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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 * | 89 * |
88 * Parse methods generate events (by calling methods on [listener]) | 90 * Parse methods generate events (by calling methods on [listener]) |
89 * and return the next token to parse. Peek methods do not generate | 91 * and return the next token to parse. Peek methods do not generate |
90 * events (except for errors) and may return null. | 92 * events (except for errors) and may return null. |
91 * | 93 * |
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? :]. |
| 99 * |
| 100 * On the extension to support generic methods: |
| 101 * |
| 102 * The syntactic conflict associated with relational expressions is resolved |
| 103 * in favor of generic invocations (for instance, with `foo(m<B, C>(3))` we |
| 104 * parse it as an invocation of `m` with type arguments `B, C` and value |
| 105 * argument `3`, not as two boolean arguments passed to `foo`. It is expected |
| 106 * that this situation is occurs rarely in practice, especially because a comma |
| 107 * or ')' will delimit the expression where we have `3` in the example, |
| 108 * which means that it won't need to be wrapped in parentheses. The work-around |
| 109 * is to add parentheses around the last relational expression (i.e., `(C>(3))` |
| 110 * in the example). |
| 111 * |
| 112 * Relative to the DEP #22 proposal, there is no support for currying |
| 113 * invocations (that is, we cannot evalate a type like `myMethod<T,S>` to |
| 114 * obtain a closure which is non-generic and which will pass the actual values |
| 115 * of `T` and `S` in the given context as type arguments). |
97 */ | 116 */ |
98 class Parser { | 117 class Parser { |
99 final Listener listener; | 118 final Listener listener; |
100 bool mayParseFunctionExpressions = true; | 119 bool mayParseFunctionExpressions = true; |
101 final bool enableConditionalDirectives; | 120 final bool enableConditionalDirectives; |
| 121 final bool enableGenericMethods; |
102 bool asyncAwaitKeywordsEnabled; | 122 bool asyncAwaitKeywordsEnabled; |
103 | 123 |
104 Parser(this.listener, | 124 Parser(this.listener, |
105 {this.enableConditionalDirectives: false, | 125 {this.enableConditionalDirectives: false, |
106 this.asyncAwaitKeywordsEnabled: false}); | 126 this.asyncAwaitKeywordsEnabled: false, |
| 127 this.enableGenericMethods: false}); |
107 | 128 |
108 Token parseUnit(Token token) { | 129 Token parseUnit(Token token) { |
109 listener.beginCompilationUnit(token); | 130 listener.beginCompilationUnit(token); |
110 int count = 0; | 131 int count = 0; |
111 while (!identical(token.kind, EOF_TOKEN)) { | 132 while (!identical(token.kind, EOF_TOKEN)) { |
112 token = parseTopLevelDeclaration(token); | 133 token = parseTopLevelDeclaration(token); |
113 listener.endTopLevelDeclaration(token); | 134 listener.endTopLevelDeclaration(token); |
114 count++; | 135 count++; |
115 } | 136 } |
116 listener.endCompilationUnit(count, token); | 137 listener.endCompilationUnit(count, token); |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 if (identical(kind, KEYWORD_TOKEN)) { | 538 if (identical(kind, KEYWORD_TOKEN)) { |
518 Keyword keyword = (token as KeywordToken).keyword; | 539 Keyword keyword = (token as KeywordToken).keyword; |
519 String value = keyword.syntax; | 540 String value = keyword.syntax; |
520 return keyword.isPseudo | 541 return keyword.isPseudo |
521 || (identical(value, 'dynamic')) | 542 || (identical(value, 'dynamic')) |
522 || (identical(value, 'void')); | 543 || (identical(value, 'void')); |
523 } | 544 } |
524 return false; | 545 return false; |
525 } | 546 } |
526 | 547 |
| 548 /// Performs lookahead to see whether the next tokens can be type arguments. |
| 549 /// |
| 550 /// This method performs a lookahead (parsing without listener events) |
| 551 /// using a near-regular language to determine a conservative approximation |
| 552 /// of whether the next tokens can be a list of actual type arguments. |
| 553 /// |
| 554 /// It is conservative in the sense that it does not return true in cases |
| 555 /// where the next tokens are a correct construct which is not an actual type |
| 556 /// argument list (because we would then reject a correct program). But it |
| 557 /// is OK to return either true or false when the next tokens are definitely |
| 558 /// not correct (because this just causes a choice of one error message where |
| 559 /// another one could also have been chosen). This allows for an imprecise |
| 560 /// parsing approach, which is the reason why we can use a near-regular |
| 561 /// language. |
| 562 /// |
| 563 /// The language which is recognized contains atoms consisting of a few |
| 564 /// tokens: |
| 565 /// |
| 566 /// (identifier | (identifier '.' identifier) | ',' | '<' | '>' | '>>')* |
| 567 /// |
| 568 /// Moreover, it is enforced that it starts with '<', ends with '>' or '>>', |
| 569 /// and that the angle brackets are balanced (where '>>' counts for two). |
| 570 /// |
| 571 /// Exceptions to this are controlled with the named arguments: If |
| 572 /// [requireParenthesis] is true then it is required that the first token |
| 573 /// after the successfully recognized type argument list is '(', and if |
| 574 /// [allowImbalance] is true then one extra case is allowed: The recognized |
| 575 /// type argument list may end in '>>' such that the final '>' creates an |
| 576 /// imbalance (that is, it would have been balanced if we had had '>' rather |
| 577 /// than '>>'). |
| 578 /// |
| 579 /// The former is used to reduce the amount of recognized constructs when |
| 580 /// it is known that the context requires the '(', and the latter is used to |
| 581 /// allow for the '>>' balance violation when the context may be another type |
| 582 /// argument list. |
| 583 // |
| 584 // Obviously, every correct `typeArguments` will pass this test. However, |
| 585 // some incorrect ones will also pass, e.g., `<K,<<><>>,>`. This should be |
| 586 // safe, but the real solution is of course the following: |
| 587 // |
| 588 // TODO(eernst): Prove that if a token sequence is accepted by this test, |
| 589 // but it is not a correct `typeArguments` then it is a syntax error rather |
| 590 // than a correct continuation of the program that does not contain a |
| 591 // `typeArguments` construct at this point. |
| 592 bool isValidTypeArguments(Token token, |
| 593 {bool requireParenthesis, bool allowImbalance}) { |
| 594 // To avoid changing the token stream during an investigation of whether |
| 595 // the parser is looking at a `typeArguments` construct, we do not replace |
| 596 // one `>>` token by two `>` tokens (which would destroy a correct |
| 597 // expression like `foo(a < 0, b >> 2)`). Instead, we count levels for the |
| 598 // '<'/'>' brackets directly. This makes sense because the type argument |
| 599 // sublanguage is so tiny: |
| 600 // |
| 601 // typeArguments ::= '<' typeList '>' |
| 602 // typeList ::= type (',' type)* |
| 603 // type ::= typeName typeArguments? |
| 604 // typeName ::= qualified |
| 605 // qualified ::= identifier ('.' identifier)? |
| 606 // |
| 607 // Clearly, any correct `typeArguments` construct will belong to the |
| 608 // following regular language: |
| 609 // |
| 610 // (identifier | (identifier '.' identifier) | ',' | '<' | '>' | '>>')* |
| 611 // |
| 612 // So we check for that, and also for the context free language that just |
| 613 // requires '<'/'>' to be balanced, and the first/last token to be '<' |
| 614 // and '>' or '>>', respectively. The two named arguments are used to |
| 615 // adjust the language slightly for context as described. |
| 616 if (!optional('<', token)) return false; |
| 617 int angleBracketLevel = 1; |
| 618 token = token.next; |
| 619 while (!identical(token.kind, EOF_TOKEN) && angleBracketLevel > 0) { |
| 620 // Invariant: `angleBracketLevel` is #'<' - #'>' from initial token |
| 621 // to `token`, both included, where #'x' is the number of tokens with |
| 622 // `stringValue` 'x'; in this computation, we consider the one-element |
| 623 // token sequence '>>' equivalent to the two element sequence '>', '>'. |
| 624 final int kind = token.kind; |
| 625 switch (kind) { |
| 626 case IDENTIFIER_TOKEN: |
| 627 if (optional('.', token.next)) { |
| 628 token = token.next.next; |
| 629 if (token.kind != IDENTIFIER_TOKEN) return false; |
| 630 } |
| 631 break; |
| 632 case COMMA_TOKEN: break; |
| 633 case LT_TOKEN: angleBracketLevel++; break; |
| 634 case GT_TOKEN: angleBracketLevel--; break; |
| 635 case GT_GT_TOKEN: angleBracketLevel -= 2; break; |
| 636 default: return false; |
| 637 } |
| 638 token = token.next; |
| 639 } |
| 640 if ((allowImbalance && angleBracketLevel > 0) || |
| 641 (!allowImbalance && angleBracketLevel != 0)) { |
| 642 return false; |
| 643 } |
| 644 return requireParenthesis |
| 645 ? token.kind == OPEN_PAREN_TOKEN |
| 646 : true; |
| 647 } |
| 648 |
527 Token parseQualified(Token token) { | 649 Token parseQualified(Token token) { |
528 token = parseIdentifier(token); | 650 token = parseIdentifier(token); |
529 while (optional('.', token)) { | 651 while (optional('.', token)) { |
530 token = parseQualifiedRest(token); | 652 token = parseQualifiedRest(token); |
531 } | 653 } |
532 return token; | 654 return token; |
533 } | 655 } |
534 | 656 |
535 Token parseQualifiedRestOpt(Token token) { | 657 Token parseQualifiedRestOpt(Token token) { |
536 if (optional('.', token)) { | 658 if (optional('.', token)) { |
537 return parseQualifiedRest(token); | 659 return parseQualifiedRest(token); |
538 } else { | 660 } else { |
539 return token; | 661 return token; |
540 } | 662 } |
541 } | 663 } |
542 | 664 |
| 665 Token parseAndIgnoreQualifiedRestOpt(Token token) { |
| 666 if (optional('.', token)) { |
| 667 return parseAndIgnoreQualifiedRest(token); |
| 668 } else { |
| 669 return token; |
| 670 } |
| 671 } |
| 672 |
543 Token parseQualifiedRest(Token token) { | 673 Token parseQualifiedRest(Token token) { |
544 assert(optional('.', token)); | 674 assert(optional('.', token)); |
545 Token period = token; | 675 Token period = token; |
546 token = parseIdentifier(token.next); | 676 token = parseIdentifier(token.next); |
547 listener.handleQualified(period); | 677 listener.handleQualified(period); |
548 return token; | 678 return token; |
549 } | 679 } |
550 | 680 |
| 681 Token parseAndIgnoreQualifiedRest(Token token) { |
| 682 assert(optional('.', token)); |
| 683 token = parseAndIgnoreIdentifier(token.next); |
| 684 return token; |
| 685 } |
| 686 |
551 Token skipBlock(Token token) { | 687 Token skipBlock(Token token) { |
552 if (!optional('{', token)) { | 688 if (!optional('{', token)) { |
553 return listener.expectedBlockToSkip(token); | 689 return listener.expectedBlockToSkip(token); |
554 } | 690 } |
555 BeginGroupToken beginGroupToken = token; | 691 BeginGroupToken beginGroupToken = token; |
556 Token endGroup = beginGroupToken.endGroup; | 692 Token endGroup = beginGroupToken.endGroup; |
557 if (endGroup == null) { | 693 if (endGroup == null) { |
558 return listener.unmatched(beginGroupToken); | 694 return listener.unmatched(beginGroupToken); |
559 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { | 695 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { |
560 return listener.unmatched(beginGroupToken); | 696 return listener.unmatched(beginGroupToken); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 } | 808 } |
673 | 809 |
674 Token parseIdentifier(Token token) { | 810 Token parseIdentifier(Token token) { |
675 if (!token.isIdentifier()) { | 811 if (!token.isIdentifier()) { |
676 token = listener.expectedIdentifier(token); | 812 token = listener.expectedIdentifier(token); |
677 } | 813 } |
678 listener.handleIdentifier(token); | 814 listener.handleIdentifier(token); |
679 return token.next; | 815 return token.next; |
680 } | 816 } |
681 | 817 |
| 818 Token parseAndIgnoreIdentifier(Token token) { |
| 819 if (!token.isIdentifier()) { |
| 820 token = listener.expectedIdentifier(token); |
| 821 } |
| 822 return token.next; |
| 823 } |
| 824 |
682 Token expect(String string, Token token) { | 825 Token expect(String string, Token token) { |
683 if (!identical(string, token.stringValue)) { | 826 if (!identical(string, token.stringValue)) { |
684 return listener.expected(string, token); | 827 return listener.expected(string, token); |
685 } | 828 } |
686 return token.next; | 829 return token.next; |
687 } | 830 } |
688 | 831 |
689 Token parseTypeVariable(Token token) { | 832 Token parseTypeVariable(Token token) { |
690 listener.beginTypeVariable(token); | 833 listener.beginTypeVariable(token); |
691 token = parseIdentifier(token); | 834 token = parseIdentifier(token); |
692 if (optional('extends', token)) { | 835 if (optional('extends', token)) { |
693 token = parseType(token.next); | 836 token = parseType(token.next); |
694 } else { | 837 } else { |
695 listener.handleNoType(token); | 838 listener.handleNoType(token); |
696 } | 839 } |
697 listener.endTypeVariable(token); | 840 listener.endTypeVariable(token); |
698 return token; | 841 return token; |
699 } | 842 } |
700 | 843 |
| 844 Token parseAndIgnoreTypeParameter(Token token) { |
| 845 token = parseAndIgnoreIdentifier(token); |
| 846 if (optional('extends', token)) { |
| 847 token = parseAndIgnoreType(token.next); |
| 848 } |
| 849 return token; |
| 850 } |
| 851 |
701 /** | 852 /** |
702 * Returns true if the stringValue of the [token] is [value]. | 853 * Returns true if the stringValue of the [token] is [value]. |
703 */ | 854 */ |
704 bool optional(String value, Token token) { | 855 bool optional(String value, Token token) { |
705 return identical(value, token.stringValue); | 856 return identical(value, token.stringValue); |
706 } | 857 } |
707 | 858 |
708 /** | 859 /** |
709 * Returns true if the stringValue of the [token] is either [value1], | 860 * Returns true if the stringValue of the [token] is either [value1], |
710 * [value2], or [value3]. | 861 * [value2], or [value3]. |
(...skipping 30 matching lines...) Expand all Loading... |
741 token = parseIdentifier(token); | 892 token = parseIdentifier(token); |
742 token = parseQualifiedRestOpt(token); | 893 token = parseQualifiedRestOpt(token); |
743 } else { | 894 } else { |
744 token = listener.expectedType(token); | 895 token = listener.expectedType(token); |
745 } | 896 } |
746 token = parseTypeArgumentsOpt(token); | 897 token = parseTypeArgumentsOpt(token); |
747 listener.endType(begin, token); | 898 listener.endType(begin, token); |
748 return token; | 899 return token; |
749 } | 900 } |
750 | 901 |
| 902 Token parseAndIgnoreType(Token token) { |
| 903 if (isValidTypeReference(token)) { |
| 904 token = parseAndIgnoreIdentifier(token); |
| 905 token = parseAndIgnoreQualifiedRestOpt(token); |
| 906 } else { |
| 907 token = listener.expectedType(token); |
| 908 } |
| 909 token = parseAndIgnoreTypeArgumentsOpt(token, |
| 910 requireParenthesis: false, allowImbalance: true); |
| 911 return token; |
| 912 } |
| 913 |
751 Token parseTypeArgumentsOpt(Token token) { | 914 Token parseTypeArgumentsOpt(Token token) { |
752 return parseStuff(token, | 915 return parseStuff(token, |
753 (t) => listener.beginTypeArguments(t), | 916 (t) => listener.beginTypeArguments(t), |
754 (t) => parseType(t), | 917 (t) => parseType(t), |
755 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 918 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
756 (t) => listener.handleNoTypeArguments(t)); | 919 (t) => listener.handleNoTypeArguments(t)); |
757 } | 920 } |
758 | 921 |
| 922 Token parseAndIgnoreTypeArgumentsOpt(Token token, |
| 923 {bool requireParenthesis, bool allowImbalance}) { |
| 924 if (isValidTypeArguments( |
| 925 token, |
| 926 requireParenthesis: requireParenthesis, |
| 927 allowImbalance: allowImbalance)) { |
| 928 return parseStuff(token, |
| 929 (t) {}, |
| 930 (t) => parseAndIgnoreType(t), |
| 931 (c, bt, et) {}, |
| 932 (t) {}); |
| 933 } else { |
| 934 return token; |
| 935 } |
| 936 } |
| 937 |
759 Token parseTypeVariablesOpt(Token token) { | 938 Token parseTypeVariablesOpt(Token token) { |
760 return parseStuff(token, | 939 return parseStuff(token, |
761 (t) => listener.beginTypeVariables(t), | 940 (t) => listener.beginTypeVariables(t), |
762 (t) => parseTypeVariable(t), | 941 (t) => parseTypeVariable(t), |
763 (c, bt, et) => listener.endTypeVariables(c, bt, et), | 942 (c, bt, et) => listener.endTypeVariables(c, bt, et), |
764 (t) => listener.handleNoTypeVariables(t)); | 943 (t) => listener.handleNoTypeVariables(t)); |
765 } | 944 } |
766 | 945 |
| 946 Token parseAndIgnoreTypeParametersOpt(Token token) { |
| 947 return parseStuff(token, |
| 948 (t) {}, |
| 949 (t) => parseAndIgnoreTypeParameter(t), |
| 950 (c, bt, et) {}, |
| 951 (t) {}); |
| 952 } |
| 953 |
767 // TODO(ahe): Clean this up. | 954 // TODO(ahe): Clean this up. |
768 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | 955 Token parseStuff(Token token, Function beginStuff, Function stuffParser, |
769 Function endStuff, Function handleNoStuff) { | 956 Function endStuff, Function handleNoStuff) { |
770 if (optional('<', token)) { | 957 if (optional('<', token)) { |
771 Token begin = token; | 958 Token begin = token; |
772 beginStuff(begin); | 959 beginStuff(begin); |
773 int count = 0; | 960 int count = 0; |
774 do { | 961 do { |
775 token = stuffParser(token.next); | 962 token = stuffParser(token.next); |
776 ++count; | 963 ++count; |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 listener.handleModifiers(0); | 1190 listener.handleModifiers(0); |
1004 } | 1191 } |
1005 | 1192 |
1006 if (type == null) { | 1193 if (type == null) { |
1007 listener.handleNoType(name); | 1194 listener.handleNoType(name); |
1008 } else { | 1195 } else { |
1009 parseReturnTypeOpt(type); | 1196 parseReturnTypeOpt(type); |
1010 } | 1197 } |
1011 Token token = parseIdentifier(name); | 1198 Token token = parseIdentifier(name); |
1012 | 1199 |
| 1200 if (enableGenericMethods && getOrSet == null) { |
| 1201 token = parseAndIgnoreTypeParametersOpt(token); |
| 1202 } |
1013 token = parseFormalParametersOpt(token); | 1203 token = parseFormalParametersOpt(token); |
1014 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1204 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1015 token = parseAsyncModifier(token); | 1205 token = parseAsyncModifier(token); |
1016 token = parseFunctionBody(token, false, externalModifier != null); | 1206 token = parseFunctionBody(token, false, externalModifier != null); |
1017 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1207 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
1018 Token endToken = token; | 1208 Token endToken = token; |
1019 token = token.next; | 1209 token = token.next; |
1020 if (token.kind == BAD_INPUT_TOKEN) { | 1210 if (token.kind == BAD_INPUT_TOKEN) { |
1021 token = listener.unexpected(token); | 1211 token = listener.unexpected(token); |
1022 } | 1212 } |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1311 } | 1501 } |
1312 } | 1502 } |
1313 | 1503 |
1314 token = afterName; | 1504 token = afterName; |
1315 bool isField; | 1505 bool isField; |
1316 while (true) { | 1506 while (true) { |
1317 // Loop to allow the listener to rewrite the token stream for | 1507 // Loop to allow the listener to rewrite the token stream for |
1318 // error handling. | 1508 // error handling. |
1319 final String value = token.stringValue; | 1509 final String value = token.stringValue; |
1320 if ((identical(value, '(')) || (identical(value, '.')) | 1510 if ((identical(value, '(')) || (identical(value, '.')) |
1321 || (identical(value, '{')) || (identical(value, '=>'))) { | 1511 || (identical(value, '{')) || (identical(value, '=>')) |
| 1512 || (enableGenericMethods && identical(value, '<'))) { |
1322 isField = false; | 1513 isField = false; |
1323 break; | 1514 break; |
1324 } else if (identical(value, ';')) { | 1515 } else if (identical(value, ';')) { |
1325 if (getOrSet != null) { | 1516 if (getOrSet != null) { |
1326 // If we found a "get" keyword, this must be an abstract | 1517 // If we found a "get" keyword, this must be an abstract |
1327 // getter. | 1518 // getter. |
1328 isField = (!identical(getOrSet.stringValue, 'get')); | 1519 isField = (!identical(getOrSet.stringValue, 'get')); |
1329 // TODO(ahe): This feels like a hack. | 1520 // TODO(ahe): This feels like a hack. |
1330 } else { | 1521 } else { |
1331 isField = true; | 1522 isField = true; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1412 if (staticModifier != null) { | 1603 if (staticModifier != null) { |
1413 listener.reportError( | 1604 listener.reportError( |
1414 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, | 1605 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, |
1415 {'modifier': staticModifier}); | 1606 {'modifier': staticModifier}); |
1416 } | 1607 } |
1417 } else { | 1608 } else { |
1418 token = parseIdentifier(name); | 1609 token = parseIdentifier(name); |
1419 } | 1610 } |
1420 | 1611 |
1421 token = parseQualifiedRestOpt(token); | 1612 token = parseQualifiedRestOpt(token); |
| 1613 if (enableGenericMethods && getOrSet == null) { |
| 1614 token = parseAndIgnoreTypeParametersOpt(token); |
| 1615 } |
1422 token = parseFormalParametersOpt(token); | 1616 token = parseFormalParametersOpt(token); |
1423 token = parseInitializersOpt(token); | 1617 token = parseInitializersOpt(token); |
1424 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1618 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1425 token = parseAsyncModifier(token); | 1619 token = parseAsyncModifier(token); |
1426 if (optional('=', token)) { | 1620 if (optional('=', token)) { |
1427 token = parseRedirectingFactoryBody(token); | 1621 token = parseRedirectingFactoryBody(token); |
1428 } else { | 1622 } else { |
1429 token = parseFunctionBody( | 1623 token = parseFunctionBody( |
1430 token, false, staticModifier == null || externalModifier != null); | 1624 token, false, staticModifier == null || externalModifier != null); |
1431 } | 1625 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1498 } | 1692 } |
1499 listener.beginFunctionName(token); | 1693 listener.beginFunctionName(token); |
1500 if (optional('operator', token)) { | 1694 if (optional('operator', token)) { |
1501 token = parseOperatorName(token); | 1695 token = parseOperatorName(token); |
1502 } else { | 1696 } else { |
1503 token = parseIdentifier(token); | 1697 token = parseIdentifier(token); |
1504 } | 1698 } |
1505 } | 1699 } |
1506 token = parseQualifiedRestOpt(token); | 1700 token = parseQualifiedRestOpt(token); |
1507 listener.endFunctionName(token); | 1701 listener.endFunctionName(token); |
| 1702 if (enableGenericMethods && getOrSet == null) { |
| 1703 token = parseAndIgnoreTypeParametersOpt(token); |
| 1704 } |
1508 token = parseFormalParametersOpt(token); | 1705 token = parseFormalParametersOpt(token); |
1509 token = parseInitializersOpt(token); | 1706 token = parseInitializersOpt(token); |
1510 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1707 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1511 token = parseAsyncModifier(token); | 1708 token = parseAsyncModifier(token); |
1512 if (optional('=', token)) { | 1709 if (optional('=', token)) { |
1513 token = parseRedirectingFactoryBody(token); | 1710 token = parseRedirectingFactoryBody(token); |
1514 } else { | 1711 } else { |
1515 token = parseFunctionBody(token, false, true); | 1712 token = parseFunctionBody(token, false, true); |
1516 } | 1713 } |
1517 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1714 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2327 } | 2524 } |
2328 | 2525 |
2329 Token parseLiteralNull(Token token) { | 2526 Token parseLiteralNull(Token token) { |
2330 listener.handleLiteralNull(token); | 2527 listener.handleLiteralNull(token); |
2331 return token.next; | 2528 return token.next; |
2332 } | 2529 } |
2333 | 2530 |
2334 Token parseSend(Token token) { | 2531 Token parseSend(Token token) { |
2335 listener.beginSend(token); | 2532 listener.beginSend(token); |
2336 token = parseIdentifier(token); | 2533 token = parseIdentifier(token); |
| 2534 if (enableGenericMethods) { |
| 2535 token = parseAndIgnoreTypeArgumentsOpt(token, |
| 2536 requireParenthesis: true, allowImbalance: false); |
| 2537 } |
2337 token = parseArgumentsOpt(token); | 2538 token = parseArgumentsOpt(token); |
2338 listener.endSend(token); | 2539 listener.endSend(token); |
2339 return token; | 2540 return token; |
2340 } | 2541 } |
2341 | 2542 |
2342 Token parseArgumentsOpt(Token token) { | 2543 Token parseArgumentsOpt(Token token) { |
2343 if (!optional('(', token)) { | 2544 if (!optional('(', token)) { |
2344 listener.handleNoArguments(token); | 2545 listener.handleNoArguments(token); |
2345 return token; | 2546 return token; |
2346 } else { | 2547 } else { |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2778 } | 2979 } |
2779 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 2980 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
2780 return expectSemicolon(token); | 2981 return expectSemicolon(token); |
2781 } | 2982 } |
2782 | 2983 |
2783 Token parseEmptyStatement(Token token) { | 2984 Token parseEmptyStatement(Token token) { |
2784 listener.handleEmptyStatement(token); | 2985 listener.handleEmptyStatement(token); |
2785 return expectSemicolon(token); | 2986 return expectSemicolon(token); |
2786 } | 2987 } |
2787 } | 2988 } |
OLD | NEW |