Chromium Code Reviews| 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.beginFunctionTypeAlias(token); | 365 listener.beginTypedef(token); |
| 366 token = parseReturnTypeOpt(token.next); | 366 Token equals; |
| 367 token = parseIdentifier(token); | 367 if (optional('=', peekAfterNominalType(token.next))) { |
| 368 token = parseTypeVariablesOpt(token); | 368 token = parseIdentifier(token.next); |
| 369 token = parseFormalParameters(token); | 369 token = parseTypeVariablesOpt(token); |
| 370 listener.endFunctionTypeAlias(typedefKeyword, token); | 370 equals = expect('=', token); |
|
Johnni Winther
2017/01/02 12:46:53
We are only using [equals] as a marker, but with t
floitsch
2017/01/02 13:48:48
Right. Good catch.
done.
| |
| 371 token = parseType(equals); | |
| 372 } else { | |
| 373 token = parseReturnTypeOpt(token.next); | |
| 374 token = parseIdentifier(token); | |
| 375 token = parseTypeVariablesOpt(token); | |
| 376 token = parseFormalParameters(token); | |
| 377 } | |
| 378 listener.endTypedef(typedefKeyword, equals, token); | |
| 371 return expect(';', token); | 379 return expect(';', token); |
| 372 } | 380 } |
| 373 | 381 |
| 374 Token parseMixinApplication(Token token) { | 382 Token parseMixinApplication(Token token) { |
| 375 listener.beginMixinApplication(token); | 383 listener.beginMixinApplication(token); |
| 376 token = parseType(token); | 384 token = parseType(token); |
| 377 token = expect('with', token); | 385 token = expect('with', token); |
| 378 token = parseTypeList(token); | 386 token = parseTypeList(token); |
| 379 listener.endMixinApplication(); | 387 listener.endMixinApplication(); |
| 380 return token; | 388 return token; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 391 | 399 |
| 392 Token parseFormalParametersOpt(Token token) { | 400 Token parseFormalParametersOpt(Token token) { |
| 393 if (optional('(', token)) { | 401 if (optional('(', token)) { |
| 394 return parseFormalParameters(token); | 402 return parseFormalParameters(token); |
| 395 } else { | 403 } else { |
| 396 listener.handleNoFormalParameters(token); | 404 listener.handleNoFormalParameters(token); |
| 397 return token; | 405 return token; |
| 398 } | 406 } |
| 399 } | 407 } |
| 400 | 408 |
| 401 Token parseFormalParameters(Token token) { | 409 /// Parses the formal parameter list of a function. |
| 410 /// | |
| 411 /// If [inFunctionType] is true, then the names may be omitted (except for | |
| 412 /// named arguments). If it is false, then the types may be omitted. | |
| 413 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { | |
| 402 Token begin = token; | 414 Token begin = token; |
| 403 listener.beginFormalParameters(begin); | 415 listener.beginFormalParameters(begin); |
| 404 expect('(', token); | 416 expect('(', token); |
| 405 int parameterCount = 0; | 417 int parameterCount = 0; |
| 406 do { | 418 do { |
| 407 token = token.next; | 419 token = token.next; |
| 408 if (optional(')', token)) { | 420 if (optional(')', token)) { |
| 409 break; | 421 break; |
| 410 } | 422 } |
| 411 ++parameterCount; | 423 ++parameterCount; |
| 412 String value = token.stringValue; | 424 String value = token.stringValue; |
| 413 if (identical(value, '[')) { | 425 if (identical(value, '[')) { |
| 414 token = parseOptionalFormalParameters(token, false); | 426 token = parseOptionalFormalParameters( |
| 427 token, false, inFunctionType: inFunctionType); | |
| 415 break; | 428 break; |
| 416 } else if (identical(value, '{')) { | 429 } else if (identical(value, '{')) { |
| 417 token = parseOptionalFormalParameters(token, true); | 430 token = parseOptionalFormalParameters( |
| 431 token, true, inFunctionType: inFunctionType); | |
| 418 break; | 432 break; |
| 419 } | 433 } |
| 420 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | 434 token = parseFormalParameter(token, FormalParameterType.REQUIRED, |
| 435 inFunctionType: inFunctionType); | |
| 421 } while (optional(',', token)); | 436 } while (optional(',', token)); |
| 422 listener.endFormalParameters(parameterCount, begin, token); | 437 listener.endFormalParameters(parameterCount, begin, token); |
| 423 return expect(')', token); | 438 return expect(')', token); |
| 424 } | 439 } |
| 425 | 440 |
| 426 Token parseFormalParameter(Token token, FormalParameterType type) { | 441 Token parseFormalParameter(Token token, FormalParameterType type, |
| 442 {bool inFunctionType}) { | |
| 427 token = parseMetadataStar(token, forParameter: true); | 443 token = parseMetadataStar(token, forParameter: true); |
| 428 listener.beginFormalParameter(token); | 444 listener.beginFormalParameter(token); |
| 429 token = parseModifiers(token); | 445 token = parseModifiers(token); |
| 430 // TODO(ahe): Validate that there are formal parameters if void. | 446 bool isNamedParameter = type == FormalParameterType.NAMED; |
| 431 token = parseReturnTypeOpt(token); | 447 |
| 432 Token thisKeyword = null; | 448 Token thisKeyword = null; |
| 433 if (optional('this', token)) { | 449 if (inFunctionType && isNamedParameter) { |
| 434 thisKeyword = token; | 450 token = parseTypeOpt(token); |
| 435 // TODO(ahe): Validate field initializers are only used in | 451 token = parseIdentifier(token); |
| 436 // constructors, and not for function-typed arguments. | 452 } else if (inFunctionType) { |
| 437 token = expect('.', token.next); | 453 token = parseType(token); |
| 454 if (token.isIdentifier()) { | |
| 455 token = parseIdentifier(token); | |
| 456 } else { | |
| 457 listener.handleNoName(token); | |
| 458 } | |
| 459 } else { | |
| 460 // TODO(ahe): Validate that there are formal parameters if void. | |
|
Johnni Winther
2017/01/02 12:46:53
Remove. This is checked in resolution.
floitsch
2017/01/02 13:48:48
Done.
| |
| 461 token = parseReturnTypeOpt(token); | |
| 462 if (optional('this', token)) { | |
| 463 thisKeyword = token; | |
| 464 // TODO(ahe): Validate field initializers are only used in | |
| 465 // constructors, and not for function-typed arguments. | |
|
Johnni Winther
2017/01/02 12:46:53
Ditto.
floitsch
2017/01/02 13:48:48
Done.
| |
| 466 token = expect('.', token.next); | |
| 467 } | |
| 468 token = parseIdentifier(token); | |
| 438 } | 469 } |
| 439 token = parseIdentifier(token); | 470 |
| 440 if (optional('(', token)) { | 471 // Generalized function types don't allow inline function types. |
| 441 listener.handleNoTypeVariables(token); | 472 // The following isn't allowed: |
| 442 token = parseFormalParameters(token); | 473 // int Function(int bar(String x)). |
| 443 listener.handleFunctionTypedFormalParameter(token); | 474 if (!inFunctionType) { |
| 444 } else if (optional('<', token)) { | 475 if (optional('(', token)) { |
| 445 token = parseTypeVariablesOpt(token); | 476 listener.handleNoTypeVariables(token); |
| 446 token = parseFormalParameters(token); | 477 token = parseFormalParameters(token); |
| 447 listener.handleFunctionTypedFormalParameter(token); | 478 listener.handleFunctionTypedFormalParameter(token); |
| 479 } else if (optional('<', token)) { | |
| 480 token = parseTypeVariablesOpt(token); | |
| 481 token = parseFormalParameters(token); | |
| 482 listener.handleFunctionTypedFormalParameter(token); | |
| 483 } | |
| 448 } | 484 } |
| 449 String value = token.stringValue; | 485 String value = token.stringValue; |
| 450 if ((identical('=', value)) || (identical(':', value))) { | 486 if ((identical('=', value)) || (identical(':', value))) { |
| 451 // TODO(ahe): Validate that these are only used for optional parameters. | 487 // TODO(ahe): Validate that these are only used for optional parameters. |
| 452 Token equal = token; | 488 Token equal = token; |
| 453 token = parseExpression(token.next); | 489 token = parseExpression(token.next); |
| 454 listener.handleValuedFormalParameter(equal, token); | 490 listener.handleValuedFormalParameter(equal, token); |
| 455 if (type.isRequired) { | 491 if (type.isRequired) { |
| 456 listener.reportError( | 492 listener.reportError( |
| 457 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); | 493 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); |
| 458 } else if (type.isPositional && identical(':', value)) { | 494 } else if (type.isPositional && identical(':', value)) { |
| 459 listener.reportError( | 495 listener.reportError( |
| 460 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); | 496 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); |
| 461 } | 497 } |
| 462 } | 498 } |
| 463 listener.endFormalParameter(thisKeyword); | 499 listener.endFormalParameter(thisKeyword); |
| 464 return token; | 500 return token; |
| 465 } | 501 } |
| 466 | 502 |
| 467 Token parseOptionalFormalParameters(Token token, bool isNamed) { | 503 Token parseOptionalFormalParameters(Token token, bool isNamed, |
| 504 {bool inFunctionType}) { | |
| 468 Token begin = token; | 505 Token begin = token; |
| 469 listener.beginOptionalFormalParameters(begin); | 506 listener.beginOptionalFormalParameters(begin); |
| 470 assert((isNamed && optional('{', token)) || optional('[', token)); | 507 assert((isNamed && optional('{', token)) || optional('[', token)); |
| 471 int parameterCount = 0; | 508 int parameterCount = 0; |
| 472 do { | 509 do { |
| 473 token = token.next; | 510 token = token.next; |
| 474 if (isNamed && optional('}', token)) { | 511 if (isNamed && optional('}', token)) { |
| 475 break; | 512 break; |
| 476 } else if (!isNamed && optional(']', token)) { | 513 } else if (!isNamed && optional(']', token)) { |
| 477 break; | 514 break; |
| 478 } | 515 } |
| 479 var type = | 516 var type = |
| 480 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 517 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
| 481 token = parseFormalParameter(token, type); | 518 token = |
| 519 parseFormalParameter(token, type, inFunctionType: inFunctionType); | |
| 482 ++parameterCount; | 520 ++parameterCount; |
| 483 } while (optional(',', token)); | 521 } while (optional(',', token)); |
| 484 if (parameterCount == 0) { | 522 if (parameterCount == 0) { |
| 485 listener.reportError( | 523 listener.reportError( |
| 486 token, | 524 token, |
| 487 isNamed | 525 isNamed |
| 488 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST | 526 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST |
| 489 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); | 527 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); |
| 490 } | 528 } |
| 491 listener.endOptionalFormalParameters(parameterCount, begin, token); | 529 listener.endOptionalFormalParameters(parameterCount, begin, token); |
| 492 if (isNamed) { | 530 if (isNamed) { |
| 493 return expect('}', token); | 531 return expect('}', token); |
| 494 } else { | 532 } else { |
| 495 return expect(']', token); | 533 return expect(']', token); |
| 496 } | 534 } |
| 497 } | 535 } |
| 498 | 536 |
| 499 Token parseTypeOpt(Token token) { | 537 Token parseTypeOpt(Token token) { |
| 538 if (isGeneralizedFunctionType(token)) { | |
| 539 // Function type without return type. | |
| 540 return parseType(token); | |
| 541 } | |
| 500 Token peek = peekAfterIfType(token); | 542 Token peek = peekAfterIfType(token); |
| 501 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 543 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
| 502 return parseType(token); | 544 return parseType(token); |
| 503 } | 545 } |
| 504 listener.handleNoType(token); | 546 listener.handleNoType(token); |
| 505 return token; | 547 return token; |
| 506 } | 548 } |
| 507 | 549 |
| 508 bool isValidTypeReference(Token token) { | 550 bool isValidTypeReference(Token token) { |
| 509 final kind = token.kind; | 551 final kind = token.kind; |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 654 } | 696 } |
| 655 | 697 |
| 656 Token parseClassOrNamedMixinApplication(Token token) { | 698 Token parseClassOrNamedMixinApplication(Token token) { |
| 657 Token begin = token; | 699 Token begin = token; |
| 658 Token abstractKeyword; | 700 Token abstractKeyword; |
| 659 if (optional('abstract', token)) { | 701 if (optional('abstract', token)) { |
| 660 abstractKeyword = token; | 702 abstractKeyword = token; |
| 661 token = token.next; | 703 token = token.next; |
| 662 } | 704 } |
| 663 Token classKeyword = token; | 705 Token classKeyword = token; |
| 664 var isMixinApplication = optional('=', peekAfterType(token.next)); | 706 var isMixinApplication = optional('=', peekAfterNominalType(token.next)); |
| 665 if (isMixinApplication) { | 707 if (isMixinApplication) { |
| 666 listener.beginNamedMixinApplication(begin); | 708 listener.beginNamedMixinApplication(begin); |
| 667 } else { | 709 } else { |
| 668 listener.beginClassDeclaration(begin); | 710 listener.beginClassDeclaration(begin); |
| 669 } | 711 } |
| 670 | 712 |
| 671 int modifierCount = 0; | 713 int modifierCount = 0; |
| 672 if (abstractKeyword != null) { | 714 if (abstractKeyword != null) { |
| 673 parseModifier(abstractKeyword); | 715 parseModifier(abstractKeyword); |
| 674 modifierCount++; | 716 modifierCount++; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 695 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); | 737 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); |
| 696 return expect(';', token); | 738 return expect(';', token); |
| 697 } | 739 } |
| 698 | 740 |
| 699 Token parseClass(Token begin, Token classKeyword) { | 741 Token parseClass(Token begin, Token classKeyword) { |
| 700 Token token = parseIdentifier(classKeyword.next); | 742 Token token = parseIdentifier(classKeyword.next); |
| 701 token = parseTypeVariablesOpt(token); | 743 token = parseTypeVariablesOpt(token); |
| 702 Token extendsKeyword; | 744 Token extendsKeyword; |
| 703 if (optional('extends', token)) { | 745 if (optional('extends', token)) { |
| 704 extendsKeyword = token; | 746 extendsKeyword = token; |
| 705 if (optional('with', peekAfterType(token.next))) { | 747 if (optional('with', peekAfterNominalType(token.next))) { |
| 706 token = parseMixinApplication(token.next); | 748 token = parseMixinApplication(token.next); |
| 707 } else { | 749 } else { |
| 708 token = parseType(token.next); | 750 token = parseType(token.next); |
| 709 } | 751 } |
| 710 } else { | 752 } else { |
| 711 extendsKeyword = null; | 753 extendsKeyword = null; |
| 712 listener.handleNoType(token); | 754 listener.handleNoType(token); |
| 713 } | 755 } |
| 714 Token implementsKeyword; | 756 Token implementsKeyword; |
| 715 int interfacesCount = 0; | 757 int interfacesCount = 0; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 793 value2 == stringValue || | 835 value2 == stringValue || |
| 794 value3 == stringValue || | 836 value3 == stringValue || |
| 795 value4 == stringValue; | 837 value4 == stringValue; |
| 796 } | 838 } |
| 797 | 839 |
| 798 bool notEofOrValue(String value, Token token) { | 840 bool notEofOrValue(String value, Token token) { |
| 799 return !identical(token.kind, EOF_TOKEN) && | 841 return !identical(token.kind, EOF_TOKEN) && |
| 800 !identical(value, token.stringValue); | 842 !identical(value, token.stringValue); |
| 801 } | 843 } |
| 802 | 844 |
| 845 bool isGeneralizedFunctionType(Token token) { | |
| 846 // TODO(floitsch): don't use string comparison, but the keyword-state | |
| 847 // table is currently not set up to deal with upper-case characters. | |
| 848 return (optional('<', token.next) || optional('(', token.next)) && | |
| 849 token.value == "Function"; | |
| 850 } | |
| 851 | |
| 803 Token parseType(Token token) { | 852 Token parseType(Token token) { |
| 804 Token begin = token; | 853 Token begin = token; |
| 805 if (isValidTypeReference(token)) { | 854 if (isGeneralizedFunctionType(token)) { |
| 806 token = parseIdentifier(token); | 855 // A function type without return type. |
| 807 token = parseQualifiedRestOpt(token); | 856 // Push the non-existing return type first. The loop below will |
| 857 // generate the full type. | |
| 858 listener.handleNoType(token); | |
| 808 } else { | 859 } else { |
| 809 token = listener.expectedType(token); | 860 if (isValidTypeReference(token)) { |
| 861 token = parseIdentifier(token); | |
| 862 token = parseQualifiedRestOpt(token); | |
| 863 } else { | |
| 864 token = listener.expectedType(token); | |
| 865 } | |
| 866 token = parseTypeArgumentsOpt(token); | |
| 867 listener.endType(begin, token); | |
| 810 } | 868 } |
| 811 token = parseTypeArgumentsOpt(token); | 869 |
| 812 listener.endType(begin, token); | 870 // While we see a `Function(` treat the pushed type as return type. |
| 871 // For example: `int Function() Function(int) Function(String x)`. | |
| 872 while (isGeneralizedFunctionType(token)) { | |
| 873 token = parseFunctionType(token); | |
| 874 } | |
| 813 return token; | 875 return token; |
| 814 } | 876 } |
| 815 | 877 |
| 878 /// Parses a generalized function type. | |
| 879 /// | |
| 880 /// The return type must already be pushed. | |
| 881 Token parseFunctionType(Token token) { | |
| 882 // TODO(floitsch): don't use string comparison, but the keyword-state | |
| 883 // table is currently not set up to deal with upper-case characters. | |
| 884 if (token.value != "Function") { | |
| 885 return listener.expected("Function", token); | |
| 886 } | |
| 887 Token functionToken = token; | |
| 888 token = token.next; | |
| 889 token = parseTypeVariablesOpt(token); | |
| 890 token = parseFormalParameters(token, inFunctionType: true); | |
| 891 listener.endFunctionType(functionToken, token); | |
| 892 return token; | |
| 893 } | |
| 894 | |
| 816 Token parseTypeArgumentsOpt(Token token) { | 895 Token parseTypeArgumentsOpt(Token token) { |
| 817 return parseStuff( | 896 return parseStuff( |
| 818 token, | 897 token, |
| 819 (t) => listener.beginTypeArguments(t), | 898 (t) => listener.beginTypeArguments(t), |
| 820 (t) => parseType(t), | 899 (t) => parseType(t), |
| 821 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 900 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
| 822 (t) => listener.handleNoTypeArguments(t)); | 901 (t) => listener.handleNoTypeArguments(t)); |
| 823 } | 902 } |
| 824 | 903 |
| 825 Token parseTypeVariablesOpt(Token token) { | 904 Token parseTypeVariablesOpt(Token token) { |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1139 identifiers = identifiers.prepend(token); | 1218 identifiers = identifiers.prepend(token); |
| 1140 return identifiers; | 1219 return identifiers; |
| 1141 } else if (value == '=' || value == ';' || value == ',') { | 1220 } else if (value == '=' || value == ';' || value == ',') { |
| 1142 // A field or abstract getter. | 1221 // A field or abstract getter. |
| 1143 identifiers = identifiers.prepend(token); | 1222 identifiers = identifiers.prepend(token); |
| 1144 return identifiers; | 1223 return identifiers; |
| 1145 } else if (isGetter) { | 1224 } else if (isGetter) { |
| 1146 hasName = true; | 1225 hasName = true; |
| 1147 } | 1226 } |
| 1148 identifiers = identifiers.prepend(token); | 1227 identifiers = identifiers.prepend(token); |
| 1149 if (isValidTypeReference(token)) { | 1228 |
| 1150 // type ... | 1229 if (!isGeneralizedFunctionType(token)) { |
| 1151 if (optional('.', token.next)) { | 1230 // Read a potential return type. |
| 1152 // type '.' ... | 1231 if (isValidTypeReference(token)) { |
| 1153 if (token.next.next.isIdentifier()) { | 1232 // type ... |
| 1154 // type '.' identifier | 1233 if (optional('.', token.next)) { |
| 1155 token = token.next.next; | 1234 // type '.' ... |
| 1235 if (token.next.next.isIdentifier()) { | |
| 1236 // type '.' identifier | |
| 1237 token = token.next.next; | |
| 1238 } | |
| 1239 } | |
| 1240 if (optional('<', token.next)) { | |
| 1241 if (token.next is BeginGroupToken) { | |
| 1242 BeginGroupToken beginGroup = token.next; | |
| 1243 if (beginGroup.endGroup == null) { | |
| 1244 listener.unmatched(beginGroup); | |
| 1245 } | |
| 1246 token = beginGroup.endGroup; | |
| 1247 } | |
| 1156 } | 1248 } |
| 1157 } | 1249 } |
| 1158 if (optional('<', token.next)) { | 1250 token = token.next; |
| 1159 if (token.next is BeginGroupToken) { | 1251 } |
| 1160 BeginGroupToken beginGroup = token.next; | 1252 while (isGeneralizedFunctionType(token)) { |
| 1253 token = token.next; | |
| 1254 if (optional('<', token)) { | |
| 1255 if (token is BeginGroupToken) { | |
| 1256 BeginGroupToken beginGroup = token; | |
| 1161 if (beginGroup.endGroup == null) { | 1257 if (beginGroup.endGroup == null) { |
| 1162 listener.unmatched(beginGroup); | 1258 listener.unmatched(beginGroup); |
| 1163 } | 1259 } |
| 1164 token = beginGroup.endGroup; | 1260 token = beginGroup.endGroup.next; |
| 1165 } | 1261 } |
| 1166 } | 1262 } |
| 1263 if (!optional('(', token)) { | |
| 1264 if (optional(';', token)) { | |
| 1265 listener.recoverableError(token, "expected '('"); | |
| 1266 } | |
| 1267 token = listener.unexpected(token); | |
| 1268 } | |
| 1269 if (token is BeginGroupToken) { | |
| 1270 BeginGroupToken beginGroup = token; | |
| 1271 if (beginGroup.endGroup == null) { | |
| 1272 listener.unmatched(beginGroup); | |
| 1273 } | |
| 1274 token = beginGroup.endGroup.next; | |
| 1275 } | |
| 1167 } | 1276 } |
| 1168 token = token.next; | |
| 1169 } | 1277 } |
| 1170 return const Link<Token>(); | 1278 return const Link<Token>(); |
| 1171 } | 1279 } |
| 1172 | 1280 |
| 1173 Token parseVariableInitializerOpt(Token token) { | 1281 Token parseVariableInitializerOpt(Token token) { |
| 1174 if (optional('=', token)) { | 1282 if (optional('=', token)) { |
| 1175 Token assignment = token; | 1283 Token assignment = token; |
| 1176 listener.beginInitializer(token); | 1284 listener.beginInitializer(token); |
| 1177 token = parseExpression(token.next); | 1285 token = parseExpression(token.next); |
| 1178 listener.endInitializer(assignment); | 1286 listener.endInitializer(assignment); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1256 if (!isModifier(token)) break; | 1364 if (!isModifier(token)) break; |
| 1257 token = parseModifier(token); | 1365 token = parseModifier(token); |
| 1258 count++; | 1366 count++; |
| 1259 } | 1367 } |
| 1260 listener.handleModifiers(count); | 1368 listener.handleModifiers(count); |
| 1261 return token; | 1369 return token; |
| 1262 } | 1370 } |
| 1263 | 1371 |
| 1264 /** | 1372 /** |
| 1265 * Returns the first token after the type starting at [token]. | 1373 * Returns the first token after the type starting at [token]. |
| 1374 * | |
| 1266 * This method assumes that [token] is an identifier (or void). | 1375 * This method assumes that [token] is an identifier (or void). |
| 1267 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1376 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
| 1268 */ | 1377 */ |
| 1269 Token peekAfterType(Token token) { | 1378 Token peekAfterType(Token token) { |
| 1270 // We are looking at "identifier ...". | 1379 // We are looking at "identifier ...". |
| 1380 Token peek = token; | |
| 1381 if (!isGeneralizedFunctionType(token)) { | |
| 1382 peek = peekAfterNominalType(token); | |
| 1383 } | |
| 1384 | |
| 1385 // We might have just skipped over the return value of the function type. | |
| 1386 // Check again, if we are now at a function type position. | |
| 1387 while (isGeneralizedFunctionType(peek)) { | |
| 1388 peek = peekAfterFunctionType(peek); | |
| 1389 } | |
| 1390 return peek; | |
| 1391 } | |
| 1392 | |
| 1393 /** | |
| 1394 * Returns the first token after the nominal type starting at [token]. | |
| 1395 * | |
| 1396 * This method assumes that [token] is an identifier (or void). | |
| 1397 */ | |
| 1398 Token peekAfterNominalType(Token token) { | |
| 1271 Token peek = token.next; | 1399 Token peek = token.next; |
| 1272 if (identical(peek.kind, PERIOD_TOKEN)) { | 1400 if (identical(peek.kind, PERIOD_TOKEN)) { |
| 1273 if (peek.next.isIdentifier()) { | 1401 if (peek.next.isIdentifier()) { |
| 1274 // Look past a library prefix. | 1402 // Look past a library prefix. |
| 1275 peek = peek.next.next; | 1403 peek = peek.next.next; |
| 1276 } | 1404 } |
| 1277 } | 1405 } |
| 1278 // We are looking at "qualified ...". | 1406 // We are looking at "qualified ...". |
| 1279 if (identical(peek.kind, LT_TOKEN)) { | 1407 if (identical(peek.kind, LT_TOKEN)) { |
| 1280 // Possibly generic type. | 1408 // Possibly generic type. |
| 1281 // We are looking at "qualified '<'". | 1409 // We are looking at "qualified '<'". |
| 1282 BeginGroupToken beginGroupToken = peek; | 1410 BeginGroupToken beginGroupToken = peek; |
| 1283 Token gtToken = beginGroupToken.endGroup; | 1411 Token gtToken = beginGroupToken.endGroup; |
| 1284 if (gtToken != null) { | 1412 if (gtToken != null) { |
| 1285 // We are looking at "qualified '<' ... '>' ...". | 1413 // We are looking at "qualified '<' ... '>' ...". |
| 1286 return gtToken.next; | 1414 peek = gtToken.next; |
| 1287 } | 1415 } |
| 1288 } | 1416 } |
| 1289 return peek; | 1417 return peek; |
| 1290 } | 1418 } |
| 1291 | 1419 |
| 1292 /** | 1420 /** |
| 1421 * Returns the first token after the function type starting at [token]. | |
| 1422 * | |
| 1423 * The token must be at the `Function` token position. That is, the return | |
| 1424 * type must have already been skipped. | |
| 1425 * | |
| 1426 * This function only skips over one function type syntax. | |
| 1427 * If necessary, this function must be called multiple times. | |
| 1428 * | |
| 1429 * Example: | |
| 1430 * ``` | |
| 1431 * int Function() Function<T>(int) | |
| 1432 * ^ ^ | |
| 1433 * A call to this function must be at one of the `Function` tokens. | |
| 1434 * If `token` pointed to the first `Function` token, then the returned | |
| 1435 * token points to the second `Function` token. | |
| 1436 */ | |
| 1437 Token peekAfterFunctionType(Token token) { | |
| 1438 // Possible inputs are: | |
| 1439 // Function( ... ) | |
| 1440 // Function< ... >( ... ) | |
| 1441 | |
| 1442 Token peek = token.next; // Skip over the Function token. | |
| 1443 // If there is a generic argument to the function, skip over that one first. | |
| 1444 if (identical(peek.kind, LT_TOKEN)) { | |
| 1445 BeginGroupToken beginGroupToken = peek; | |
| 1446 Token closeToken = beginGroupToken.endGroup; | |
| 1447 if (closeToken != null) { | |
| 1448 peek = closeToken.next; | |
| 1449 } | |
| 1450 } | |
| 1451 | |
| 1452 // Now we just need to skip over the formals. | |
| 1453 expect('(', peek); | |
| 1454 | |
| 1455 BeginGroupToken beginGroupToken = peek; | |
| 1456 Token closeToken = beginGroupToken.endGroup; | |
| 1457 if (closeToken != null) { | |
| 1458 peek = closeToken.next; | |
| 1459 } | |
| 1460 | |
| 1461 return peek; | |
| 1462 } | |
| 1463 | |
| 1464 /** | |
| 1293 * If [token] is the start of a type, returns the token after that type. | 1465 * If [token] is the start of a type, returns the token after that type. |
| 1294 * If [token] is not the start of a type, null is returned. | 1466 * If [token] is not the start of a type, null is returned. |
| 1295 */ | 1467 */ |
| 1296 Token peekAfterIfType(Token token) { | 1468 Token peekAfterIfType(Token token) { |
| 1297 if (!optional('void', token) && !token.isIdentifier()) { | 1469 if (!optional('void', token) && !token.isIdentifier()) { |
| 1298 return null; | 1470 return null; |
| 1299 } | 1471 } |
| 1300 return peekAfterType(token); | 1472 return peekAfterType(token); |
| 1301 } | 1473 } |
| 1302 | 1474 |
| (...skipping 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2969 } | 3141 } |
| 2970 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 3142 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
| 2971 return expectSemicolon(token); | 3143 return expectSemicolon(token); |
| 2972 } | 3144 } |
| 2973 | 3145 |
| 2974 Token parseEmptyStatement(Token token) { | 3146 Token parseEmptyStatement(Token token) { |
| 2975 listener.handleEmptyStatement(token); | 3147 listener.handleEmptyStatement(token); |
| 2976 return expectSemicolon(token); | 3148 return expectSemicolon(token); |
| 2977 } | 3149 } |
| 2978 } | 3150 } |
| OLD | NEW |