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 | 8 import '../tokens/keyword.dart' show |
| 9 Keyword; | 9 Keyword; |
| 10 import '../tokens/precedence.dart' show | 10 import '../tokens/precedence.dart' show |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 KeywordToken, | 32 KeywordToken, |
| 33 SymbolToken, | 33 SymbolToken, |
| 34 Token; | 34 Token; |
| 35 import '../tokens/token_constants.dart' show | 35 import '../tokens/token_constants.dart' show |
| 36 BAD_INPUT_TOKEN, | 36 BAD_INPUT_TOKEN, |
| 37 COMMA_TOKEN, | 37 COMMA_TOKEN, |
| 38 DOUBLE_TOKEN, | 38 DOUBLE_TOKEN, |
| 39 EOF_TOKEN, | 39 EOF_TOKEN, |
| 40 EQ_TOKEN, | 40 EQ_TOKEN, |
| 41 FUNCTION_TOKEN, | 41 FUNCTION_TOKEN, |
| 42 GT_TOKEN, | |
| 43 GT_GT_TOKEN, | |
| 42 HASH_TOKEN, | 44 HASH_TOKEN, |
| 43 HEXADECIMAL_TOKEN, | 45 HEXADECIMAL_TOKEN, |
| 44 IDENTIFIER_TOKEN, | 46 IDENTIFIER_TOKEN, |
| 45 INT_TOKEN, | 47 INT_TOKEN, |
| 46 KEYWORD_TOKEN, | 48 KEYWORD_TOKEN, |
| 47 LT_TOKEN, | 49 LT_TOKEN, |
| 48 OPEN_CURLY_BRACKET_TOKEN, | 50 OPEN_CURLY_BRACKET_TOKEN, |
| 49 OPEN_PAREN_TOKEN, | 51 OPEN_PAREN_TOKEN, |
| 50 OPEN_SQUARE_BRACKET_TOKEN, | 52 OPEN_SQUARE_BRACKET_TOKEN, |
| 51 PERIOD_TOKEN, | 53 PERIOD_TOKEN, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 * Parse methods are generally named parseGrammarProductionSuffix. The | 94 * Parse methods are generally named parseGrammarProductionSuffix. The |
| 93 * suffix can be one of "opt", or "star". "opt" means zero or one | 95 * suffix can be one of "opt", or "star". "opt" means zero or one |
| 94 * matches, "star" means zero or more matches. For example, | 96 * matches, "star" means zero or more matches. For example, |
| 95 * [parseMetadataStar] corresponds to this grammar snippet: [: | 97 * [parseMetadataStar] corresponds to this grammar snippet: [: |
| 96 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. | 98 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. |
| 97 */ | 99 */ |
| 98 class Parser { | 100 class Parser { |
| 99 final Listener listener; | 101 final Listener listener; |
| 100 bool mayParseFunctionExpressions = true; | 102 bool mayParseFunctionExpressions = true; |
| 101 final bool enableConditionalDirectives; | 103 final bool enableConditionalDirectives; |
| 104 final bool enableGenericMethods; | |
| 102 bool asyncAwaitKeywordsEnabled; | 105 bool asyncAwaitKeywordsEnabled; |
| 103 | 106 |
| 104 Parser(this.listener, | 107 Parser(this.listener, |
| 105 {this.enableConditionalDirectives: false, | 108 {this.enableConditionalDirectives: false, |
| 106 this.asyncAwaitKeywordsEnabled: false}); | 109 this.asyncAwaitKeywordsEnabled: false, |
| 110 this.enableGenericMethods: false}); | |
| 107 | 111 |
| 108 Token parseUnit(Token token) { | 112 Token parseUnit(Token token) { |
| 109 listener.beginCompilationUnit(token); | 113 listener.beginCompilationUnit(token); |
| 110 int count = 0; | 114 int count = 0; |
| 111 while (!identical(token.kind, EOF_TOKEN)) { | 115 while (!identical(token.kind, EOF_TOKEN)) { |
| 112 token = parseTopLevelDeclaration(token); | 116 token = parseTopLevelDeclaration(token); |
| 113 listener.endTopLevelDeclaration(token); | 117 listener.endTopLevelDeclaration(token); |
| 114 count++; | 118 count++; |
| 115 } | 119 } |
| 116 listener.endCompilationUnit(count, token); | 120 listener.endCompilationUnit(count, token); |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 if (identical(kind, KEYWORD_TOKEN)) { | 521 if (identical(kind, KEYWORD_TOKEN)) { |
| 518 Keyword keyword = (token as KeywordToken).keyword; | 522 Keyword keyword = (token as KeywordToken).keyword; |
| 519 String value = keyword.syntax; | 523 String value = keyword.syntax; |
| 520 return keyword.isPseudo | 524 return keyword.isPseudo |
| 521 || (identical(value, 'dynamic')) | 525 || (identical(value, 'dynamic')) |
| 522 || (identical(value, 'void')); | 526 || (identical(value, 'void')); |
| 523 } | 527 } |
| 524 return false; | 528 return false; |
| 525 } | 529 } |
| 526 | 530 |
| 531 bool isValidTypeArguments(Token token, {bool requireParenthesis: false}) { | |
| 532 // To avoid changing the token stream during an investigation of whether | |
| 533 // the parser is looking at a `typeArguments` construct, we do not replace | |
| 534 // one `>>` token by two `>` tokens (which would destroy a correct | |
| 535 // expression like `foo(a < 0, b >> 2)`). Instead, we count levels for the | |
| 536 // '<'/'>' brackets directly. This makes sense because the type argument | |
| 537 // sublanguage is so tiny: | |
|
ahe
2016/02/23 08:05:27
The scanner should already have computed this for
eernst
2016/02/23 12:40:45
Ah, yes, I hadn't looked at that.
| |
| 538 // | |
| 539 // typeArguments ::= '<' typeList '>' | |
| 540 // typeList ::= type (',' type)* | |
| 541 // type ::= typeName typeArguments? | |
| 542 // typeName ::= qualified | |
| 543 // qualified ::= identifier ('.' identifier)? | |
| 544 // | |
| 545 // The point is that we check for parenthesis correctness for '<'/'>' plus | |
| 546 // membership of the intersection between the following regular languages: | |
| 547 // | |
| 548 // anything starting with '<' and ending with '>' | |
| 549 // (identifier | (identifier '.' identifier) | ',' | '<' | '>' | '>>')* | |
| 550 // | |
| 551 // Obviously, every correct `typeArguments` will pass this test. However, | |
| 552 // some incorrect ones will also pass, e.g., `<K,<<><>>,>`. This should be | |
| 553 // safe, but the real solution is of course the following: | |
| 554 // | |
| 555 // TODO(eernst): Prove that if a token sequence is accepted by this test, | |
| 556 // but it is not a correct `typeArguments` then it is a syntax error rather | |
| 557 // than a correct continuation of the program that does not contain a | |
| 558 // `typeArguments` construct at this point. | |
| 559 // If that property does not hold then we will reject some correct programs. | |
| 560 if (optional('<', token)) { | |
| 561 int angleBracketLevel = 1; | |
| 562 token = token.next; | |
| 563 while (!identical(token.kind, EOF_TOKEN) && angleBracketLevel > 0) { | |
| 564 // Invariant: `angleBracketLevel` is #'<' - #'>' from initial token | |
|
ahe
2016/02/23 08:05:27
What does #'<' mean?
eernst
2016/02/23 12:40:45
The number of '<' tokens. Added an explanation to
| |
| 565 // to `token`, both included, and considering ['>>'] as ['>', '>']. | |
|
ahe
2016/02/23 08:05:27
I don't think ['>>'] is a valid reference.
eernst
2016/02/23 12:40:45
Ah, of course not. It is intended to be the sequen
| |
| 566 final int kind = token.kind; | |
| 567 switch (kind) { | |
| 568 case IDENTIFIER_TOKEN: | |
| 569 if (optional('.', token.next)) { | |
| 570 token = token.next.next; | |
| 571 if (token.kind != IDENTIFIER_TOKEN) return false; | |
| 572 } | |
| 573 break; | |
| 574 case COMMA_TOKEN: break; | |
|
floitsch
2016/02/22 12:45:20
couldn't you treat the "comma" the same way as the
eernst
2016/02/22 18:02:51
Not immediately: The comma separates complex const
| |
| 575 case LT_TOKEN: angleBracketLevel++; break; | |
| 576 case GT_TOKEN: angleBracketLevel--; break; | |
| 577 case GT_GT_TOKEN: angleBracketLevel -= 2; break; | |
| 578 default: return false; | |
| 579 } | |
| 580 token = token.next; | |
| 581 } | |
| 582 if (angleBracketLevel != 0) return false; | |
| 583 return requireParenthesis | |
| 584 ? token.kind == OPEN_PAREN_TOKEN | |
| 585 : true; | |
| 586 } else { | |
| 587 return false; | |
| 588 } | |
| 589 } | |
| 590 | |
| 527 Token parseQualified(Token token) { | 591 Token parseQualified(Token token) { |
| 528 token = parseIdentifier(token); | 592 token = parseIdentifier(token); |
| 529 while (optional('.', token)) { | 593 while (optional('.', token)) { |
| 530 token = parseQualifiedRest(token); | 594 token = parseQualifiedRest(token); |
| 531 } | 595 } |
| 532 return token; | 596 return token; |
| 533 } | 597 } |
| 534 | 598 |
| 535 Token parseQualifiedRestOpt(Token token) { | 599 Token parseQualifiedRestOpt(Token token) { |
| 536 if (optional('.', token)) { | 600 if (optional('.', token)) { |
| 537 return parseQualifiedRest(token); | 601 return parseQualifiedRest(token); |
| 538 } else { | 602 } else { |
| 539 return token; | 603 return token; |
| 540 } | 604 } |
| 541 } | 605 } |
| 542 | 606 |
| 607 Token parseAndIgnoreQualifiedRestOpt(Token token) { | |
| 608 if (optional('.', token)) { | |
| 609 return parseAndIgnoreQualifiedRest(token); | |
| 610 } else { | |
| 611 return token; | |
| 612 } | |
| 613 } | |
| 614 | |
| 543 Token parseQualifiedRest(Token token) { | 615 Token parseQualifiedRest(Token token) { |
| 544 assert(optional('.', token)); | 616 assert(optional('.', token)); |
| 545 Token period = token; | 617 Token period = token; |
| 546 token = parseIdentifier(token.next); | 618 token = parseIdentifier(token.next); |
| 547 listener.handleQualified(period); | 619 listener.handleQualified(period); |
| 548 return token; | 620 return token; |
| 549 } | 621 } |
| 550 | 622 |
| 623 Token parseAndIgnoreQualifiedRest(Token token) { | |
| 624 assert(optional('.', token)); | |
| 625 token = parseAndIgnoreIdentifier(token.next); | |
| 626 return token; | |
| 627 } | |
| 628 | |
| 551 Token skipBlock(Token token) { | 629 Token skipBlock(Token token) { |
| 552 if (!optional('{', token)) { | 630 if (!optional('{', token)) { |
| 553 return listener.expectedBlockToSkip(token); | 631 return listener.expectedBlockToSkip(token); |
| 554 } | 632 } |
| 555 BeginGroupToken beginGroupToken = token; | 633 BeginGroupToken beginGroupToken = token; |
| 556 Token endGroup = beginGroupToken.endGroup; | 634 Token endGroup = beginGroupToken.endGroup; |
| 557 if (endGroup == null) { | 635 if (endGroup == null) { |
| 558 return listener.unmatched(beginGroupToken); | 636 return listener.unmatched(beginGroupToken); |
| 559 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { | 637 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { |
| 560 return listener.unmatched(beginGroupToken); | 638 return listener.unmatched(beginGroupToken); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 } | 750 } |
| 673 | 751 |
| 674 Token parseIdentifier(Token token) { | 752 Token parseIdentifier(Token token) { |
| 675 if (!token.isIdentifier()) { | 753 if (!token.isIdentifier()) { |
| 676 token = listener.expectedIdentifier(token); | 754 token = listener.expectedIdentifier(token); |
| 677 } | 755 } |
| 678 listener.handleIdentifier(token); | 756 listener.handleIdentifier(token); |
| 679 return token.next; | 757 return token.next; |
| 680 } | 758 } |
| 681 | 759 |
| 760 Token parseAndIgnoreIdentifier(Token token) { | |
| 761 if (!token.isIdentifier()) { | |
| 762 token = listener.expectedIdentifier(token); | |
| 763 } | |
| 764 return token.next; | |
| 765 } | |
| 766 | |
| 682 Token expect(String string, Token token) { | 767 Token expect(String string, Token token) { |
| 683 if (!identical(string, token.stringValue)) { | 768 if (!identical(string, token.stringValue)) { |
| 684 return listener.expected(string, token); | 769 return listener.expected(string, token); |
| 685 } | 770 } |
| 686 return token.next; | 771 return token.next; |
| 687 } | 772 } |
| 688 | 773 |
| 689 Token parseTypeVariable(Token token) { | 774 Token parseTypeVariable(Token token) { |
| 690 listener.beginTypeVariable(token); | 775 listener.beginTypeVariable(token); |
| 691 token = parseIdentifier(token); | 776 token = parseIdentifier(token); |
| 692 if (optional('extends', token)) { | 777 if (optional('extends', token)) { |
| 693 token = parseType(token.next); | 778 token = parseType(token.next); |
| 694 } else { | 779 } else { |
| 695 listener.handleNoType(token); | 780 listener.handleNoType(token); |
| 696 } | 781 } |
| 697 listener.endTypeVariable(token); | 782 listener.endTypeVariable(token); |
| 698 return token; | 783 return token; |
| 699 } | 784 } |
| 700 | 785 |
| 786 Token parseAndIgnoreTypeParameter(Token token) { | |
| 787 token = parseAndIgnoreIdentifier(token); | |
| 788 if (optional('extends', token)) { | |
| 789 token = parseAndIgnoreType(token.next); | |
| 790 } | |
| 791 return token; | |
| 792 } | |
| 793 | |
| 701 /** | 794 /** |
| 702 * Returns true if the stringValue of the [token] is [value]. | 795 * Returns true if the stringValue of the [token] is [value]. |
| 703 */ | 796 */ |
| 704 bool optional(String value, Token token) { | 797 bool optional(String value, Token token) { |
| 705 return identical(value, token.stringValue); | 798 return identical(value, token.stringValue); |
| 706 } | 799 } |
| 707 | 800 |
| 708 /** | 801 /** |
| 709 * Returns true if the stringValue of the [token] is either [value1], | 802 * Returns true if the stringValue of the [token] is either [value1], |
| 710 * [value2], or [value3]. | 803 * [value2], or [value3]. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 741 token = parseIdentifier(token); | 834 token = parseIdentifier(token); |
| 742 token = parseQualifiedRestOpt(token); | 835 token = parseQualifiedRestOpt(token); |
| 743 } else { | 836 } else { |
| 744 token = listener.expectedType(token); | 837 token = listener.expectedType(token); |
| 745 } | 838 } |
| 746 token = parseTypeArgumentsOpt(token); | 839 token = parseTypeArgumentsOpt(token); |
| 747 listener.endType(begin, token); | 840 listener.endType(begin, token); |
| 748 return token; | 841 return token; |
| 749 } | 842 } |
| 750 | 843 |
| 844 Token parseAndIgnoreType(Token token) { | |
| 845 if (isValidTypeReference(token)) { | |
| 846 token = parseAndIgnoreIdentifier(token); | |
| 847 token = parseAndIgnoreQualifiedRestOpt(token); | |
| 848 } else { | |
| 849 token = listener.expectedType(token); | |
| 850 } | |
| 851 token = parseAndIgnoreTypeArgumentsOpt(token); | |
| 852 return token; | |
| 853 } | |
| 854 | |
| 751 Token parseTypeArgumentsOpt(Token token) { | 855 Token parseTypeArgumentsOpt(Token token) { |
| 752 return parseStuff(token, | 856 return parseStuff(token, |
| 753 (t) => listener.beginTypeArguments(t), | 857 (t) => listener.beginTypeArguments(t), |
| 754 (t) => parseType(t), | 858 (t) => parseType(t), |
| 755 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 859 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
| 756 (t) => listener.handleNoTypeArguments(t)); | 860 (t) => listener.handleNoTypeArguments(t)); |
| 757 } | 861 } |
| 758 | 862 |
| 863 Token parseAndIgnoreTypeArgumentsOpt(Token token, | |
| 864 {bool requireParenthesis: false}) { | |
| 865 if (isValidTypeArguments(token, requireParenthesis: requireParenthesis)) { | |
| 866 return parseStuff(token, | |
| 867 (t) {}, | |
| 868 (t) => parseAndIgnoreType(t), | |
| 869 (c, bt, et) {}, | |
| 870 (t) {}); | |
| 871 } else { | |
| 872 return token; | |
| 873 } | |
| 874 } | |
| 875 | |
| 759 Token parseTypeVariablesOpt(Token token) { | 876 Token parseTypeVariablesOpt(Token token) { |
| 760 return parseStuff(token, | 877 return parseStuff(token, |
| 761 (t) => listener.beginTypeVariables(t), | 878 (t) => listener.beginTypeVariables(t), |
| 762 (t) => parseTypeVariable(t), | 879 (t) => parseTypeVariable(t), |
| 763 (c, bt, et) => listener.endTypeVariables(c, bt, et), | 880 (c, bt, et) => listener.endTypeVariables(c, bt, et), |
| 764 (t) => listener.handleNoTypeVariables(t)); | 881 (t) => listener.handleNoTypeVariables(t)); |
| 765 } | 882 } |
| 766 | 883 |
| 884 Token parseAndIgnoreTypeParametersOpt(Token token) { | |
|
floitsch
2016/02/22 12:45:20
All these duplicated parseAndIgnore make me think
eernst
2016/02/22 18:02:51
Will probably have to do that in the next step any
| |
| 885 return parseStuff(token, | |
| 886 (t) {}, | |
| 887 (t) => parseAndIgnoreTypeParameter(t), | |
| 888 (c, bt, et) {}, | |
| 889 (t) {}); | |
| 890 } | |
| 891 | |
| 767 // TODO(ahe): Clean this up. | 892 // TODO(ahe): Clean this up. |
| 768 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | 893 Token parseStuff(Token token, Function beginStuff, Function stuffParser, |
| 769 Function endStuff, Function handleNoStuff) { | 894 Function endStuff, Function handleNoStuff) { |
| 770 if (optional('<', token)) { | 895 if (optional('<', token)) { |
| 771 Token begin = token; | 896 Token begin = token; |
| 772 beginStuff(begin); | 897 beginStuff(begin); |
| 773 int count = 0; | 898 int count = 0; |
| 774 do { | 899 do { |
| 775 token = stuffParser(token.next); | 900 token = stuffParser(token.next); |
| 776 ++count; | 901 ++count; |
| 777 } while (optional(',', token)); | 902 } while (optional(',', token)); |
| 778 Token next = token.next; | 903 Token next = token.next; |
| 779 if (identical(token.stringValue, '>>')) { | 904 if (identical(token.stringValue, '>>')) { |
| 780 token = new SymbolToken(GT_INFO, token.charOffset); | 905 token = new SymbolToken(GT_INFO, token.charOffset); |
| 781 token.next = new SymbolToken(GT_INFO, token.charOffset + 1); | 906 token.next = new SymbolToken(GT_INFO, token.charOffset + 1); |
| 782 token.next.next = next; | 907 token.next.next = next; |
| 783 } else if (identical(token.stringValue, '>>>')) { | |
| 784 token = new SymbolToken(GT_INFO, token.charOffset); | |
| 785 token.next = new SymbolToken(GT_GT_INFO, token.charOffset + 1); | |
| 786 token.next.next = next; | |
| 787 } | 908 } |
| 788 endStuff(count, begin, token); | 909 endStuff(count, begin, token); |
| 789 return expect('>', token); | 910 return expect('>', token); |
| 790 } | 911 } |
| 791 handleNoStuff(token); | 912 handleNoStuff(token); |
| 792 return token; | 913 return token; |
| 793 } | 914 } |
| 794 | 915 |
| 795 Token parseTopLevelMember(Token token) { | 916 Token parseTopLevelMember(Token token) { |
| 796 Token start = token; | 917 Token start = token; |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1007 listener.handleModifiers(0); | 1128 listener.handleModifiers(0); |
| 1008 } | 1129 } |
| 1009 | 1130 |
| 1010 if (type == null) { | 1131 if (type == null) { |
| 1011 listener.handleNoType(name); | 1132 listener.handleNoType(name); |
| 1012 } else { | 1133 } else { |
| 1013 parseReturnTypeOpt(type); | 1134 parseReturnTypeOpt(type); |
| 1014 } | 1135 } |
| 1015 Token token = parseIdentifier(name); | 1136 Token token = parseIdentifier(name); |
| 1016 | 1137 |
| 1138 if (enableGenericMethods && getOrSet == null) { | |
| 1139 token = parseAndIgnoreTypeParametersOpt(token); | |
| 1140 } | |
| 1017 token = parseFormalParametersOpt(token); | 1141 token = parseFormalParametersOpt(token); |
| 1018 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1142 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1019 token = parseAsyncModifier(token); | 1143 token = parseAsyncModifier(token); |
| 1020 token = parseFunctionBody(token, false, externalModifier != null); | 1144 token = parseFunctionBody(token, false, externalModifier != null); |
| 1021 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1145 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
| 1022 Token endToken = token; | 1146 Token endToken = token; |
| 1023 token = token.next; | 1147 token = token.next; |
| 1024 if (token.kind == BAD_INPUT_TOKEN) { | 1148 if (token.kind == BAD_INPUT_TOKEN) { |
| 1025 token = listener.unexpected(token); | 1149 token = listener.unexpected(token); |
| 1026 } | 1150 } |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1315 } | 1439 } |
| 1316 } | 1440 } |
| 1317 | 1441 |
| 1318 token = afterName; | 1442 token = afterName; |
| 1319 bool isField; | 1443 bool isField; |
| 1320 while (true) { | 1444 while (true) { |
| 1321 // Loop to allow the listener to rewrite the token stream for | 1445 // Loop to allow the listener to rewrite the token stream for |
| 1322 // error handling. | 1446 // error handling. |
| 1323 final String value = token.stringValue; | 1447 final String value = token.stringValue; |
| 1324 if ((identical(value, '(')) || (identical(value, '.')) | 1448 if ((identical(value, '(')) || (identical(value, '.')) |
| 1325 || (identical(value, '{')) || (identical(value, '=>'))) { | 1449 || (identical(value, '{')) || (identical(value, '=>')) |
| 1450 || (enableGenericMethods && identical(value, '<'))) { | |
| 1326 isField = false; | 1451 isField = false; |
| 1327 break; | 1452 break; |
| 1328 } else if (identical(value, ';')) { | 1453 } else if (identical(value, ';')) { |
| 1329 if (getOrSet != null) { | 1454 if (getOrSet != null) { |
| 1330 // If we found a "get" keyword, this must be an abstract | 1455 // If we found a "get" keyword, this must be an abstract |
| 1331 // getter. | 1456 // getter. |
| 1332 isField = (!identical(getOrSet.stringValue, 'get')); | 1457 isField = (!identical(getOrSet.stringValue, 'get')); |
| 1333 // TODO(ahe): This feels like a hack. | 1458 // TODO(ahe): This feels like a hack. |
| 1334 } else { | 1459 } else { |
| 1335 isField = true; | 1460 isField = true; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1416 if (staticModifier != null) { | 1541 if (staticModifier != null) { |
| 1417 listener.reportError( | 1542 listener.reportError( |
| 1418 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, | 1543 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, |
| 1419 {'modifier': staticModifier}); | 1544 {'modifier': staticModifier}); |
| 1420 } | 1545 } |
| 1421 } else { | 1546 } else { |
| 1422 token = parseIdentifier(name); | 1547 token = parseIdentifier(name); |
| 1423 } | 1548 } |
| 1424 | 1549 |
| 1425 token = parseQualifiedRestOpt(token); | 1550 token = parseQualifiedRestOpt(token); |
| 1551 if (enableGenericMethods && getOrSet == null) { | |
| 1552 token = parseAndIgnoreTypeParametersOpt(token); | |
| 1553 } | |
| 1426 token = parseFormalParametersOpt(token); | 1554 token = parseFormalParametersOpt(token); |
| 1427 token = parseInitializersOpt(token); | 1555 token = parseInitializersOpt(token); |
| 1428 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1556 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1429 token = parseAsyncModifier(token); | 1557 token = parseAsyncModifier(token); |
| 1430 if (optional('=', token)) { | 1558 if (optional('=', token)) { |
| 1431 token = parseRedirectingFactoryBody(token); | 1559 token = parseRedirectingFactoryBody(token); |
| 1432 } else { | 1560 } else { |
| 1433 token = parseFunctionBody( | 1561 token = parseFunctionBody( |
| 1434 token, false, staticModifier == null || externalModifier != null); | 1562 token, false, staticModifier == null || externalModifier != null); |
| 1435 } | 1563 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1502 } | 1630 } |
| 1503 listener.beginFunctionName(token); | 1631 listener.beginFunctionName(token); |
| 1504 if (optional('operator', token)) { | 1632 if (optional('operator', token)) { |
| 1505 token = parseOperatorName(token); | 1633 token = parseOperatorName(token); |
| 1506 } else { | 1634 } else { |
| 1507 token = parseIdentifier(token); | 1635 token = parseIdentifier(token); |
| 1508 } | 1636 } |
| 1509 } | 1637 } |
| 1510 token = parseQualifiedRestOpt(token); | 1638 token = parseQualifiedRestOpt(token); |
| 1511 listener.endFunctionName(token); | 1639 listener.endFunctionName(token); |
| 1640 if (enableGenericMethods && getOrSet == null) { | |
| 1641 token = parseAndIgnoreTypeParametersOpt(token); | |
| 1642 } | |
| 1512 token = parseFormalParametersOpt(token); | 1643 token = parseFormalParametersOpt(token); |
| 1513 token = parseInitializersOpt(token); | 1644 token = parseInitializersOpt(token); |
| 1514 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1645 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1515 token = parseAsyncModifier(token); | 1646 token = parseAsyncModifier(token); |
| 1516 if (optional('=', token)) { | 1647 if (optional('=', token)) { |
| 1517 token = parseRedirectingFactoryBody(token); | 1648 token = parseRedirectingFactoryBody(token); |
| 1518 } else { | 1649 } else { |
| 1519 token = parseFunctionBody(token, false, true); | 1650 token = parseFunctionBody(token, false, true); |
| 1520 } | 1651 } |
| 1521 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1652 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
| (...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2331 } | 2462 } |
| 2332 | 2463 |
| 2333 Token parseLiteralNull(Token token) { | 2464 Token parseLiteralNull(Token token) { |
| 2334 listener.handleLiteralNull(token); | 2465 listener.handleLiteralNull(token); |
| 2335 return token.next; | 2466 return token.next; |
| 2336 } | 2467 } |
| 2337 | 2468 |
| 2338 Token parseSend(Token token) { | 2469 Token parseSend(Token token) { |
| 2339 listener.beginSend(token); | 2470 listener.beginSend(token); |
| 2340 token = parseIdentifier(token); | 2471 token = parseIdentifier(token); |
| 2472 if (enableGenericMethods) { | |
| 2473 token = parseAndIgnoreTypeArgumentsOpt(token, requireParenthesis: true); | |
| 2474 } | |
| 2341 token = parseArgumentsOpt(token); | 2475 token = parseArgumentsOpt(token); |
| 2342 listener.endSend(token); | 2476 listener.endSend(token); |
| 2343 return token; | 2477 return token; |
| 2344 } | 2478 } |
| 2345 | 2479 |
| 2346 Token parseArgumentsOpt(Token token) { | 2480 Token parseArgumentsOpt(Token token) { |
| 2347 if (!optional('(', token)) { | 2481 if (!optional('(', token)) { |
| 2348 listener.handleNoArguments(token); | 2482 listener.handleNoArguments(token); |
| 2349 return token; | 2483 return token; |
| 2350 } else { | 2484 } else { |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2782 } | 2916 } |
| 2783 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 2917 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
| 2784 return expectSemicolon(token); | 2918 return expectSemicolon(token); |
| 2785 } | 2919 } |
| 2786 | 2920 |
| 2787 Token parseEmptyStatement(Token token) { | 2921 Token parseEmptyStatement(Token token) { |
| 2788 listener.handleEmptyStatement(token); | 2922 listener.handleEmptyStatement(token); |
| 2789 return expectSemicolon(token); | 2923 return expectSemicolon(token); |
| 2790 } | 2924 } |
| 2791 } | 2925 } |
| OLD | NEW |