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

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

Powered by Google App Engine
This is Rietveld 408576698