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

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: Moved text from description to dartdoc 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698