Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Side by Side Diff: pkg/compiler/lib/src/parser/parser.dart

Issue 1723443003: First step of support for parsing and ignoring generic methods. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698