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 |