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 bool isValidTypeArguments(Token token, {bool requireParenthesis: false}) { | |
549 // To avoid changing the token stream during an investigation of whether | |
550 // the parser is looking at a `typeArguments` construct, we do not replace | |
551 // one `>>` token by two `>` tokens (which would destroy a correct | |
552 // expression like `foo(a < 0, b >> 2)`). Instead, we count levels for the | |
553 // '<'/'>' brackets directly. This makes sense because the type argument | |
554 // sublanguage is so tiny: | |
555 // | |
556 // typeArguments ::= '<' typeList '>' | |
557 // typeList ::= type (',' type)* | |
558 // type ::= typeName typeArguments? | |
559 // typeName ::= qualified | |
560 // qualified ::= identifier ('.' identifier)? | |
561 // | |
562 // The point is that we check for parenthesis correctness for '<'/'>' plus | |
563 // membership of the intersection between the following regular languages: | |
564 // | |
565 // anything starting with '<' and ending with '>' | |
566 // (identifier | (identifier '.' identifier) | ',' | '<' | '>' | '>>')* | |
567 // | |
568 // Obviously, every correct `typeArguments` will pass this test. However, | |
569 // some incorrect ones will also pass, e.g., `<K,<<><>>,>`. This should be | |
570 // safe, but the real solution is of course the following: | |
571 // | |
572 // TODO(eernst): Prove that if a token sequence is accepted by this test, | |
573 // but it is not a correct `typeArguments` then it is a syntax error rather | |
574 // than a correct continuation of the program that does not contain a | |
575 // `typeArguments` construct at this point. | |
576 // If that property does not hold then we will reject some correct programs. | |
577 if (optional('<', token)) { | |
Johnni Winther
2016/02/29 10:18:45
Negate this to avoid the else branch:
if (!option
eernst
2016/03/09 16:28:13
Done.
| |
578 int angleBracketLevel = 1; | |
579 token = token.next; | |
580 while (!identical(token.kind, EOF_TOKEN) && angleBracketLevel > 0) { | |
581 // Invariant: `angleBracketLevel` is #'<' - #'>' from initial token | |
582 // to `token`, both included, where #'x' is the number of tokens with | |
583 // `stringValue` 'x'; in this computation, we consider the one-element | |
584 // token sequence '>>' equivalent to the two element sequence '>', '>'. | |
585 final int kind = token.kind; | |
586 switch (kind) { | |
587 case IDENTIFIER_TOKEN: | |
588 if (optional('.', token.next)) { | |
589 token = token.next.next; | |
590 if (token.kind != IDENTIFIER_TOKEN) return false; | |
591 } | |
592 break; | |
593 case COMMA_TOKEN: break; | |
594 case LT_TOKEN: angleBracketLevel++; break; | |
595 case GT_TOKEN: angleBracketLevel--; break; | |
596 case GT_GT_TOKEN: angleBracketLevel -= 2; break; | |
597 default: return false; | |
598 } | |
599 token = token.next; | |
600 } | |
601 if (angleBracketLevel != 0) return false; | |
602 return requireParenthesis | |
603 ? token.kind == OPEN_PAREN_TOKEN | |
604 : true; | |
605 } else { | |
606 return false; | |
607 } | |
608 } | |
609 | |
527 Token parseQualified(Token token) { | 610 Token parseQualified(Token token) { |
528 token = parseIdentifier(token); | 611 token = parseIdentifier(token); |
529 while (optional('.', token)) { | 612 while (optional('.', token)) { |
530 token = parseQualifiedRest(token); | 613 token = parseQualifiedRest(token); |
531 } | 614 } |
532 return token; | 615 return token; |
533 } | 616 } |
534 | 617 |
535 Token parseQualifiedRestOpt(Token token) { | 618 Token parseQualifiedRestOpt(Token token) { |
536 if (optional('.', token)) { | 619 if (optional('.', token)) { |
537 return parseQualifiedRest(token); | 620 return parseQualifiedRest(token); |
538 } else { | 621 } else { |
539 return token; | 622 return token; |
540 } | 623 } |
541 } | 624 } |
542 | 625 |
626 Token parseAndIgnoreQualifiedRestOpt(Token token) { | |
627 if (optional('.', token)) { | |
628 return parseAndIgnoreQualifiedRest(token); | |
629 } else { | |
630 return token; | |
631 } | |
632 } | |
633 | |
543 Token parseQualifiedRest(Token token) { | 634 Token parseQualifiedRest(Token token) { |
544 assert(optional('.', token)); | 635 assert(optional('.', token)); |
545 Token period = token; | 636 Token period = token; |
546 token = parseIdentifier(token.next); | 637 token = parseIdentifier(token.next); |
547 listener.handleQualified(period); | 638 listener.handleQualified(period); |
548 return token; | 639 return token; |
549 } | 640 } |
550 | 641 |
642 Token parseAndIgnoreQualifiedRest(Token token) { | |
643 assert(optional('.', token)); | |
644 token = parseAndIgnoreIdentifier(token.next); | |
645 return token; | |
646 } | |
647 | |
551 Token skipBlock(Token token) { | 648 Token skipBlock(Token token) { |
552 if (!optional('{', token)) { | 649 if (!optional('{', token)) { |
553 return listener.expectedBlockToSkip(token); | 650 return listener.expectedBlockToSkip(token); |
554 } | 651 } |
555 BeginGroupToken beginGroupToken = token; | 652 BeginGroupToken beginGroupToken = token; |
556 Token endGroup = beginGroupToken.endGroup; | 653 Token endGroup = beginGroupToken.endGroup; |
557 if (endGroup == null) { | 654 if (endGroup == null) { |
558 return listener.unmatched(beginGroupToken); | 655 return listener.unmatched(beginGroupToken); |
559 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { | 656 } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) { |
560 return listener.unmatched(beginGroupToken); | 657 return listener.unmatched(beginGroupToken); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
672 } | 769 } |
673 | 770 |
674 Token parseIdentifier(Token token) { | 771 Token parseIdentifier(Token token) { |
675 if (!token.isIdentifier()) { | 772 if (!token.isIdentifier()) { |
676 token = listener.expectedIdentifier(token); | 773 token = listener.expectedIdentifier(token); |
677 } | 774 } |
678 listener.handleIdentifier(token); | 775 listener.handleIdentifier(token); |
679 return token.next; | 776 return token.next; |
680 } | 777 } |
681 | 778 |
779 Token parseAndIgnoreIdentifier(Token token) { | |
780 if (!token.isIdentifier()) { | |
781 token = listener.expectedIdentifier(token); | |
782 } | |
783 return token.next; | |
784 } | |
785 | |
682 Token expect(String string, Token token) { | 786 Token expect(String string, Token token) { |
683 if (!identical(string, token.stringValue)) { | 787 if (!identical(string, token.stringValue)) { |
684 return listener.expected(string, token); | 788 return listener.expected(string, token); |
685 } | 789 } |
686 return token.next; | 790 return token.next; |
687 } | 791 } |
688 | 792 |
689 Token parseTypeVariable(Token token) { | 793 Token parseTypeVariable(Token token) { |
690 listener.beginTypeVariable(token); | 794 listener.beginTypeVariable(token); |
691 token = parseIdentifier(token); | 795 token = parseIdentifier(token); |
692 if (optional('extends', token)) { | 796 if (optional('extends', token)) { |
693 token = parseType(token.next); | 797 token = parseType(token.next); |
694 } else { | 798 } else { |
695 listener.handleNoType(token); | 799 listener.handleNoType(token); |
696 } | 800 } |
697 listener.endTypeVariable(token); | 801 listener.endTypeVariable(token); |
698 return token; | 802 return token; |
699 } | 803 } |
700 | 804 |
805 Token parseAndIgnoreTypeParameter(Token token) { | |
806 token = parseAndIgnoreIdentifier(token); | |
807 if (optional('extends', token)) { | |
808 token = parseAndIgnoreType(token.next); | |
809 } | |
810 return token; | |
811 } | |
812 | |
701 /** | 813 /** |
702 * Returns true if the stringValue of the [token] is [value]. | 814 * Returns true if the stringValue of the [token] is [value]. |
703 */ | 815 */ |
704 bool optional(String value, Token token) { | 816 bool optional(String value, Token token) { |
705 return identical(value, token.stringValue); | 817 return identical(value, token.stringValue); |
706 } | 818 } |
707 | 819 |
708 /** | 820 /** |
709 * Returns true if the stringValue of the [token] is either [value1], | 821 * Returns true if the stringValue of the [token] is either [value1], |
710 * [value2], or [value3]. | 822 * [value2], or [value3]. |
(...skipping 30 matching lines...) Expand all Loading... | |
741 token = parseIdentifier(token); | 853 token = parseIdentifier(token); |
742 token = parseQualifiedRestOpt(token); | 854 token = parseQualifiedRestOpt(token); |
743 } else { | 855 } else { |
744 token = listener.expectedType(token); | 856 token = listener.expectedType(token); |
745 } | 857 } |
746 token = parseTypeArgumentsOpt(token); | 858 token = parseTypeArgumentsOpt(token); |
747 listener.endType(begin, token); | 859 listener.endType(begin, token); |
748 return token; | 860 return token; |
749 } | 861 } |
750 | 862 |
863 Token parseAndIgnoreType(Token token) { | |
864 if (isValidTypeReference(token)) { | |
865 token = parseAndIgnoreIdentifier(token); | |
866 token = parseAndIgnoreQualifiedRestOpt(token); | |
867 } else { | |
868 token = listener.expectedType(token); | |
869 } | |
870 token = parseAndIgnoreTypeArgumentsOpt(token); | |
871 return token; | |
872 } | |
873 | |
751 Token parseTypeArgumentsOpt(Token token) { | 874 Token parseTypeArgumentsOpt(Token token) { |
752 return parseStuff(token, | 875 return parseStuff(token, |
753 (t) => listener.beginTypeArguments(t), | 876 (t) => listener.beginTypeArguments(t), |
754 (t) => parseType(t), | 877 (t) => parseType(t), |
755 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 878 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
756 (t) => listener.handleNoTypeArguments(t)); | 879 (t) => listener.handleNoTypeArguments(t)); |
757 } | 880 } |
758 | 881 |
882 Token parseAndIgnoreTypeArgumentsOpt(Token token, | |
883 {bool requireParenthesis: false}) { | |
884 if (isValidTypeArguments(token, requireParenthesis: requireParenthesis)) { | |
885 return parseStuff(token, | |
886 (t) {}, | |
887 (t) => parseAndIgnoreType(t), | |
888 (c, bt, et) {}, | |
889 (t) {}); | |
890 } else { | |
891 return token; | |
892 } | |
893 } | |
894 | |
759 Token parseTypeVariablesOpt(Token token) { | 895 Token parseTypeVariablesOpt(Token token) { |
760 return parseStuff(token, | 896 return parseStuff(token, |
761 (t) => listener.beginTypeVariables(t), | 897 (t) => listener.beginTypeVariables(t), |
762 (t) => parseTypeVariable(t), | 898 (t) => parseTypeVariable(t), |
763 (c, bt, et) => listener.endTypeVariables(c, bt, et), | 899 (c, bt, et) => listener.endTypeVariables(c, bt, et), |
764 (t) => listener.handleNoTypeVariables(t)); | 900 (t) => listener.handleNoTypeVariables(t)); |
765 } | 901 } |
766 | 902 |
903 Token parseAndIgnoreTypeParametersOpt(Token token) { | |
904 return parseStuff(token, | |
905 (t) {}, | |
906 (t) => parseAndIgnoreTypeParameter(t), | |
907 (c, bt, et) {}, | |
908 (t) {}); | |
909 } | |
910 | |
767 // TODO(ahe): Clean this up. | 911 // TODO(ahe): Clean this up. |
768 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | 912 Token parseStuff(Token token, Function beginStuff, Function stuffParser, |
769 Function endStuff, Function handleNoStuff) { | 913 Function endStuff, Function handleNoStuff) { |
770 if (optional('<', token)) { | 914 if (optional('<', token)) { |
771 Token begin = token; | 915 Token begin = token; |
772 beginStuff(begin); | 916 beginStuff(begin); |
773 int count = 0; | 917 int count = 0; |
774 do { | 918 do { |
775 token = stuffParser(token.next); | 919 token = stuffParser(token.next); |
776 ++count; | 920 ++count; |
777 } while (optional(',', token)); | 921 } while (optional(',', token)); |
778 Token next = token.next; | 922 Token next = token.next; |
779 if (identical(token.stringValue, '>>')) { | 923 if (identical(token.stringValue, '>>')) { |
780 token = new SymbolToken(GT_INFO, token.charOffset); | 924 token = new SymbolToken(GT_INFO, token.charOffset); |
781 token.next = new SymbolToken(GT_INFO, token.charOffset + 1); | 925 token.next = new SymbolToken(GT_INFO, token.charOffset + 1); |
782 token.next.next = next; | 926 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 } | 927 } |
788 endStuff(count, begin, token); | 928 endStuff(count, begin, token); |
789 return expect('>', token); | 929 return expect('>', token); |
790 } | 930 } |
791 handleNoStuff(token); | 931 handleNoStuff(token); |
792 return token; | 932 return token; |
793 } | 933 } |
794 | 934 |
795 Token parseTopLevelMember(Token token) { | 935 Token parseTopLevelMember(Token token) { |
796 Token start = token; | 936 Token start = token; |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1007 listener.handleModifiers(0); | 1147 listener.handleModifiers(0); |
1008 } | 1148 } |
1009 | 1149 |
1010 if (type == null) { | 1150 if (type == null) { |
1011 listener.handleNoType(name); | 1151 listener.handleNoType(name); |
1012 } else { | 1152 } else { |
1013 parseReturnTypeOpt(type); | 1153 parseReturnTypeOpt(type); |
1014 } | 1154 } |
1015 Token token = parseIdentifier(name); | 1155 Token token = parseIdentifier(name); |
1016 | 1156 |
1157 if (enableGenericMethods && getOrSet == null) { | |
1158 token = parseAndIgnoreTypeParametersOpt(token); | |
1159 } | |
1017 token = parseFormalParametersOpt(token); | 1160 token = parseFormalParametersOpt(token); |
1018 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1161 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1019 token = parseAsyncModifier(token); | 1162 token = parseAsyncModifier(token); |
1020 token = parseFunctionBody(token, false, externalModifier != null); | 1163 token = parseFunctionBody(token, false, externalModifier != null); |
1021 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1164 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
1022 Token endToken = token; | 1165 Token endToken = token; |
1023 token = token.next; | 1166 token = token.next; |
1024 if (token.kind == BAD_INPUT_TOKEN) { | 1167 if (token.kind == BAD_INPUT_TOKEN) { |
1025 token = listener.unexpected(token); | 1168 token = listener.unexpected(token); |
1026 } | 1169 } |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1315 } | 1458 } |
1316 } | 1459 } |
1317 | 1460 |
1318 token = afterName; | 1461 token = afterName; |
1319 bool isField; | 1462 bool isField; |
1320 while (true) { | 1463 while (true) { |
1321 // Loop to allow the listener to rewrite the token stream for | 1464 // Loop to allow the listener to rewrite the token stream for |
1322 // error handling. | 1465 // error handling. |
1323 final String value = token.stringValue; | 1466 final String value = token.stringValue; |
1324 if ((identical(value, '(')) || (identical(value, '.')) | 1467 if ((identical(value, '(')) || (identical(value, '.')) |
1325 || (identical(value, '{')) || (identical(value, '=>'))) { | 1468 || (identical(value, '{')) || (identical(value, '=>')) |
1469 || (enableGenericMethods && identical(value, '<'))) { | |
1326 isField = false; | 1470 isField = false; |
1327 break; | 1471 break; |
1328 } else if (identical(value, ';')) { | 1472 } else if (identical(value, ';')) { |
1329 if (getOrSet != null) { | 1473 if (getOrSet != null) { |
1330 // If we found a "get" keyword, this must be an abstract | 1474 // If we found a "get" keyword, this must be an abstract |
1331 // getter. | 1475 // getter. |
1332 isField = (!identical(getOrSet.stringValue, 'get')); | 1476 isField = (!identical(getOrSet.stringValue, 'get')); |
1333 // TODO(ahe): This feels like a hack. | 1477 // TODO(ahe): This feels like a hack. |
1334 } else { | 1478 } else { |
1335 isField = true; | 1479 isField = true; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1416 if (staticModifier != null) { | 1560 if (staticModifier != null) { |
1417 listener.reportError( | 1561 listener.reportError( |
1418 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, | 1562 staticModifier, MessageKind.EXTRANEOUS_MODIFIER, |
1419 {'modifier': staticModifier}); | 1563 {'modifier': staticModifier}); |
1420 } | 1564 } |
1421 } else { | 1565 } else { |
1422 token = parseIdentifier(name); | 1566 token = parseIdentifier(name); |
1423 } | 1567 } |
1424 | 1568 |
1425 token = parseQualifiedRestOpt(token); | 1569 token = parseQualifiedRestOpt(token); |
1570 if (enableGenericMethods && getOrSet == null) { | |
1571 token = parseAndIgnoreTypeParametersOpt(token); | |
1572 } | |
1426 token = parseFormalParametersOpt(token); | 1573 token = parseFormalParametersOpt(token); |
1427 token = parseInitializersOpt(token); | 1574 token = parseInitializersOpt(token); |
1428 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1575 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1429 token = parseAsyncModifier(token); | 1576 token = parseAsyncModifier(token); |
1430 if (optional('=', token)) { | 1577 if (optional('=', token)) { |
1431 token = parseRedirectingFactoryBody(token); | 1578 token = parseRedirectingFactoryBody(token); |
1432 } else { | 1579 } else { |
1433 token = parseFunctionBody( | 1580 token = parseFunctionBody( |
1434 token, false, staticModifier == null || externalModifier != null); | 1581 token, false, staticModifier == null || externalModifier != null); |
1435 } | 1582 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1502 } | 1649 } |
1503 listener.beginFunctionName(token); | 1650 listener.beginFunctionName(token); |
1504 if (optional('operator', token)) { | 1651 if (optional('operator', token)) { |
1505 token = parseOperatorName(token); | 1652 token = parseOperatorName(token); |
1506 } else { | 1653 } else { |
1507 token = parseIdentifier(token); | 1654 token = parseIdentifier(token); |
1508 } | 1655 } |
1509 } | 1656 } |
1510 token = parseQualifiedRestOpt(token); | 1657 token = parseQualifiedRestOpt(token); |
1511 listener.endFunctionName(token); | 1658 listener.endFunctionName(token); |
1659 if (enableGenericMethods && getOrSet == null) { | |
1660 token = parseAndIgnoreTypeParametersOpt(token); | |
1661 } | |
1512 token = parseFormalParametersOpt(token); | 1662 token = parseFormalParametersOpt(token); |
1513 token = parseInitializersOpt(token); | 1663 token = parseInitializersOpt(token); |
1514 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1664 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1515 token = parseAsyncModifier(token); | 1665 token = parseAsyncModifier(token); |
1516 if (optional('=', token)) { | 1666 if (optional('=', token)) { |
1517 token = parseRedirectingFactoryBody(token); | 1667 token = parseRedirectingFactoryBody(token); |
1518 } else { | 1668 } else { |
1519 token = parseFunctionBody(token, false, true); | 1669 token = parseFunctionBody(token, false, true); |
1520 } | 1670 } |
1521 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1671 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2331 } | 2481 } |
2332 | 2482 |
2333 Token parseLiteralNull(Token token) { | 2483 Token parseLiteralNull(Token token) { |
2334 listener.handleLiteralNull(token); | 2484 listener.handleLiteralNull(token); |
2335 return token.next; | 2485 return token.next; |
2336 } | 2486 } |
2337 | 2487 |
2338 Token parseSend(Token token) { | 2488 Token parseSend(Token token) { |
2339 listener.beginSend(token); | 2489 listener.beginSend(token); |
2340 token = parseIdentifier(token); | 2490 token = parseIdentifier(token); |
2491 if (enableGenericMethods) { | |
2492 token = parseAndIgnoreTypeArgumentsOpt(token, requireParenthesis: true); | |
2493 } | |
2341 token = parseArgumentsOpt(token); | 2494 token = parseArgumentsOpt(token); |
2342 listener.endSend(token); | 2495 listener.endSend(token); |
2343 return token; | 2496 return token; |
2344 } | 2497 } |
2345 | 2498 |
2346 Token parseArgumentsOpt(Token token) { | 2499 Token parseArgumentsOpt(Token token) { |
2347 if (!optional('(', token)) { | 2500 if (!optional('(', token)) { |
2348 listener.handleNoArguments(token); | 2501 listener.handleNoArguments(token); |
2349 return token; | 2502 return token; |
2350 } else { | 2503 } else { |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2782 } | 2935 } |
2783 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 2936 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
2784 return expectSemicolon(token); | 2937 return expectSemicolon(token); |
2785 } | 2938 } |
2786 | 2939 |
2787 Token parseEmptyStatement(Token token) { | 2940 Token parseEmptyStatement(Token token) { |
2788 listener.handleEmptyStatement(token); | 2941 listener.handleEmptyStatement(token); |
2789 return expectSemicolon(token); | 2942 return expectSemicolon(token); |
2790 } | 2943 } |
2791 } | 2944 } |
OLD | NEW |