Ticket #226: big-or-complex.patch
File big-or-complex.patch, 37.9 KB (added by hopscc, 14 years ago) |
---|
-
Source/Members.cobra
1483 1483 else 1484 1484 members = .members 1485 1485 1486 for member in members 1487 score = -1000 1488 if member.params.count == args.count 1489 score = 0 1490 if member inherits Method and (member to Method).genericParams.count > 0, score += 1 1491 for i, param in member.params.numbered 1492 arg = args[i] 1493 if strictBindChecking and not arg.didBindImp 1494 trace arg 1495 trace arg.hasError 1496 if strictBindChecking and (arg.type == param.type or arg.type == param.type.nonNil) 1497 score += 20 1498 else if strictBindChecking and arg.canBeAssignedTo(param.type) 1499 score += 10 1500 else if strictBindChecking and arg.type.nonNil.isAssignableTo(param.type) 1501 # Cobra's code and data flow analysis sometimes leaves us with a nilable type that's not actually nil anymore 1502 # due to an assignment, possibly wrapped in an if statement. Eventually this will be corrected, but for now 1503 # compensate here. 1504 score += 1 1505 else if not strictBindChecking 1506 if arg.type is not nil 1507 if arg.type == param.type 1508 score += 20 1509 else if arg.type.isDynamic 1510 score += 10 1511 else 1512 score -= 100 1513 else 1514 score -= 100 1515 # print 'candidate:', score, member.name, member.serialNum, Utils.join(', ', (for param in member.params get param.type.name)) 1516 candidates.add([score, member]) 1486 _calcMembersScore(members, args, strictBindChecking, candidates) 1517 1487 1518 1488 maxScore = -10_000 1519 1489 winner = nil to BoxMember? … … 1559 1529 assert winner 1560 1530 return winner to ! 1561 1531 1532 def _calcMembersScore(members as List<of BoxMember>, args as List<of Expr>, strictBindChecking as bool, candidates) 1533 for member in members 1534 score = -1000 1535 if member.params.count == args.count 1536 score = 0 1537 if member inherits Method and (member to Method).genericParams.count > 0, score += 1 1538 for i, param in member.params.numbered 1539 arg = args[i] 1540 if strictBindChecking and not arg.didBindImp 1541 trace arg 1542 trace arg.hasError 1543 if strictBindChecking and (arg.type == param.type or arg.type == param.type.nonNil) 1544 score += 20 1545 else if strictBindChecking and arg.canBeAssignedTo(param.type) 1546 score += 10 1547 else if strictBindChecking and arg.type.nonNil.isAssignableTo(param.type) 1548 # Cobra's code and data flow analysis sometimes leaves us with a nilable type that's not actually nil anymore 1549 # due to an assignment, possibly wrapped in an if statement. Eventually this will be corrected, but for now 1550 # compensate here. 1551 score += 1 1552 else if not strictBindChecking 1553 if arg.type is not nil 1554 if arg.type == param.type 1555 score += 20 1556 else if arg.type.isDynamic 1557 score += 10 1558 else 1559 score -= 100 1560 else 1561 score -= 100 1562 # print 'candidate:', score, member.name, member.serialNum, Utils.join(', ', (for param in member.params get param.type.name)) 1563 candidates.add([score, member]) 1564 1562 1565 def _bindInt is override 1563 1566 base._bindInt 1564 1567 # sanity check that members all have the right name -
Source/TypeProxies.cobra
168 168 169 169 # Must return the Cobra primitive types in place of System.Boolean, System.Char, System.Int16, etc. 170 170 # because it's the primitives that are used all over the compiler. 171 172 171 clrPrimitiveToIType = .compiler.clrPrimitiveToITypeCache 173 172 if clrPrimitiveToIType is nil or clrPrimitiveToIType.count == 0 174 clrPrimitiveToIType = Dictionary<of System.Type, IType>() 175 for bt in .compiler.basicTypes 176 if bt.systemAliasProxy 177 key = (.compiler.nativeType((bt.systemAliasProxy to LibraryTypeProxy).qualifiedName) to ClrNativeType).clrType # TODO: cleanup 178 clrPrimitiveToIType[key] = bt 179 assert clrPrimitiveToIType.count == 0 or clrPrimitiveToIType.count > 9 173 clrPrimitiveToIType = _makePrimitiveTypesDict 180 174 basicType as IType? 181 175 if clrPrimitiveToIType.tryGetValue(clrType, out basicType) 182 176 return basicType to ! … … 211 205 if clrType.isGenericParameter 212 206 return GenericParam(ClrNativeType(clrType)) 213 207 214 # compute type name 215 typeName = clrType.name 216 if '`' in typeName 217 # generic like IComparable`1 218 assert r'[' not in typeName 219 typeName = .cobraNameForSharpBoxName(typeName) 220 else if typeName[typeName.length-1].isLetterOrDigit 221 pass 222 else 223 .throwError('Cannot locate CLR type "[clrType]".') 224 225 # compute namespace 208 typeName = _computeTypeName(clrType) 226 209 missing = false 227 nameParts = clrType.namespace.split(c'.') 228 member = .compiler.globalNS.symbolForName(nameParts[0]) 229 if member inherits NameSpace, curNS = member 230 else, missing = true 231 if not missing 232 i = 1 233 while i < nameParts.length 234 namePart = nameParts[i] 235 possible = curNS.declForName(namePart) 236 if possible is nil 237 missing = true 238 break 239 else if possible inherits NameSpace 240 curNS = possible 241 else 242 .throwError('Found "[namePart]" at component [i+1] of CLR type "[clrType.fullName]", but it is a [possible.englishName].') 243 i += 1 244 210 curNS = _computeNameSpace(clrType, level, out missing) 245 211 if missing 246 212 # since the CLR type exists, but cannot be located in our namespaces, 247 213 # it must be pulled from a dependent DLL that was not directly referenced 248 249 214 # but maybe it was already attempted 250 215 if level > 0 251 216 .throwError('Cannot read CLR type "[clrType.fullName]" or its assembly "[clrType.assembly]". Please report to the Cobra discussion forums (http://cobra-language.com/).') 252 217 253 218 (.compiler to dynamic).readAssembly(clrType.assembly) 254 return _realTypeWithoutCache(clrType, level+1) 219 return _realTypeWithoutCache(clrType, level+1) # recurse. guard is just above. 255 220 256 221 # return namespace member 257 member = curNS.declForName(typeName)222 member as IMember? = curNS.declForName(typeName) 258 223 if member inherits IType 259 224 if member inherits Box 260 225 if clrType.isGenericType and not clrType.isGenericTypeDefinition 261 226 # So we have something like ICollection<of KeyValuePair<of TKey,TValue>> which is all CLR types. 262 227 # We need the Cobra types of those args so we can construct the Cobra type from the generic cobra type 263 228 # otherwise, we would just end up returning the generic definition. 264 args = List<of IType>() 265 for genArg in clrType.getGenericArguments 266 args.add(_realTypeWithCache(genArg)) 267 if member.qualifiedName == 'System.Nullable<of>' 268 assert args.count == 1 269 member = .typeProvider.nilableType(args[0]) 270 else 271 member = (member to Box).constructedTypeFor(args) 229 member = _typeForArgsOfGeneric(clrType, member) 272 230 return member 273 231 else 274 232 msg = 'Cannot locate CLR type "[clrType]".' … … 284 242 .throwError(msg) 285 243 return .compiler.intType # CC: to make C# code gen happy. 286 244 245 def _makePrimitiveTypesDict as Dictionary<of System.Type, IType> 246 clrPrimitiveToIType = Dictionary<of System.Type, IType>() 247 for bt in .compiler.basicTypes 248 if bt.systemAliasProxy 249 key = (.compiler.nativeType((bt.systemAliasProxy to LibraryTypeProxy).qualifiedName) to ClrNativeType).clrType # TODO: cleanup 250 clrPrimitiveToIType[key] = bt 251 assert clrPrimitiveToIType.count == 0 or clrPrimitiveToIType.count > 9 252 return clrPrimitiveToIType 253 254 def _computeTypeName(clrType as Type) as String 255 typeName = clrType.name 256 if '`' in typeName 257 # generic like IComparable`1 258 assert r'[' not in typeName 259 typeName = .cobraNameForSharpBoxName(typeName) 260 else if typeName[typeName.length-1].isLetterOrDigit 261 pass 262 else 263 .throwError('Cannot locate CLR type "[clrType]".') 264 return typeName 265 266 def _computeNameSpace(clrType as Type, level as int, missing as out bool) as NameSpace 267 missing = false 268 nameParts = clrType.namespace.split(c'.') 269 member = .compiler.globalNS.symbolForName(nameParts[0]) 270 if member inherits NameSpace, curNS = member 271 else, missing = true 272 if not missing 273 i = 1 274 while i < nameParts.length 275 namePart = nameParts[i] 276 possible = curNS.declForName(namePart) 277 if possible is nil 278 missing = true 279 break 280 else if possible inherits NameSpace 281 curNS = possible 282 else 283 .throwError('Found "[namePart]" at component [i+1] of CLR type "[clrType.fullName]", but it is a [possible.englishName].') 284 i += 1 285 return curNS 286 287 def _typeForArgsOfGeneric(clrType as Type, member as IType) as IType 288 args = List<of IType>() 289 for genArg in clrType.getGenericArguments 290 args.add(_realTypeWithCache(genArg)) 291 boxMember = member to Box 292 if boxMember.qualifiedName == 'System.Nullable<of>' 293 assert args.count == 1 294 member = .typeProvider.nilableType(args[0]) 295 else 296 member = boxMember.constructedTypeFor(args) 297 return member 298 287 299 def _hack(clrType as Type) as IType 288 300 if clrType.isInterface 289 301 return ClrTypeProxy(sharp'typeof(System.ICloneable)').realType -
Source/BackEndClr/SharpGenerator.cobra
135 135 .modules.count 136 136 body 137 137 v, options = .verbosity, .options 138 139 138 optChar = if(.platform==PlatformEnum.Microsoft, '/', '-') # option prefix character 140 139 141 140 # exe names … … 184 183 # CS1718: A comparison made to same variable. 185 184 186 185 if .mainMethodTypeName <> '', backEndOptions.add('[optChar]main:[.mainMethodTypeName]') 187 188 186 backEndOptions.addRange(extraCscOptions) 189 187 190 188 sharpArgs = .options.getDefault('native-compiler-args', List<of String>()) to List<of String> … … 204 202 backEndOptions.add('-lib:[libPath]') 205 203 206 204 # Passing -pkg: to the C# compiler seems unnecessary. 207 # Compiler.refsForPackage already gets the .dll refs and 208 # including this was reported as a problem at 209 # http://cobra-language.com/forums/viewtopic.php?f=4&t=263 210 # 2008-12 / 2009-01 205 # Compiler.refsForPackage already gets the .dll refs and including this was reported at 206 # http://cobra-language.com/forums/viewtopic.php?f=4&t=263 2008-12 / 2009-01 211 207 # for pkgName in .options.getStringList('pkg') 212 208 # backEndOptions.add('-pkg:[pkgName]') 213 209 -
Source/Statements.cobra
686 686 left = cond.left 687 687 if left inherits IdentifierExpr 688 688 leftVar = left.namedDefinition 689 if leftVar inherits IVar # if-inherits smarts only work on variables 690 # if x inherits Y ... 691 if (right = cond.right) inherits IPotentialTypeExpr 692 assert right.potentialType 693 leftVar.ifInheritsStack.push(right.potentialType to !) 694 else 695 throw FallThroughException(right) 696 ifInherits = true 697 _trueStmts.setIfInherits(leftVar, leftVar.ifInheritsStack.peek) 689 ifInherits = _ivarIfInherits(cond, leftVar) 690 #if leftVar inherits IVar # if-inherits smarts only work on variables 691 # # if x inherits Y ... 692 # if (right = cond.right) inherits IPotentialTypeExpr 693 # assert right.potentialType 694 # leftVar.ifInheritsStack.push(right.potentialType to !) 695 # else 696 # throw FallThroughException(right) 697 # ifInherits = true 698 # _trueStmts.setIfInherits(leftVar, leftVar.ifInheritsStack.peek) 698 699 else if left inherits AssignExpr 699 700 if left.left inherits IdentifierExpr 700 701 leftVar = left.left.definition 701 if leftVar inherits IVar 702 # if (x = expr) inherits Y ... 703 if (right = cond.right) inherits IPotentialTypeExpr 704 leftVar.ifInheritsStack.push(right.potentialType to !) 705 else 706 throw FallThroughException(right) 707 ifInherits = true 708 _trueStmts.setIfInherits(leftVar, leftVar.ifInheritsStack.peek) 702 ifInherits = _ivarIfInherits(cond, leftVar) 703 #if leftVar inherits IVar 704 # # if (x = expr) inherits Y ... 705 # if (right = cond.right) inherits IPotentialTypeExpr 706 # leftVar.ifInheritsStack.push(right.potentialType to !) 707 # else 708 # throw FallThroughException(right) 709 # ifInherits = true 710 # _trueStmts.setIfInherits(leftVar, leftVar.ifInheritsStack.peek) 709 711 if not ifInherits 710 712 # check for an if-not-nil 711 713 if cond inherits TruthExpr … … 755 757 _falseStmts.parent = this 756 758 _falseStmts.bindImp 757 759 760 def _ivarIfInherits(cond as InheritsExpr, leftVar as INamedNode?) as bool 761 ifInherits = false 762 if leftVar inherits IVar # if-inherits smarts only work on variables 763 # if x inherits Y ... 764 if (right = cond.right) inherits IPotentialTypeExpr 765 assert right.potentialType 766 leftVar.ifInheritsStack.push(right.potentialType to !) 767 else 768 throw FallThroughException(right) 769 ifInherits = true 770 _trueStmts.setIfInherits(leftVar, leftVar.ifInheritsStack.peek) 771 return ifInherits 772 758 773 def doNotPopIfInheritsStack 759 774 _doNotPopIfInheritsStack = true 760 775 -
Source/Compiler.cobra
812 812 if .referenceVerbosity, print '[fle] in _loadReference("[reference]")' 813 813 return false 814 814 815 sig RVPrintStringSig( s as String) 816 815 817 def __loadReference(reference as String) as bool 816 818 require 817 819 reference.endsWith('.dll') or reference.endsWith('.exe') … … 821 823 not result implies .loadedReferences.count == old .loadedReferences.count 822 824 body 823 825 rv = .referenceVerbosity 826 rvPrint as RVPrintStringSig = ref _rvNull 827 if rv, rvPrint = ref _rvPrint 824 828 assert not (reference.startsWith('-r') and '-r' in reference[2:]) 825 829 if false 826 830 # Does not work on Novell Mono. See notes above. … … 829 833 else 830 834 if File.exists(reference) 831 835 # try current directory 832 if rv, '"[reference]" found as file. Will Assembly.loadFrom().'836 rvPrint('"[reference]" found as file. Will Assembly.loadFrom().') 833 837 referredAss = Assembly.loadFrom(reference) 834 if rv, 'Assembly.loadFrom() returned: [CobraCore.toTechString(referredAss)]'838 rvPrint('Assembly.loadFrom() returned: [CobraCore.toTechString(referredAss)]') 835 839 else 836 840 # TODO: the problem with -lib: in both Cobra and C# is that it has no effect on runtime, 837 841 # you must still register the DLLs in the GAC or copy them into the same dir as the .exe 838 842 # because the -lib: paths are not passed into executable. 839 843 # So should Cobra copy the .dll's into the target directory (if their paths are not in MONO_PATH)? 840 if rv, print 'File does not exist.'844 rvPrint('File does not exist.') 841 845 searchPaths = .options.getDefault('library-directory', List<of String>()) to List<of String> 842 846 # TODO: ?: searchPaths.add(Path.getDirectoryName(Assembly.getExecutingAssembly.location)) # try Cobra's directory - also should be added to .options.'library-directory' not to a local var 843 847 found = false 844 848 for searchPath in searchPaths 845 if rv, 'Checking lib path: "[searchPath]"'849 rvPrint('Checking lib path: "[searchPath]"') 846 850 combinedPath = Path.combine(searchPath, reference) 847 851 if File.exists(combinedPath) 848 if rv, '"[reference]" found as file. Will Assembly.loadFrom().'852 rvPrint('"[reference]" found as file. Will Assembly.loadFrom().') 849 853 referredAss = Assembly.loadFrom(combinedPath) 850 if rv, 'Assembly.loadFrom() returned: [CobraCore.toTechString(referredAss)]'854 rvPrint('Assembly.loadFrom() returned: [CobraCore.toTechString(referredAss)]') 851 855 found = true 852 856 break 853 857 if rv … … 858 862 if not found 859 863 # try system wide (GAC) 860 864 if reference.endsWith('.dll'), reference = reference[:-4] 861 if rv, print 'Will load with partial name "[reference]"'865 rvPrint('Will load with partial name "[reference]"') 862 866 referredAss = Utils.loadWithPartialName(reference) 863 if rv, print 'Load with partial name returned: [CobraCore.toTechString(referredAss)]'867 rvPrint( 'Load with partial name returned: [CobraCore.toTechString(referredAss)]') 864 868 if referredAss is nil, return false 865 869 # 2009-08-03 CE: Removed this code: 866 870 # reference = referredAss.location … … 885 889 print '<< Loading dependency: [dependency]' 886 890 else 887 891 .loadAssembly(dependency) 888 if rv, 'Will read assembly: [referredAss]'892 rvPrint('Will read assembly: [referredAss]') 889 893 try 890 894 .readAssembly(referredAss, reference <> 'Cobra.Lang.dll') 891 895 catch readExc as Exception 892 if rv, print 'Caught exception during read assembly: [readExc]'896 rvPrint('Caught exception during read assembly: [readExc]') 893 897 throw 894 if rv, 'Did read assembly: [referredAss]'898 rvPrint('Did read assembly: [referredAss]') 895 899 # reassert the preconditions. there have been bugs in the past 896 900 assert reference.endsWith('.dll') or reference.endsWith('.exe') 897 901 assert reference not in ['.dll', '.exe'] 898 902 .loadedReferences.add(reference) 899 if rv, 'Returning true for __loadReference("[reference]").'903 rvPrint('Returning true for __loadReference("[reference]").') 900 904 return true 901 905 else 902 if rv, 'Returning false for __loadReference("[reference]").'906 rvPrint('Returning false for __loadReference("[reference]").') 903 907 return false 904 908 909 def _rvPrint(s as String) 910 print s 911 912 def _rvNull(s as String) 913 pass 914 905 915 var _didLoadAssemblies = Set<of String>() 906 916 907 917 def loadAssembly(assName as AssemblyName) -
Source/BinaryOpExpr.cobra
320 320 _type = .compiler.numberType 321 321 else 322 322 _type = tgcd 323 else if rightType.isDescendantOf(tdecimal) 324 _type = tdecimal 325 else if rightType.isDescendantOf(tfloat) 326 _type = tgcd 323 else 324 cannotMix = _ifRightTypeThen(tdecimal, tdecimal, tfloat, tgcd) 325 #else if rightType.isDescendantOf(tdecimal) 326 # _type = tdecimal 327 #else if rightType.isDescendantOf(tfloat) 328 # _type = tgcd 327 329 else if leftType.isDescendantOf(tdecimal) 328 if rightType.isDescendantOf(tdecimal) 329 _type = tdecimal 330 else if rightType.isDescendantOf(tint) 331 _type = tdecimal 332 else if rightType.isDescendantOf(tfloat) 333 cannotMix = true 334 else 335 cannotMix = true 330 cannotMix = _ifRightTypeThen(tdecimal, tdecimal, tint, tdecimal) 331 #if rightType.isDescendantOf(tdecimal) 332 # _type = tdecimal 333 #else if rightType.isDescendantOf(tint) 334 # _type = tdecimal 335 #else if rightType.isDescendantOf(tfloat) 336 # cannotMix = true 337 #else 338 # cannotMix = true 336 339 else if leftType.isDescendantOf(tfloat) 337 if rightType.isDescendantOf(tfloat) 338 _type = tgcd 339 else if rightType.isDescendantOf(tint) 340 _type = tgcd 341 else if rightType.isDescendantOf(tdecimal) 342 cannotMix = true 343 else 344 cannotMix = true 340 cannotMix = _ifRightTypeThen(tfloat, tgcd, tint, tgcd) 341 #if rightType.isDescendantOf(tfloat) 342 # _type = tgcd 343 #else if rightType.isDescendantOf(tint) 344 # _type = tgcd 345 #else if rightType.isDescendantOf(tdecimal) 346 # cannotMix = true 347 #else 348 # cannotMix = true 345 349 else if leftType.isDescendantOf(tstring) 346 if rightType.isDescendantOf(tstring) 347 _type = tstring 348 else 349 cannotMix = true 350 cannotMix = _ifRightTypeThen(tstring, tstring) 351 #if rightType.isDescendantOf(tstring) 352 # _type = tstring 353 #else 354 # cannotMix = true 350 355 else if leftType inherits Box 351 356 if leftType.isGeneric and leftType.isDescendantOf(.compiler.collectionOfType.constructedTypeFor([leftType.genericParams[0]])) 352 357 if leftType.genericParams.count > 1 … … 385 390 .throwError('Cannot apply [_op] to [leftType.name]. [sugg]') 386 391 else 387 392 .throwError('Cannot apply [_op] to [leftType.name] and [rightType.name]. [sugg]') 393 394 def _ifRightTypeThen(ifThenPairs as vari IType) as bool 395 rightType = _right.type.nonNil 396 n =0 397 while n < ifThenPairs.length 398 matchType = ifThenPairs[n] 399 resultType = ifThenPairs[n+1] 400 n += 2 401 if rightType.isDescendantOf(matchType) 402 _type = resultType 403 return false 404 return true 405 388 406 389 407 390 408 class AugAssignMathExpr inherits NumericPromoExpr is partial -
Source/CobraParser.cobra
584 584 .genericConstraints(token, genericParams) 585 585 on 'INHERITS' 586 586 if .optional('INHERITS') 587 expectComma = false 588 while true 589 if expectComma 590 if .peek.isKeyword, break 591 .expect('COMMA') 592 inheritsProxies.add(.typeId) 593 expectComma = true 594 if .peek.which == 'EOL' 595 .grab 596 break 597 else if .peek.isKeyword 598 break 587 _commaSepTypes(inheritsProxies) 599 588 on 'IMPLEMENTS' 600 589 if .optional('IMPLEMENTS') 601 # TODO: use a nested def to eliminate duplication with on 'INHERITS' just above 602 expectComma = false 603 while true 604 if expectComma 605 if .peek.isKeyword, break 606 .expect('COMMA') 607 implementsProxies.add(.typeId) 608 expectComma = true 609 if .peek.which == 'EOL' 610 .grab 611 break 612 else if .peek.isKeyword 613 break 590 _commaSepTypes(implementsProxies) 614 591 on 'ADDS' 615 592 if .optional('ADDS') 616 expectComma = false 617 while true 618 if expectComma 619 if .peek.isKeyword, break 620 .expect('COMMA') 621 addsProxies.add(.typeId) 622 expectComma = true 623 if .peek.which == 'EOL' 624 .grab 625 break 626 else if .peek.isKeyword 627 break 593 _commaSepTypes(addsProxies) 628 594 else 629 595 isDone = true 630 596 if last.isOneOf('EOL.INDENT.'), continue … … 635 601 if not didIndent, .indent 636 602 return TypeSpecs(isNames, attribs, inheritsProxies, implementsProxies, addsProxies) 637 603 604 def _commaSepTypes(proxies as List<of ITypeProxy>) 605 expectComma = false 606 while true 607 if expectComma 608 if .peek.isKeyword, break 609 .expect('COMMA') 610 proxies.add(.typeId) 611 expectComma = true 612 if .peek.which == 'EOL' 613 .grab 614 break 615 else if .peek.isKeyword 616 break 617 638 618 def endOfTypeSpecClause 639 619 """ 640 620 Ends a type clause on EOL or a keyword. … … 1343 1323 opener = .grab to ! 1344 1324 if not opener.which.isOneOf('ID.OPEN_CALL.OPEN_GENERIC.') and not opener.isKeyword 1345 1325 .throwError('Encountered [opener.which] when expecting an identifier.') 1346 if opener.which == 'OPEN_GENERIC' 1347 genericParams = .declGenericParams(opener) 1348 else 1349 genericParams = List<of GenericParam>() 1326 genericParams = _methodGenericParams(opener) 1327 1350 1328 name = opener.value to String 1351 1329 curBox = .curBox 1352 1330 if name == curBox.name or name.capitalized == curBox.name 1353 1331 .throwError('Method names cannot be the same as their enclosing [curBox.englishName]. Use `cue init` for creating an initializer/constructor or choose another name.') # TODO list the enclosing types location 1354 1332 1355 unnecessary = false 1356 if opener.which == 'OPEN_CALL' 1357 params = .paramDecls(/#skipParen=#/true) 1358 if params.count == 0, unnecessary = true 1359 else if opener.which == 'OPEN_GENERIC' 1360 if .optional('LPAREN') 1361 params = .paramDecls(/#skipParen=#/true) 1362 if params.count == 0, unnecessary = true 1363 else 1364 params = List<of Param>() 1365 else if opener.which == 'ID' and .optional('LPAREN') 1366 # def id (... - misplaced space after name 1367 .throwError('Misplaced space between method name and opening brace "("') 1368 else 1369 params = List<of Param>() 1370 if unnecessary 1371 _warning(opener, 'Unnecessary parentheses. You can remove them.') 1333 params = _methodParams(opener) 1334 returnType = _methodReturnType 1372 1335 1373 if .optional('AS')1374 returnType = .typeId to ITypeProxy?1375 else1376 returnType = _typeProvider.voidType1377 assert returnType1378 1379 1336 isNames = List<of String>(_isNamesStack) 1380 1337 attribs = AttributeList() 1381 1338 implementsType = nil to ITypeProxy? 1382 1383 1339 method as AbstractMethod? 1384 1340 1385 1341 # Rules: … … 1426 1382 encountered.add(last) 1427 1383 assert .last.which.isOneOf('EOL.INDENT.') 1428 1384 1429 if _spaceAgnosticIndentLevel 1430 sail = _spaceAgnosticIndentLevel 1431 if sail > 0, _spaceAgnosticIndentLevel -= 1 # for missing indent 1432 if sail < 0, _spaceAgnosticIndentLevel += 1 # for missing dedent 1433 _finishSpaceAgnostic 1434 if sail > 0 1435 nothingMore = false # TODO: feels wrong 1436 else 1437 nothingMore = .last.which == 'INDENT' and .peek.which <> 'INDENT' # _spaceAgnosticIndentLevel == 0 1438 else 1439 nothingMore = not didIndent and .last.which == 'EOL' 1440 1385 nothingMore = _endMethodDecl(didIndent) 1441 1386 docString = .docString 1442 1387 if token.which == 'CUE' and name == 'init' 1443 if curBox inherits Interface 1444 .throwError('Cannot declare an initializer for an interface.') 1445 if returnType is not .typeProvider.voidType 1446 .throwError('Cannot declare a return type for an initializer.') 1447 if implementsType 1448 .throwError('Cannot specify `implements` for an initializer.') 1388 _verifyInitializer(returnType, implementsType) 1449 1389 method = Initializer(token, opener, .curBox, params, isNames, attribs, docString) 1450 1390 else 1451 1391 method = Method(token, opener, .curBox, name, .makeList<of IType>(genericParams), params, returnType, implementsType, isNames, attribs, docString) … … 1455 1395 else 1456 1396 .statementsFor(method) 1457 1397 1398 _verifyMethodStatements(method to !, isNames, curBox) 1399 assert method 1400 overload = _overloadIfNeeded(method.token, curBox, method.name) # also checks for various errors 1401 if overload 1402 overload.addMember(method to !) 1403 return nil 1404 return method 1405 1406 #Helper for declareMethod; get List of GenericParam or empty GenericParam List 1407 def _methodGenericParams(opener as IToken) as List<of GenericParam> 1408 if opener.which == 'OPEN_GENERIC' 1409 genericParams = .declGenericParams(opener) 1410 else 1411 genericParams = List<of GenericParam>() 1412 return genericParams 1413 1414 #Helper for declareMethod; return declared method returnType or voidType 1415 def _methodReturnType as ITypeProxy 1416 if .optional('AS') 1417 returnType = .typeId to ITypeProxy? 1418 else 1419 returnType = _typeProvider.voidType 1420 assert returnType 1421 return returnType to ! 1422 1423 #Helper for declareMethod; get List of Param or empty Param List 1424 def _methodParams(opener as IToken) as List<of Param> 1425 unnecessary = false 1426 if opener.which == 'OPEN_CALL' 1427 params = .paramDecls(/#skipParen=#/true) 1428 if params.count == 0, unnecessary = true 1429 else if opener.which == 'OPEN_GENERIC' 1430 if .optional('LPAREN') 1431 params = .paramDecls(/#skipParen=#/true) 1432 if params.count == 0, unnecessary = true 1433 else 1434 params = List<of Param>() 1435 else if opener.which == 'ID' and .optional('LPAREN') 1436 # def id (... - misplaced space after name 1437 .throwError('Misplaced space between method name and opening brace "("') 1438 else 1439 params = List<of Param>() 1440 if unnecessary 1441 _warning(opener, 'Unnecessary parentheses. You can remove them.') 1442 return params 1443 1444 #Helper for declareMethod; Error checks on statements 1445 def _verifyMethodStatements(method as AbstractMethod, isNames as List<of String>, curBox as Box) 1458 1446 if method.statements.count 1459 1447 if 'abstract' in isNames 1460 1448 .throwError('Cannot have statements for an abstract method.') … … 1464 1452 if not 'abstract' in isNames and not curBox inherits Interface 1465 1453 .throwError('Missing statements. Use "pass" or other statements.') 1466 1454 1467 assert method 1468 overload = _overloadIfNeeded(method.token, curBox, method.name) # also checks for various errors 1469 if overload 1470 overload.addMember(method to !) 1471 return nil 1455 #Helper for declareMethod; slurp up indentation and indicate if end of declaration 1456 def _endMethodDecl(didIndent as bool) as bool 1457 if _spaceAgnosticIndentLevel 1458 sail = _spaceAgnosticIndentLevel 1459 if sail > 0, _spaceAgnosticIndentLevel -= 1 # for missing indent 1460 if sail < 0, _spaceAgnosticIndentLevel += 1 # for missing dedent 1461 _finishSpaceAgnostic 1462 if sail > 0 1463 nothingMore = false # TODO: feels wrong 1464 else 1465 nothingMore = .last.which == 'INDENT' and .peek.which <> 'INDENT' # _spaceAgnosticIndentLevel == 0 1472 1466 else 1473 return method 1467 nothingMore = not didIndent and .last.which == 'EOL' 1468 return nothingMore 1469 1470 #Helper for declareMethod; Error checks on initializer 1471 def _verifyInitializer(returnType as ITypeProxy, implementsType as ITypeProxy?) 1472 if .curBox inherits Interface 1473 .throwError('Cannot declare an initializer for an interface.') 1474 if returnType is not .typeProvider.voidType 1475 .throwError('Cannot declare a return type for an initializer.') 1476 if implementsType 1477 .throwError('Cannot specify `implements` for an initializer.') 1478 1474 1479 1475 1480 def declareMethodSig as MethodSig 1476 1481 require _typeProvider … … 2049 2054 s.afterParserRecognizesStatement 2050 2055 if .optional('COMMA') 2051 2056 s = .multiTargetAssign(s to Expr) 2052 if expectEOL 2053 if .verbosity>=5 2054 print '<> last statement start token=[token]' 2055 print '<> s = [s]' 2056 try 2057 .expect('EOL') 2058 catch pe as ParserException 2059 # example: puts 5 2060 token = .last(1) 2061 if token <> nil 2062 sugg = if(token.text.length, Compiler.suggestionFor(token.text), nil) 2063 sugg = if(sugg, ' Try "[sugg]" instead of "[token.text]".', nil) 2064 if sugg, pe = pe.cloneWithMessage(pe.message + sugg) 2065 throw pe 2057 if expectEOL 2058 _handleStmtEOL(token, s) 2059 2066 2060 _finishSpaceAgnostic 2067 2061 return s 2062 2063 def _handleStmtEOL(token as IToken?, s as Stmt?) 2064 if .verbosity>=5 2065 print '<> last statement start token=[token]' 2066 print '<> s = [s]' 2067 try 2068 .expect('EOL') 2069 catch pe as ParserException 2070 # example: puts 5 2071 token = .last(1) 2072 if token <> nil 2073 sugg = if(token.text.length, Compiler.suggestionFor(token.text), nil) 2074 sugg = if(sugg, ' Try "[sugg]" instead of "[token.text]".', nil) 2075 if sugg, pe = pe.cloneWithMessage(pe.message + sugg) 2076 throw pe 2068 2077 2069 2078 2070 2079 ## … … 2790 2799 return left to ! 2791 2800 2792 2801 def expression2 as Expr 2793 if _spaceAgnosticExprLevel > 0 2794 _spaceAgnostic 2802 if _spaceAgnosticExprLevel > 0, _spaceAgnostic 2795 2803 peekToken = .peek 2796 2804 peek = peekToken.which 2797 2805 if _unaryOpPrec.containsKey(peek) … … 2804 2812 on 'OLD', return OldExpr(token, unaryExpr) 2805 2813 on 'REF', return RefExpr(token, unaryExpr) 2806 2814 else, return UnaryOpExpr(token, peek, unaryExpr) 2807 # TODO: make a branch statement 2808 else if peek=='LPAREN' 2809 .grab 2810 _spaceAgnosticExprLevel += 1 2811 node = .expression(0, nil) 2812 .expect('RPAREN') 2813 _spaceAgnosticExprLevel -= 1 2814 node.isParened = true 2815 return node 2816 else if peek=='DOT' 2817 # leading dot 2818 token = .grab 2819 .opStack.push('DOT') 2820 try 2821 peekToken = .peek 2822 peek = peekToken.which 2823 if peek=='ID' or peekToken.isKeyword 2824 memberToken = .idOrKeyword 2825 expr = MemberExpr(memberToken) to Expr 2826 else if peek=='OPEN_CALL' 2827 expr = .callExpr 2828 else if peek=='OPEN_GENERIC' 2829 expr = .callExpr 2815 branch peek 2816 on 'LPAREN' 2817 .grab 2818 _spaceAgnosticExprLevel += 1 2819 node = .expression(0, nil) 2820 .expect('RPAREN') 2821 _spaceAgnosticExprLevel -= 1 2822 node.isParened = true 2823 return node 2824 on 'DOT' # leading dot 2825 token = .grab 2826 .opStack.push('DOT') 2827 try 2828 peekToken = .peek 2829 peek = peekToken.which 2830 if peek=='ID' or peekToken.isKeyword 2831 memberToken = .idOrKeyword 2832 expr = MemberExpr(memberToken) to Expr 2833 else if peek=='OPEN_CALL' 2834 expr = .callExpr 2835 else if peek=='OPEN_GENERIC' 2836 expr = .callExpr 2837 else 2838 .throwError('Syntax error after "."') 2839 finally 2840 .opStack.pop 2841 return BinaryOpExpr.make(token to !, 'DOT', ThisLit(token, isImplicit=true), expr) 2842 on 'NIL', return NilLiteral(.grab) 2843 on 'TRUE' or 'FALSE', return BoolLit(.grab) 2844 on 'THIS', return ThisLit(.grab) 2845 on 'BASE', return BaseLit(.grab) 2846 on 'VAR' 2847 assert _curCodePart 2848 if _curCodePart inherits ProperDexerXetter 2849 return VarLit(.grab, _curCodePart) 2830 2850 else 2831 .throwError('Syntax error after "."') 2832 finally 2833 .opStack.pop 2834 return BinaryOpExpr.make(token to !, 'DOT', ThisLit(token, isImplicit=true), expr) 2835 else if peek=='NIL' 2836 return NilLiteral(.grab) 2837 else if peek=='TRUE' 2838 return BoolLit(.grab) 2839 else if peek=='FALSE' 2840 return BoolLit(.grab) 2841 else if peek=='THIS' 2842 return ThisLit(.grab) 2843 else if peek=='BASE' 2844 return BaseLit(.grab) 2845 else if peek=='VAR' 2846 assert _curCodePart 2847 if _curCodePart inherits ProperDexerXetter 2848 return VarLit(.grab, _curCodePart) 2849 else 2850 .throwError('Cannot refer to `var` in expressions outside of a property `get` or `set`.') 2851 throw FallThroughException() # stop a warning 2852 else if peek=='CHAR_LIT_SINGLE' 2853 return CharLit(.grab) 2854 else if peek=='CHAR_LIT_DOUBLE' 2855 return CharLit(.grab) 2856 else if peek=='STRING_START_SINGLE' 2857 return .stringWithSubstitutionLit('STRING_START_SINGLE', 'STRING_PART_SINGLE', 'STRING_STOP_SINGLE') 2858 else if peek=='STRING_START_DOUBLE' 2859 return .stringWithSubstitutionLit('STRING_START_DOUBLE', 'STRING_PART_DOUBLE', 'STRING_STOP_DOUBLE') 2860 else if peek=='STRING_SINGLE' 2861 return StringLit(.grab) 2862 else if peek=='STRING_DOUBLE' 2863 return StringLit(.grab) 2864 else if peek=='INTEGER_LIT' 2865 return IntegerLit(.grab) 2866 else if peek=='DECIMAL_LIT' 2867 return DecimalLit(.grab) 2868 else if peek=='FRACTIONAL_LIT' 2869 return FractionalLit(.grab) 2870 else if peek=='FLOAT_LIT' 2871 return FloatLit(.grab) 2872 else if peek=='LBRACKET' 2873 return .literalList 2874 else if peek=='ARRAY_OPEN' 2875 return .literalArray 2876 else if peek=='LCURLY' 2877 return .literalDictOrSet 2878 else if peek.isOneOf('OPEN_DO.DO.') 2879 return .doExpr 2880 else if peek=='OPEN_IF' 2881 return .ifExpr 2882 else if peek=='FOR' 2883 return .forExpr 2884 else if peek=='OPEN_CALL' 2885 return .callExpr 2886 else if peek=='OPEN_GENERIC' 2887 if .opStack.count and .opStack.peek == 'DOT' 2888 return .callExpr 2889 else 2890 return TypeExpr(.typeId) 2891 else if peek=='ID' 2892 return .identifierExpr 2893 else if peek.isOneOf('SHARP_OPEN.SHARP_SINGLE.SHARP_DOUBLE.') 2894 return .sharpExpr 2895 else if .opStack.count and .opStack.peek=='DOT' and .peek.isKeyword 2896 return .identifierExpr 2897 else 2898 try 2899 return .typeExpr 2900 catch pe as ParserException 2901 if .allowKeywordAssignment and peekToken.isKeyword and .peek is not nil and .peek.which == 'ASSIGN' 2902 assert .last is peekToken 2903 word, op = .last, .grab 2904 if word.text.startsWithNonLowerLetter 2905 .recordError(ErrorMessages.localVariablesMustStartLowercase) 2906 return AssignExpr(op, 'ASSIGN', IdentifierExpr(word), .expression) 2907 else if pe.message.contains('Unrecognized type') 2908 msg = 'Expecting an expression.' 2909 if peekToken.isKeyword 2910 msg += ' "[peekToken.text]" is a reserved keyword that is not expected here.' 2911 .throwError(msg) 2912 throw FallThroughException() 2851 .throwError('Cannot refer to `var` in expressions outside of a property `get` or `set`.') 2852 throw FallThroughException() # stop a warning 2853 on 'CHAR_LIT_SINGLE' or 'CHAR_LIT_DOUBLE' 2854 return CharLit(.grab) 2855 on 'STRING_START_SINGLE' 2856 return .stringWithSubstitutionLit('STRING_START_SINGLE', 'STRING_PART_SINGLE', 'STRING_STOP_SINGLE') 2857 on 'STRING_START_DOUBLE' 2858 return .stringWithSubstitutionLit('STRING_START_DOUBLE', 'STRING_PART_DOUBLE', 'STRING_STOP_DOUBLE') 2859 on 'STRING_SINGLE' or 'STRING_DOUBLE' 2860 return StringLit(.grab) 2861 on 'INTEGER_LIT', return IntegerLit(.grab) 2862 on 'DECIMAL_LIT', return DecimalLit(.grab) 2863 on 'FRACTIONAL_LIT', return FractionalLit(.grab) 2864 on 'FLOAT_LIT', return FloatLit(.grab) 2865 on 'LBRACKET', return .literalList 2866 on 'ARRAY_OPEN', return .literalArray 2867 on 'LCURLY', return .literalDictOrSet 2868 on 'OPEN_DO' or 'DO', return .doExpr 2869 on 'OPEN_IF', return .ifExpr 2870 on 'FOR', return .forExpr 2871 on 'OPEN_CALL', return .callExpr 2872 on 'OPEN_GENERIC' 2873 if .opStack.count and .opStack.peek == 'DOT' 2874 return .callExpr 2913 2875 else 2914 throw 2876 return TypeExpr(.typeId) 2877 on 'ID', return .identifierExpr 2878 on 'SHARP_OPEN' or 'SHARP_SINGLE' or 'SHARP_DOUBLE' 2879 return .sharpExpr 2880 else 2881 if .opStack.count and .opStack.peek=='DOT' and .peek.isKeyword 2882 return .identifierExpr 2883 try 2884 return .typeExpr 2885 catch pe as ParserException 2886 if .allowKeywordAssignment and peekToken.isKeyword and .peek is not nil and .peek.which == 'ASSIGN' 2887 assert .last is peekToken 2888 word, op = .last, .grab 2889 if word.text.startsWithNonLowerLetter 2890 .recordError(ErrorMessages.localVariablesMustStartLowercase) 2891 return AssignExpr(op, 'ASSIGN', IdentifierExpr(word), .expression) 2892 else if pe.message.contains('Unrecognized type') 2893 msg = 'Expecting an expression.' 2894 if peekToken.isKeyword 2895 msg += ' "[peekToken.text]" is a reserved keyword that is not expected here.' 2896 .throwError(msg) 2897 throw FallThroughException() 2898 else 2899 throw 2915 2900 2916 2901 def multiTargetAssign(arg0 as Expr) as Stmt 2917 2902 # id, |[id,]... = <expr>