| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.parser; | 5 library dart2js.parser; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../tokens/keyword.dart' show Keyword; | 8 import '../tokens/keyword.dart' show Keyword; |
| 9 import '../tokens/precedence.dart' show PrecedenceInfo; | 9 import '../tokens/precedence.dart' show PrecedenceInfo; |
| 10 import '../tokens/precedence_constants.dart' | 10 import '../tokens/precedence_constants.dart' |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 period = token; | 355 period = token; |
| 356 token = parseIdentifier(token.next); | 356 token = parseIdentifier(token.next); |
| 357 } | 357 } |
| 358 token = parseArgumentsOpt(token); | 358 token = parseArgumentsOpt(token); |
| 359 listener.endMetadata(atToken, period, token); | 359 listener.endMetadata(atToken, period, token); |
| 360 return token; | 360 return token; |
| 361 } | 361 } |
| 362 | 362 |
| 363 Token parseTypedef(Token token) { | 363 Token parseTypedef(Token token) { |
| 364 Token typedefKeyword = token; | 364 Token typedefKeyword = token; |
| 365 listener.beginTypedef(token); | 365 listener.beginFunctionTypeAlias(token); |
| 366 Token equals; | 366 token = parseReturnTypeOpt(token.next); |
| 367 if (optional('=', peekAfterNominalType(token.next))) { | 367 token = parseIdentifier(token); |
| 368 token = parseIdentifier(token.next); | 368 token = parseTypeVariablesOpt(token); |
| 369 token = parseTypeVariablesOpt(token); | 369 token = parseFormalParameters(token); |
| 370 equals = token; | 370 listener.endFunctionTypeAlias(typedefKeyword, token); |
| 371 token = expect('=', token); | |
| 372 token = parseType(token); | |
| 373 } else { | |
| 374 token = parseReturnTypeOpt(token.next); | |
| 375 token = parseIdentifier(token); | |
| 376 token = parseTypeVariablesOpt(token); | |
| 377 token = parseFormalParameters(token); | |
| 378 } | |
| 379 listener.endTypedef(typedefKeyword, equals, token); | |
| 380 return expect(';', token); | 371 return expect(';', token); |
| 381 } | 372 } |
| 382 | 373 |
| 383 Token parseMixinApplication(Token token) { | 374 Token parseMixinApplication(Token token) { |
| 384 listener.beginMixinApplication(token); | 375 listener.beginMixinApplication(token); |
| 385 token = parseType(token); | 376 token = parseType(token); |
| 386 token = expect('with', token); | 377 token = expect('with', token); |
| 387 token = parseTypeList(token); | 378 token = parseTypeList(token); |
| 388 listener.endMixinApplication(); | 379 listener.endMixinApplication(); |
| 389 return token; | 380 return token; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 400 | 391 |
| 401 Token parseFormalParametersOpt(Token token) { | 392 Token parseFormalParametersOpt(Token token) { |
| 402 if (optional('(', token)) { | 393 if (optional('(', token)) { |
| 403 return parseFormalParameters(token); | 394 return parseFormalParameters(token); |
| 404 } else { | 395 } else { |
| 405 listener.handleNoFormalParameters(token); | 396 listener.handleNoFormalParameters(token); |
| 406 return token; | 397 return token; |
| 407 } | 398 } |
| 408 } | 399 } |
| 409 | 400 |
| 410 /// Parses the formal parameter list of a function. | 401 Token parseFormalParameters(Token token) { |
| 411 /// | |
| 412 /// If [inFunctionType] is true, then the names may be omitted (except for | |
| 413 /// named arguments). If it is false, then the types may be omitted. | |
| 414 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { | |
| 415 Token begin = token; | 402 Token begin = token; |
| 416 listener.beginFormalParameters(begin); | 403 listener.beginFormalParameters(begin); |
| 417 expect('(', token); | 404 expect('(', token); |
| 418 int parameterCount = 0; | 405 int parameterCount = 0; |
| 419 do { | 406 do { |
| 420 token = token.next; | 407 token = token.next; |
| 421 if (optional(')', token)) { | 408 if (optional(')', token)) { |
| 422 break; | 409 break; |
| 423 } | 410 } |
| 424 ++parameterCount; | 411 ++parameterCount; |
| 425 String value = token.stringValue; | 412 String value = token.stringValue; |
| 426 if (identical(value, '[')) { | 413 if (identical(value, '[')) { |
| 427 token = parseOptionalFormalParameters( | 414 token = parseOptionalFormalParameters(token, false); |
| 428 token, false, inFunctionType: inFunctionType); | |
| 429 break; | 415 break; |
| 430 } else if (identical(value, '{')) { | 416 } else if (identical(value, '{')) { |
| 431 token = parseOptionalFormalParameters( | 417 token = parseOptionalFormalParameters(token, true); |
| 432 token, true, inFunctionType: inFunctionType); | |
| 433 break; | 418 break; |
| 434 } | 419 } |
| 435 token = parseFormalParameter(token, FormalParameterType.REQUIRED, | 420 token = parseFormalParameter(token, FormalParameterType.REQUIRED); |
| 436 inFunctionType: inFunctionType); | |
| 437 } while (optional(',', token)); | 421 } while (optional(',', token)); |
| 438 listener.endFormalParameters(parameterCount, begin, token); | 422 listener.endFormalParameters(parameterCount, begin, token); |
| 439 return expect(')', token); | 423 return expect(')', token); |
| 440 } | 424 } |
| 441 | 425 |
| 442 Token parseFormalParameter(Token token, FormalParameterType type, | 426 Token parseFormalParameter(Token token, FormalParameterType type) { |
| 443 {bool inFunctionType}) { | |
| 444 token = parseMetadataStar(token, forParameter: true); | 427 token = parseMetadataStar(token, forParameter: true); |
| 445 listener.beginFormalParameter(token); | 428 listener.beginFormalParameter(token); |
| 446 | 429 |
| 447 // Skip over `covariant` token, if the next token is an identifier or | 430 // Skip over `covariant` token, if the next token is an identifier or |
| 448 // modifier. | 431 // modifier. |
| 449 // This enables the case where `covariant` is the name of the parameter: | 432 // This enables the case where `covariant` is the name of the parameter: |
| 450 // void foo(covariant); | 433 // void foo(covariant); |
| 451 if (identical(token.stringValue, 'covariant') && | 434 if (identical(token.stringValue, 'covariant') && |
| 452 (token.next.isIdentifier() || isModifier(token.next))) { | 435 (token.next.isIdentifier() || isModifier(token.next))) { |
| 453 token = token.next; | 436 token = token.next; |
| 454 } | 437 } |
| 455 token = parseModifiers(token); | 438 token = parseModifiers(token); |
| 456 bool isNamedParameter = type == FormalParameterType.NAMED; | 439 // TODO(ahe): Validate that there are formal parameters if void. |
| 457 | 440 token = parseReturnTypeOpt(token); |
| 458 Token thisKeyword = null; | 441 Token thisKeyword = null; |
| 459 if (inFunctionType && isNamedParameter) { | 442 if (optional('this', token)) { |
| 460 token = parseType(token); | 443 thisKeyword = token; |
| 461 token = parseIdentifier(token); | 444 // TODO(ahe): Validate field initializers are only used in |
| 462 } else if (inFunctionType) { | 445 // constructors, and not for function-typed arguments. |
| 463 token = parseType(token); | 446 token = expect('.', token.next); |
| 464 if (token.isIdentifier()) { | |
| 465 token = parseIdentifier(token); | |
| 466 } else { | |
| 467 listener.handleNoName(token); | |
| 468 } | |
| 469 } else { | |
| 470 token = parseReturnTypeOpt(token); | |
| 471 if (optional('this', token)) { | |
| 472 thisKeyword = token; | |
| 473 token = expect('.', token.next); | |
| 474 } | |
| 475 token = parseIdentifier(token); | |
| 476 } | 447 } |
| 477 | 448 token = parseIdentifier(token); |
| 478 // Generalized function types don't allow inline function types. | 449 if (optional('(', token)) { |
| 479 // The following isn't allowed: | 450 listener.handleNoTypeVariables(token); |
| 480 // int Function(int bar(String x)). | 451 token = parseFormalParameters(token); |
| 481 if (!inFunctionType) { | 452 listener.handleFunctionTypedFormalParameter(token); |
| 482 if (optional('(', token)) { | 453 } else if (optional('<', token)) { |
| 483 listener.handleNoTypeVariables(token); | 454 token = parseTypeVariablesOpt(token); |
| 484 token = parseFormalParameters(token); | 455 token = parseFormalParameters(token); |
| 485 listener.handleFunctionTypedFormalParameter(token); | 456 listener.handleFunctionTypedFormalParameter(token); |
| 486 } else if (optional('<', token)) { | |
| 487 token = parseTypeVariablesOpt(token); | |
| 488 token = parseFormalParameters(token); | |
| 489 listener.handleFunctionTypedFormalParameter(token); | |
| 490 } | |
| 491 } | 457 } |
| 492 String value = token.stringValue; | 458 String value = token.stringValue; |
| 493 if ((identical('=', value)) || (identical(':', value))) { | 459 if ((identical('=', value)) || (identical(':', value))) { |
| 494 // TODO(ahe): Validate that these are only used for optional parameters. | 460 // TODO(ahe): Validate that these are only used for optional parameters. |
| 495 Token equal = token; | 461 Token equal = token; |
| 496 token = parseExpression(token.next); | 462 token = parseExpression(token.next); |
| 497 listener.handleValuedFormalParameter(equal, token); | 463 listener.handleValuedFormalParameter(equal, token); |
| 498 if (type.isRequired) { | 464 if (type.isRequired) { |
| 499 listener.reportError( | 465 listener.reportError( |
| 500 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); | 466 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); |
| 501 } else if (type.isPositional && identical(':', value)) { | 467 } else if (type.isPositional && identical(':', value)) { |
| 502 listener.reportError( | 468 listener.reportError( |
| 503 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); | 469 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); |
| 504 } | 470 } |
| 505 } | 471 } |
| 506 listener.endFormalParameter(thisKeyword); | 472 listener.endFormalParameter(thisKeyword); |
| 507 return token; | 473 return token; |
| 508 } | 474 } |
| 509 | 475 |
| 510 Token parseOptionalFormalParameters(Token token, bool isNamed, | 476 Token parseOptionalFormalParameters(Token token, bool isNamed) { |
| 511 {bool inFunctionType}) { | |
| 512 Token begin = token; | 477 Token begin = token; |
| 513 listener.beginOptionalFormalParameters(begin); | 478 listener.beginOptionalFormalParameters(begin); |
| 514 assert((isNamed && optional('{', token)) || optional('[', token)); | 479 assert((isNamed && optional('{', token)) || optional('[', token)); |
| 515 int parameterCount = 0; | 480 int parameterCount = 0; |
| 516 do { | 481 do { |
| 517 token = token.next; | 482 token = token.next; |
| 518 if (isNamed && optional('}', token)) { | 483 if (isNamed && optional('}', token)) { |
| 519 break; | 484 break; |
| 520 } else if (!isNamed && optional(']', token)) { | 485 } else if (!isNamed && optional(']', token)) { |
| 521 break; | 486 break; |
| 522 } | 487 } |
| 523 var type = | 488 var type = |
| 524 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 489 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
| 525 token = | 490 token = parseFormalParameter(token, type); |
| 526 parseFormalParameter(token, type, inFunctionType: inFunctionType); | |
| 527 ++parameterCount; | 491 ++parameterCount; |
| 528 } while (optional(',', token)); | 492 } while (optional(',', token)); |
| 529 if (parameterCount == 0) { | 493 if (parameterCount == 0) { |
| 530 listener.reportError( | 494 listener.reportError( |
| 531 token, | 495 token, |
| 532 isNamed | 496 isNamed |
| 533 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST | 497 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST |
| 534 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); | 498 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); |
| 535 } | 499 } |
| 536 listener.endOptionalFormalParameters(parameterCount, begin, token); | 500 listener.endOptionalFormalParameters(parameterCount, begin, token); |
| 537 if (isNamed) { | 501 if (isNamed) { |
| 538 return expect('}', token); | 502 return expect('}', token); |
| 539 } else { | 503 } else { |
| 540 return expect(']', token); | 504 return expect(']', token); |
| 541 } | 505 } |
| 542 } | 506 } |
| 543 | 507 |
| 544 Token parseTypeOpt(Token token) { | 508 Token parseTypeOpt(Token token) { |
| 545 if (isGeneralizedFunctionType(token)) { | |
| 546 // Function type without return type. | |
| 547 return parseType(token); | |
| 548 } | |
| 549 Token peek = peekAfterIfType(token); | 509 Token peek = peekAfterIfType(token); |
| 550 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 510 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
| 551 return parseType(token); | 511 return parseType(token); |
| 552 } | 512 } |
| 553 listener.handleNoType(token); | 513 listener.handleNoType(token); |
| 554 return token; | 514 return token; |
| 555 } | 515 } |
| 556 | 516 |
| 557 bool isValidTypeReference(Token token) { | 517 bool isValidTypeReference(Token token) { |
| 558 final kind = token.kind; | 518 final kind = token.kind; |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 } | 663 } |
| 704 | 664 |
| 705 Token parseClassOrNamedMixinApplication(Token token) { | 665 Token parseClassOrNamedMixinApplication(Token token) { |
| 706 Token begin = token; | 666 Token begin = token; |
| 707 Token abstractKeyword; | 667 Token abstractKeyword; |
| 708 if (optional('abstract', token)) { | 668 if (optional('abstract', token)) { |
| 709 abstractKeyword = token; | 669 abstractKeyword = token; |
| 710 token = token.next; | 670 token = token.next; |
| 711 } | 671 } |
| 712 Token classKeyword = token; | 672 Token classKeyword = token; |
| 713 var isMixinApplication = optional('=', peekAfterNominalType(token.next)); | 673 var isMixinApplication = optional('=', peekAfterType(token.next)); |
| 714 if (isMixinApplication) { | 674 if (isMixinApplication) { |
| 715 listener.beginNamedMixinApplication(begin); | 675 listener.beginNamedMixinApplication(begin); |
| 716 } else { | 676 } else { |
| 717 listener.beginClassDeclaration(begin); | 677 listener.beginClassDeclaration(begin); |
| 718 } | 678 } |
| 719 | 679 |
| 720 int modifierCount = 0; | 680 int modifierCount = 0; |
| 721 if (abstractKeyword != null) { | 681 if (abstractKeyword != null) { |
| 722 parseModifier(abstractKeyword); | 682 parseModifier(abstractKeyword); |
| 723 modifierCount++; | 683 modifierCount++; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 744 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); | 704 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); |
| 745 return expect(';', token); | 705 return expect(';', token); |
| 746 } | 706 } |
| 747 | 707 |
| 748 Token parseClass(Token begin, Token classKeyword) { | 708 Token parseClass(Token begin, Token classKeyword) { |
| 749 Token token = parseIdentifier(classKeyword.next); | 709 Token token = parseIdentifier(classKeyword.next); |
| 750 token = parseTypeVariablesOpt(token); | 710 token = parseTypeVariablesOpt(token); |
| 751 Token extendsKeyword; | 711 Token extendsKeyword; |
| 752 if (optional('extends', token)) { | 712 if (optional('extends', token)) { |
| 753 extendsKeyword = token; | 713 extendsKeyword = token; |
| 754 if (optional('with', peekAfterNominalType(token.next))) { | 714 if (optional('with', peekAfterType(token.next))) { |
| 755 token = parseMixinApplication(token.next); | 715 token = parseMixinApplication(token.next); |
| 756 } else { | 716 } else { |
| 757 token = parseType(token.next); | 717 token = parseType(token.next); |
| 758 } | 718 } |
| 759 } else { | 719 } else { |
| 760 extendsKeyword = null; | 720 extendsKeyword = null; |
| 761 listener.handleNoType(token); | 721 listener.handleNoType(token); |
| 762 } | 722 } |
| 763 Token implementsKeyword; | 723 Token implementsKeyword; |
| 764 int interfacesCount = 0; | 724 int interfacesCount = 0; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 value2 == stringValue || | 802 value2 == stringValue || |
| 843 value3 == stringValue || | 803 value3 == stringValue || |
| 844 value4 == stringValue; | 804 value4 == stringValue; |
| 845 } | 805 } |
| 846 | 806 |
| 847 bool notEofOrValue(String value, Token token) { | 807 bool notEofOrValue(String value, Token token) { |
| 848 return !identical(token.kind, EOF_TOKEN) && | 808 return !identical(token.kind, EOF_TOKEN) && |
| 849 !identical(value, token.stringValue); | 809 !identical(value, token.stringValue); |
| 850 } | 810 } |
| 851 | 811 |
| 852 bool isGeneralizedFunctionType(Token token) { | |
| 853 // TODO(floitsch): don't use string comparison, but the keyword-state | |
| 854 // table is currently not set up to deal with upper-case characters. | |
| 855 return (optional('<', token.next) || optional('(', token.next)) && | |
| 856 token.value == "Function"; | |
| 857 } | |
| 858 | |
| 859 Token parseType(Token token) { | 812 Token parseType(Token token) { |
| 860 Token begin = token; | 813 Token begin = token; |
| 861 if (isGeneralizedFunctionType(token)) { | 814 if (isValidTypeReference(token)) { |
| 862 // A function type without return type. | 815 token = parseIdentifier(token); |
| 863 // Push the non-existing return type first. The loop below will | 816 token = parseQualifiedRestOpt(token); |
| 864 // generate the full type. | |
| 865 listener.handleNoType(token); | |
| 866 } else { | 817 } else { |
| 867 if (isValidTypeReference(token)) { | 818 token = listener.expectedType(token); |
| 868 token = parseIdentifier(token); | |
| 869 token = parseQualifiedRestOpt(token); | |
| 870 } else { | |
| 871 token = listener.expectedType(token); | |
| 872 } | |
| 873 token = parseTypeArgumentsOpt(token); | |
| 874 listener.endType(begin, token); | |
| 875 } | 819 } |
| 876 | 820 token = parseTypeArgumentsOpt(token); |
| 877 // While we see a `Function(` treat the pushed type as return type. | 821 listener.endType(begin, token); |
| 878 // For example: `int Function() Function(int) Function(String x)`. | |
| 879 while (isGeneralizedFunctionType(token)) { | |
| 880 token = parseFunctionType(token); | |
| 881 } | |
| 882 return token; | 822 return token; |
| 883 } | 823 } |
| 884 | 824 |
| 885 /// Parses a generalized function type. | |
| 886 /// | |
| 887 /// The return type must already be pushed. | |
| 888 Token parseFunctionType(Token token) { | |
| 889 // TODO(floitsch): don't use string comparison, but the keyword-state | |
| 890 // table is currently not set up to deal with upper-case characters. | |
| 891 if (token.value != "Function") { | |
| 892 return listener.expected("Function", token); | |
| 893 } | |
| 894 Token functionToken = token; | |
| 895 token = token.next; | |
| 896 token = parseTypeVariablesOpt(token); | |
| 897 token = parseFormalParameters(token, inFunctionType: true); | |
| 898 listener.endFunctionType(functionToken, token); | |
| 899 return token; | |
| 900 } | |
| 901 | |
| 902 Token parseTypeArgumentsOpt(Token token) { | 825 Token parseTypeArgumentsOpt(Token token) { |
| 903 return parseStuff( | 826 return parseStuff( |
| 904 token, | 827 token, |
| 905 (t) => listener.beginTypeArguments(t), | 828 (t) => listener.beginTypeArguments(t), |
| 906 (t) => parseType(t), | 829 (t) => parseType(t), |
| 907 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 830 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
| 908 (t) => listener.handleNoTypeArguments(t)); | 831 (t) => listener.handleNoTypeArguments(t)); |
| 909 } | 832 } |
| 910 | 833 |
| 911 Token parseTypeVariablesOpt(Token token) { | 834 Token parseTypeVariablesOpt(Token token) { |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1245 identifiers = identifiers.prepend(token); | 1168 identifiers = identifiers.prepend(token); |
| 1246 return identifiers; | 1169 return identifiers; |
| 1247 } else if (value == '=' || value == ';' || value == ',') { | 1170 } else if (value == '=' || value == ';' || value == ',') { |
| 1248 // A field or abstract getter. | 1171 // A field or abstract getter. |
| 1249 identifiers = identifiers.prepend(token); | 1172 identifiers = identifiers.prepend(token); |
| 1250 return identifiers; | 1173 return identifiers; |
| 1251 } else if (isGetter) { | 1174 } else if (isGetter) { |
| 1252 hasName = true; | 1175 hasName = true; |
| 1253 } | 1176 } |
| 1254 identifiers = identifiers.prepend(token); | 1177 identifiers = identifiers.prepend(token); |
| 1255 | 1178 if (isValidTypeReference(token)) { |
| 1256 if (!isGeneralizedFunctionType(token)) { | 1179 // type ... |
| 1257 // Read a potential return type. | 1180 if (optional('.', token.next)) { |
| 1258 if (isValidTypeReference(token)) { | 1181 // type '.' ... |
| 1259 // type ... | 1182 if (token.next.next.isIdentifier()) { |
| 1260 if (optional('.', token.next)) { | 1183 // type '.' identifier |
| 1261 // type '.' ... | 1184 token = token.next.next; |
| 1262 if (token.next.next.isIdentifier()) { | |
| 1263 // type '.' identifier | |
| 1264 token = token.next.next; | |
| 1265 } | |
| 1266 } | |
| 1267 if (optional('<', token.next)) { | |
| 1268 if (token.next is BeginGroupToken) { | |
| 1269 BeginGroupToken beginGroup = token.next; | |
| 1270 if (beginGroup.endGroup == null) { | |
| 1271 listener.unmatched(beginGroup); | |
| 1272 } | |
| 1273 token = beginGroup.endGroup; | |
| 1274 } | |
| 1275 } | 1185 } |
| 1276 } | 1186 } |
| 1277 token = token.next; | 1187 if (optional('<', token.next)) { |
| 1278 } | 1188 if (token.next is BeginGroupToken) { |
| 1279 while (isGeneralizedFunctionType(token)) { | 1189 BeginGroupToken beginGroup = token.next; |
| 1280 token = token.next; | |
| 1281 if (optional('<', token)) { | |
| 1282 if (token is BeginGroupToken) { | |
| 1283 BeginGroupToken beginGroup = token; | |
| 1284 if (beginGroup.endGroup == null) { | 1190 if (beginGroup.endGroup == null) { |
| 1285 listener.unmatched(beginGroup); | 1191 listener.unmatched(beginGroup); |
| 1286 } | 1192 } |
| 1287 token = beginGroup.endGroup.next; | 1193 token = beginGroup.endGroup; |
| 1288 } | 1194 } |
| 1289 } | 1195 } |
| 1290 if (!optional('(', token)) { | |
| 1291 if (optional(';', token)) { | |
| 1292 listener.recoverableError(token, "expected '('"); | |
| 1293 } | |
| 1294 token = listener.unexpected(token); | |
| 1295 } | |
| 1296 if (token is BeginGroupToken) { | |
| 1297 BeginGroupToken beginGroup = token; | |
| 1298 if (beginGroup.endGroup == null) { | |
| 1299 listener.unmatched(beginGroup); | |
| 1300 } | |
| 1301 token = beginGroup.endGroup.next; | |
| 1302 } | |
| 1303 } | 1196 } |
| 1197 token = token.next; |
| 1304 } | 1198 } |
| 1305 return const Link<Token>(); | 1199 return const Link<Token>(); |
| 1306 } | 1200 } |
| 1307 | 1201 |
| 1308 Token parseVariableInitializerOpt(Token token) { | 1202 Token parseVariableInitializerOpt(Token token) { |
| 1309 if (optional('=', token)) { | 1203 if (optional('=', token)) { |
| 1310 Token assignment = token; | 1204 Token assignment = token; |
| 1311 listener.beginInitializer(token); | 1205 listener.beginInitializer(token); |
| 1312 token = parseExpression(token.next); | 1206 token = parseExpression(token.next); |
| 1313 listener.endInitializer(assignment); | 1207 listener.endInitializer(assignment); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1391 if (!isModifier(token)) break; | 1285 if (!isModifier(token)) break; |
| 1392 token = parseModifier(token); | 1286 token = parseModifier(token); |
| 1393 count++; | 1287 count++; |
| 1394 } | 1288 } |
| 1395 listener.handleModifiers(count); | 1289 listener.handleModifiers(count); |
| 1396 return token; | 1290 return token; |
| 1397 } | 1291 } |
| 1398 | 1292 |
| 1399 /** | 1293 /** |
| 1400 * Returns the first token after the type starting at [token]. | 1294 * Returns the first token after the type starting at [token]. |
| 1401 * | |
| 1402 * This method assumes that [token] is an identifier (or void). | 1295 * This method assumes that [token] is an identifier (or void). |
| 1403 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1296 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
| 1404 */ | 1297 */ |
| 1405 Token peekAfterType(Token token) { | 1298 Token peekAfterType(Token token) { |
| 1406 // We are looking at "identifier ...". | 1299 // We are looking at "identifier ...". |
| 1407 Token peek = token; | |
| 1408 if (!isGeneralizedFunctionType(token)) { | |
| 1409 peek = peekAfterNominalType(token); | |
| 1410 } | |
| 1411 | |
| 1412 // We might have just skipped over the return value of the function type. | |
| 1413 // Check again, if we are now at a function type position. | |
| 1414 while (isGeneralizedFunctionType(peek)) { | |
| 1415 peek = peekAfterFunctionType(peek); | |
| 1416 } | |
| 1417 return peek; | |
| 1418 } | |
| 1419 | |
| 1420 /** | |
| 1421 * Returns the first token after the nominal type starting at [token]. | |
| 1422 * | |
| 1423 * This method assumes that [token] is an identifier (or void). | |
| 1424 */ | |
| 1425 Token peekAfterNominalType(Token token) { | |
| 1426 Token peek = token.next; | 1300 Token peek = token.next; |
| 1427 if (identical(peek.kind, PERIOD_TOKEN)) { | 1301 if (identical(peek.kind, PERIOD_TOKEN)) { |
| 1428 if (peek.next.isIdentifier()) { | 1302 if (peek.next.isIdentifier()) { |
| 1429 // Look past a library prefix. | 1303 // Look past a library prefix. |
| 1430 peek = peek.next.next; | 1304 peek = peek.next.next; |
| 1431 } | 1305 } |
| 1432 } | 1306 } |
| 1433 // We are looking at "qualified ...". | 1307 // We are looking at "qualified ...". |
| 1434 if (identical(peek.kind, LT_TOKEN)) { | 1308 if (identical(peek.kind, LT_TOKEN)) { |
| 1435 // Possibly generic type. | 1309 // Possibly generic type. |
| 1436 // We are looking at "qualified '<'". | 1310 // We are looking at "qualified '<'". |
| 1437 BeginGroupToken beginGroupToken = peek; | 1311 BeginGroupToken beginGroupToken = peek; |
| 1438 Token gtToken = beginGroupToken.endGroup; | 1312 Token gtToken = beginGroupToken.endGroup; |
| 1439 if (gtToken != null) { | 1313 if (gtToken != null) { |
| 1440 // We are looking at "qualified '<' ... '>' ...". | 1314 // We are looking at "qualified '<' ... '>' ...". |
| 1441 peek = gtToken.next; | 1315 return gtToken.next; |
| 1442 } | 1316 } |
| 1443 } | 1317 } |
| 1444 return peek; | 1318 return peek; |
| 1445 } | 1319 } |
| 1446 | 1320 |
| 1447 /** | 1321 /** |
| 1448 * Returns the first token after the function type starting at [token]. | |
| 1449 * | |
| 1450 * The token must be at the `Function` token position. That is, the return | |
| 1451 * type must have already been skipped. | |
| 1452 * | |
| 1453 * This function only skips over one function type syntax. | |
| 1454 * If necessary, this function must be called multiple times. | |
| 1455 * | |
| 1456 * Example: | |
| 1457 * ``` | |
| 1458 * int Function() Function<T>(int) | |
| 1459 * ^ ^ | |
| 1460 * A call to this function must be at one of the `Function` tokens. | |
| 1461 * If `token` pointed to the first `Function` token, then the returned | |
| 1462 * token points to the second `Function` token. | |
| 1463 */ | |
| 1464 Token peekAfterFunctionType(Token token) { | |
| 1465 // Possible inputs are: | |
| 1466 // Function( ... ) | |
| 1467 // Function< ... >( ... ) | |
| 1468 | |
| 1469 Token peek = token.next; // Skip over the Function token. | |
| 1470 // If there is a generic argument to the function, skip over that one first. | |
| 1471 if (identical(peek.kind, LT_TOKEN)) { | |
| 1472 BeginGroupToken beginGroupToken = peek; | |
| 1473 Token closeToken = beginGroupToken.endGroup; | |
| 1474 if (closeToken != null) { | |
| 1475 peek = closeToken.next; | |
| 1476 } | |
| 1477 } | |
| 1478 | |
| 1479 // Now we just need to skip over the formals. | |
| 1480 expect('(', peek); | |
| 1481 | |
| 1482 BeginGroupToken beginGroupToken = peek; | |
| 1483 Token closeToken = beginGroupToken.endGroup; | |
| 1484 if (closeToken != null) { | |
| 1485 peek = closeToken.next; | |
| 1486 } | |
| 1487 | |
| 1488 return peek; | |
| 1489 } | |
| 1490 | |
| 1491 /** | |
| 1492 * If [token] is the start of a type, returns the token after that type. | 1322 * If [token] is the start of a type, returns the token after that type. |
| 1493 * If [token] is not the start of a type, null is returned. | 1323 * If [token] is not the start of a type, null is returned. |
| 1494 */ | 1324 */ |
| 1495 Token peekAfterIfType(Token token) { | 1325 Token peekAfterIfType(Token token) { |
| 1496 if (!optional('void', token) && !token.isIdentifier()) { | 1326 if (!optional('void', token) && !token.isIdentifier()) { |
| 1497 return null; | 1327 return null; |
| 1498 } | 1328 } |
| 1499 return peekAfterType(token); | 1329 return peekAfterType(token); |
| 1500 } | 1330 } |
| 1501 | 1331 |
| (...skipping 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3168 } | 2998 } |
| 3169 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 2999 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
| 3170 return expectSemicolon(token); | 3000 return expectSemicolon(token); |
| 3171 } | 3001 } |
| 3172 | 3002 |
| 3173 Token parseEmptyStatement(Token token) { | 3003 Token parseEmptyStatement(Token token) { |
| 3174 listener.handleEmptyStatement(token); | 3004 listener.handleEmptyStatement(token); |
| 3175 return expectSemicolon(token); | 3005 return expectSemicolon(token); |
| 3176 } | 3006 } |
| 3177 } | 3007 } |
| OLD | NEW |