Ticket #325: optional-params.patch
File optional-params.patch, 19.2 KB (added by hopscc, 11 years ago) |
---|
-
Source/Expr.cobra
281 281 """ 282 282 return ' whose type is "[.receiverType.name]"' 283 283 284 def _paramsCountMsg(defnName as String, params as IList<of Param>, args as IList<of Expr>) as String284 def _paramsCountMsg(defnName as String, params as IList<of Param>, nOptParams as int, args as IList<of Expr>) as String 285 285 item = if(defnName == r'[]', 'indexer', 'method') 286 286 countStr = if(args.count == 0, 'no arguments', '[args.count]') 287 287 countStr += if(args.count == 1, ' is', ' are') 288 288 detail = _paramsVsArgsString(defnName, params, args) 289 msg = 'The [item] "[defnName]" is expecting [params.count] argument[Utils.plural(params)], but [countStr] being supplied in this call. [detail]' 289 optPart = if(nOptParams, ' ([nOptParams] optional)','') 290 expectingPart = 'is expecting [params.count] argument[Utils.plural(params)][optPart]' 291 suppliedPart = 'but [countStr] being supplied in this call' 292 msg = 'The [item] "[defnName]" [expectingPart], [suppliedPart]. [detail]' 290 293 return msg 291 294 292 295 def _paramsVsArgsString(defnName as String, params as IList<of Param>, args as IList<of Expr>) as String … … 301 304 sb = StringBuilder('The [item]declaration is "[defnName](') 302 305 sep = '' 303 306 for param in params 304 sb.append('[sep][param.name] as [param.type.name]') 307 optInit = if(param.optValue, ' = [param.optValue.toCobraSource]', '') 308 sb.append('[sep][param.name] as [param.type.name][optInit]') 305 309 sep = ', ' 306 310 sb.append(')"') 307 311 # to-do: append definition return Type (if any)? … … 910 914 if _name=='toString' # to-do: hack: because many structs like Decimal have a toString() overload which cannot currently be expressed in SystemInterfaces.cobra 911 915 return false 912 916 else 913 .throwError(_paramsCountMsg(definition.name, params, args)) #'The method "[definition.name]" is expecting [params.count] argument[Utils.plural(params)], but [countStr] being supplied in this call.' 917 haveErr = args.count > params.count 918 if not haveErr 919 nOptionalParams =0 920 for p in params, if p.optValue, nOptionalParams += 1 921 #print '[params.count] Params [nOptParams] Optional' 922 haveErr = args.count < params.count - nOptionalParams 923 if haveErr 924 .throwError(_paramsCountMsg(definition.name, params, nOptionalParams, args)) #'The method "[definition.name]" is expecting [params.count] argument[Utils.plural(params)], but [countStr] being supplied in this call.' 914 925 return true 915 926 916 927 def _inferOutArgs(args as IList<of Expr>, params as IList<of Param>, warn as bool) … … 1579 1590 return 1580 1591 1581 1592 if not hasVari and args.count <> params.count 1582 .throwError(_paramsCountMsg(r'[]', params, args)) # 'The indexer is expecting [params.count] argument[Utils.plural(params)], but [countStr] being supplied in this call.[msg]'1593 .throwError(_paramsCountMsg(r'[]', params, 0, args)) # 'The indexer is expecting [params.count] argument[Utils.plural(params)], but [countStr] being supplied in this call.[msg]' 1583 1594 for i in 0 : args.count 1584 1595 arg = args[i] 1585 1596 param = params[i] … … 1796 1807 .throwError('Could not find an overload for "[.name]" with zero arguments.') 1797 1808 else if defn inherits AbstractMethod 1798 1809 params = defn.params 1799 if params.count <> 0 and not (params.count == 1 and params[0].type inherits VariType) 1800 .throwError(_paramsCountMsg(defn.name, params, List<of Expr>())) # 'The method "[defn.name]" is expecting [params.count] argument[Utils.plural(params)], but no arguments are being supplied in this call.' 1810 nOptionalParams =0 1811 if params.count <> 0 and not _allParamsOptional(params, out nOptionalParams) 1812 .throwError(_paramsCountMsg(defn.name, params, nOptionalParams, List<of Expr>())) # 'The method "[defn.name]" is expecting [params.count] argument[Utils.plural(params)], but no arguments are being supplied in this call.' 1801 1813 else if .name <> 'getType' # ug, more special handling for getType 1802 1814 box = .binarySuperNode.left.type to? Box 1803 1815 if box … … 1814 1826 _type = mbr.resultType 1815 1827 break 1816 1828 1829 def _allParamsOptional(params as IList<of Param>, nOptParams as out int) as bool 1830 """VariArg single param or all params in paramList optional.""" 1831 nOptParams=0 1832 if params.count == 1 and params[0].type inherits VariType 1833 return true 1834 for p in params, if p.optValue, nOptParams += 1 1835 return nOptParams == params.count 1836 #return false 1837 1817 1838 def toCobraSource as String is override 1818 1839 return _name 1819 1840 -
Source/BackEndClr/SharpGenerator.cobra
544 544 d = writer.curlyToCobraLineNum 545 545 546 546 # Output 547 #print 'Output: ', writer.output 547 548 (.compiler to Compiler).createSharpFile(.sharpFileName, writer.output) 548 549 549 550 return d … … 1489 1490 on Direction.InOut, sw.write('ref ') 1490 1491 on Direction.Out, sw.write('out ') 1491 1492 sw.write('[.type.sharpParamRef] [.sharpName]') 1492 1493 if .optValue # Net4 optional param 1494 sw.write('=') 1495 _optValue.writeSharpDef(sw) 1496 1493 1497 def writeSharpDefSansReferenceLabels(sw as CurlyWriter) 1494 1498 """ 1495 1499 Writes the parameter declaration but without C# "out" or "ref"--these are not available for -
Source/CobraParser.cobra
1853 1853 foo as List<of int> 1854 1854 foo # default type (dynamic?) 1855 1855 foo as Type has Attribute(arg1, arg2) 1856 foo [as Type] = optionalValue [has Attribute] 1856 1857 foo has Attribute(arg1, arg2) 1857 1858 """ 1858 1859 if .peek.which == 'OPEN_GENERIC' … … 1900 1901 else 1901 1902 type = TypeProxy(_typeProvider.defaultType) 1902 1903 isMissingType = true 1904 1905 if .optional('ASSIGN') # default value for optional param 1906 optExpr = .expression to ? # a constant, value Type or default(Type) 1907 else 1908 optExpr = nil 1909 if type is nil 1910 type = .typeProvider.defaultType 1911 1903 1912 attribs = AttributeList() 1904 1913 if .optional('HAS') 1905 1914 # TODO: multiple attribs like: x as Type has (Attrib1, Attrib2) 1906 1915 attribs.add(AttributeDecl(.attribExpr(0))) 1907 1916 # note: isMissingType is currently used to generate a warning in .paramDecls above 1908 1917 # and may be used for anonymous method parameter type inference at some point 1909 return Param(token, type, isMissingType=isMissingType, direction=dir, isDeclaredAsUnused=declaredAsUnused, attributes=attribs) 1918 return Param(token, type, isMissingType=isMissingType, direction=dir, 1919 isDeclaredAsUnused=declaredAsUnused, optValue=optExpr, attributes=attribs) 1910 1920 1911 1921 1912 1922 ## -
Source/Vars.cobra
172 172 173 173 174 174 class Param inherits AbstractLocalVar is partial 175 175 176 var _optValue as Expr? 177 """Default value for an optional parameter.""" 178 176 179 cue init(token as IToken, type as IType) 177 180 base.init(token, type) 178 181 … … 207 210 208 211 pro direction from var as Direction 209 212 213 pro optValue from var 214 """ Value for optional param. Marks param as optional""" 215 210 216 get isInOut as bool 211 217 return .direction == Direction.InOut 212 218 … … 239 245 240 246 def _bindInt 241 247 base._bindInt 248 if _optValue 249 # TODO: check optValue is constant, valueType ctor or 'default(valueType') 250 #print _optValue 251 _optValue.bindImp # that's bindImp intentionally 252 #print _optValue.type 253 if not _optValue.canBeAssignedTo(_type to !) 254 .throwError('Incompatible types. Cannot assign value of type [_optValue.type.name] on the right to [_type.name] on the left.') 242 255 for attrib in .attributes 243 256 try 244 257 attrib.bindInt … … 247 260 248 261 def _bindImp 249 262 base._bindImp 263 if .isMissingType and _optValue and _optValue.type and not _optValue inherits NilLiteral 264 #infer param type from optional param default value 265 #if NilLiteral just leave it alone 266 _type = _optValue.type 250 267 for attrib in .attributes 251 268 try 252 269 attrib.bindImp -
Source/BackEndJvm/JavaGenerator.cobra
1309 1318 base.writeJavaDef(sw) 1310 1319 # TODO 1311 1320 #if .type.isReference and not .type inherits NilableType 1312 # sw.write(r'[Cobra.Core.NotNull] ') 1321 # sw.write(r'[Cobra.Core.NotNull] ') # TODO: annotations on params avail in Java8 1313 1322 branch .direction 1314 1323 on Direction.In, pass 1315 1324 on Direction.InOut, sw.write('/*inOut*/') # default 1316 1325 on Direction.Out, sw.write('/*out*/') # TODO 1317 1326 sw.write('[.type.javaParamRef] [.javaName]') 1327 if .optValue # Net4 optional param 1328 detail='For java at the moment you will need to recode the optional parameter method as a set of overloaded (possibly cascaded) methods with the desired number of parameters.' 1329 .compiler.warning(this, 'Java does not support optional parameters. Default parameter value setting is ignored. [detail]') 1330 #sw.write('=') 1331 #_optValue.writeSharpDef(sw) 1318 1332 1319 1333 def writeJavaDefSansReferenceLabels(sw as CurlyWriter) 1320 1334 """ 1321 1335 Writes the parameter declaration but without Java "out" or "ref"--these are not available for 1322 1336 contract methods (require_foo and ensure_foo) because contracts cannot modify arguments. 1323 1337 """ 1324 # skip the [NotNull] as well since it's not really needed1325 1338 sw.write('[.type.javaRef] [.javaName]') 1326 1339 1327 1340 -
Tests/160-methods/630-opt-param-string.cobra
1 # String default 2 class OptParam 3 def main is shared 4 x = OptParam() 5 x.val = 'none' 6 x.foo('default') 7 assert x.val == 'defaultVal' 8 x.foo('provided', 'xyzzy') 9 assert x.val == 'xyzzy' 10 11 var val = '' 12 13 def foo(f as String, s = 'defaultVal') 14 if f == 'default' 15 assert s == 'defaultVal' 16 .val = s -
Tests/160-methods/600-opt-param-inferred-type.cobra
1 # single optional param 2 class OptParam 3 def main is shared 4 x = OptParam() 5 x.call = 0 6 x.foo('default') 7 assert x.call ==1 8 x.foo('provided',10) 9 assert x.call == 10 10 11 var call =0 12 13 def foo(s as String, i = nil) # optional single (dynamic) param 14 #print s,i 15 if s == 'default' 16 assert i == nil 17 i = 1 18 .call = i -
Tests/160-methods/620-opt-param-bool.cobra
1 # boolean default 2 class OptParam 3 def main is shared 4 x = OptParam() 5 x.val = true 6 x.foo('default') 7 assert x.val == false 8 x.foo('provided', true) 9 assert x.val 10 11 var val = false 12 13 def foo(s as String, b = false) 14 if s == 'default' 15 assert b == false 16 .val = b -
Tests/160-methods/610-opt-param-inferred-type.cobra
1 # single optional param 2 class OptParam 3 def main is shared 4 x = OptParam() 5 x.call = 0 6 x.foo('default') 7 assert x.call ==1 8 x.foo('provided',10) 9 assert x.call == 10 10 11 var call = 0 12 13 def foo(s as String, i = 1) # optional single param 14 #print s,i 15 if s == 'default' 16 assert i ==1 17 .call = i -
Tests/160-methods/640-opt-param-list.cobra
1 # single optional param 2 class OptParam 3 4 def main is shared 5 x = OptParam() 6 x.call = [0] 7 x.foo('default') 8 assert x.call == nil 9 x.foo('provided',[1,4,9]) 10 assert x.call == [1,4,9] 11 12 var call as List<of int>? =[0] 13 def foo(s as String, l as List<of int>? = nil) 14 #print s,i 15 .call = l -
Tests/160-methods/641-opt-param-list.cobra
1 # single optional param 2 class OptParam 3 4 def main is shared 5 x = OptParam() 6 x.call = [0] 7 x.foo('default') 8 assert x.call == nil 9 x.foo('provided',[1,4,9]) 10 assert x.call == [1,4,9] 11 12 var call as List<of int>? =[0] 13 def foo(s as String, l as List<of int>? = nil) 14 #print s,i 15 .call = l -
Tests/160-methods/400-optional-ctor-arg.cobra
1 class OptCtor 2 def main is shared 3 x = OptCtor() 4 assert x.x == 'default' 5 6 x1 = OptCtor('foo') 7 assert x1.x == 'foo' 8 9 var x = '' 10 11 cue init(s as String = 'default') 12 base.init 13 .x = s 14 print 'OptCtor [.x]' 15 -
Tests/160-methods/800-no-args-error.cobra
1 # count of optparams in error message 2 class OptionalExample 3 def main is shared 4 eg = EClass() 5 eg.twoOpt() #.error. expecting 3 arguments (2 optional) 6 7 class EClass 8 var name as String 9 10 cue init(name as String) 11 base.init 12 .name = name 13 14 def twoOpt(required as int, optionalstr as String = "default", optionalint as int = 10) 15 pass -
Tests/160-methods/100-optional-params.cobra
1 # fixed and single optional param 2 class OptParam 3 def main is shared 4 x = OptParam() 5 x.call = 0 6 x.foo('default') 7 assert x.call ==1 8 x.foo('provided',10) 9 assert x.call == 10 10 11 var call = 0 12 13 def foo(s as String, i as int = 1) # optional single param 14 #print s,i 15 if s == 'default' 16 assert i ==1 17 .call = i -
Tests/160-methods/641-opt-param-list.cobra#
1 # Cannot pass non compile const as default values 2 class OptParam 3 4 def main is shared 5 x = OptParam() 6 x.call = [0] 7 x.foo('default') 8 assert x.call == [1,2,3] 9 x.foo('provided',[1,4,9,16 ]) 10 assert x.call == [1,4,9,16] 11 12 var call = List<of int>() 13 14 def foo(s as String, l as List<of int>? = nil) 15 #print s,i 16 if not l 17 l = [1,2,3] 18 .call = l -
Tests/160-methods/200-optional-params.cobra
1 class OptParam 2 def main is shared 3 x = OptParam() 4 x.call = 0 5 x.foo 6 assert x.call ==1 7 x.foo(10) 8 assert x.call == 10 9 10 var call = 0 11 12 def foo(i as int = 1) # optional single param 13 print i 14 .call = i -
Tests/160-methods/300-optional-params.cobra
1 class OptParam 2 def main is shared 3 x = OptParam() 4 assert x.val ==0 and x.isOn == false 5 x.isOn = true 6 x.foo('this') 7 assert x.val ==1 and x.isOn == false 8 x.isOn = true 9 x.foo('is', 10) 10 assert x.val == 10 and x.isOn == false 11 x.foo('sparta', 20, true) 12 assert x.val == 20 and x.isOn == true 13 14 var val = 0 15 var isOn = false 16 17 def foo(s as String, i as int = 1, isOn as bool = false) 18 .val = i 19 .isOn = isOn -
Tests/160-methods/700-optional.cobra
1 class OptionalExample 2 def main is shared 3 # Instance eg does not send an argument for the constructor's 4 # optional parameter. 5 eg = ExampleClass() 6 assert eg.name =='Default name' 7 eg.exampleMethod(1, "One", 1) 8 assert eg.required ==1 and eg.optionalStr == 'One' and eg.optionalInt ==1 9 eg.exampleMethod(2, "Two") 10 assert eg.required ==2 and eg.optionalStr == 'Two' and eg.optionalInt ==10 11 eg.exampleMethod(3) 12 assert eg.required ==3 and eg.optionalStr == 'default' and eg.optionalInt ==10 13 14 # Instance eg2 sends an argument for the constructor's optional parameter. 15 eg2 = ExampleClass("Provided name") 16 assert eg2.name =='Provided name' 17 eg2.exampleMethod(1, "One", 1) 18 assert eg2.required ==1 and eg2.optionalStr == 'One' and eg2.optionalInt ==1 19 eg2.exampleMethod(2, "Two") 20 assert eg2.required ==2 and eg2.optionalStr == 'Two' and eg2.optionalInt ==10 21 eg2.exampleMethod(3) 22 assert eg2.required ==3 and eg2.optionalStr == 'default' and eg2.optionalInt ==10 23 24 # The following statements produce compiler errors. 25 # An argument must be supplied for the first parameter, and it 26 # must be an integer. 27 #eg.exampleMethod("One", 1) 28 #eg.exampleMethod() 29 30 # You cannot leave a gap in the provided arguments. 31 #eg.exampleMethod(3, ,4) 32 #eg.exampleMethod(3, 4) 33 34 # You can use a named parameter to make the previous 35 # statement work. 36 #eg.exampleMethod(3, optionalint: 4) 37 38 class ExampleClass 39 var name as String 40 41 var required =0 42 var optionalStr = '' 43 var optionalInt =0 44 45 cue init(name as String = "Default name") 46 base.init 47 .name = name 48 49 # The first parameter, required, has no default value assigned 50 # to it. Therefore, it is not optional. Both optionalstr and 51 # optionalint have default values assigned to them. They are optional. 52 def exampleMethod(required as int, optionalstr as String = "default", optionalint as int = 10) 53 #print String.format("{0}: {1}, {2}, and {3}.", .name, required, optionalstr, optionalint) 54 .required = required 55 .optionalStr = optionalstr 56 .optionalInt = optionalint