| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.parser; | 5 library dart2js.parser; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../tokens/keyword.dart' show | 8 import '../tokens/keyword.dart' show |
| 9 Keyword; | 9 Keyword; |
| 10 import '../tokens/precedence.dart' show | 10 import '../tokens/precedence.dart' show |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 KeywordToken, | 32 KeywordToken, |
| 33 SymbolToken, | 33 SymbolToken, |
| 34 Token; | 34 Token; |
| 35 import '../tokens/token_constants.dart' show | 35 import '../tokens/token_constants.dart' show |
| 36 BAD_INPUT_TOKEN, | 36 BAD_INPUT_TOKEN, |
| 37 COMMA_TOKEN, | 37 COMMA_TOKEN, |
| 38 DOUBLE_TOKEN, | 38 DOUBLE_TOKEN, |
| 39 EOF_TOKEN, | 39 EOF_TOKEN, |
| 40 EQ_TOKEN, | 40 EQ_TOKEN, |
| 41 FUNCTION_TOKEN, | 41 FUNCTION_TOKEN, |
| 42 GT_TOKEN, |
| 43 GT_GT_TOKEN, |
| 42 HASH_TOKEN, | 44 HASH_TOKEN, |
| 43 HEXADECIMAL_TOKEN, | 45 HEXADECIMAL_TOKEN, |
| 44 IDENTIFIER_TOKEN, | 46 IDENTIFIER_TOKEN, |
| 45 INT_TOKEN, | 47 INT_TOKEN, |
| 46 KEYWORD_TOKEN, | 48 KEYWORD_TOKEN, |
| 47 LT_TOKEN, | 49 LT_TOKEN, |
| 48 OPEN_CURLY_BRACKET_TOKEN, | 50 OPEN_CURLY_BRACKET_TOKEN, |
| 49 OPEN_PAREN_TOKEN, | 51 OPEN_PAREN_TOKEN, |
| 50 OPEN_SQUARE_BRACKET_TOKEN, | 52 OPEN_SQUARE_BRACKET_TOKEN, |
| 51 PERIOD_TOKEN, | 53 PERIOD_TOKEN, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 * | 89 * |
| 88 * Parse methods generate events (by calling methods on [listener]) | 90 * Parse methods generate events (by calling methods on [listener]) |
| 89 * and return the next token to parse. Peek methods do not generate | 91 * and return the next token to parse. Peek methods do not generate |
| 90 * events (except for errors) and may return null. | 92 * events (except for errors) and may return null. |
| 91 * | 93 * |
| 92 * Parse methods are generally named parseGrammarProductionSuffix. The | 94 * Parse methods are generally named parseGrammarProductionSuffix. The |
| 93 * suffix can be one of "opt", or "star". "opt" means zero or one | 95 * suffix can be one of "opt", or "star". "opt" means zero or one |
| 94 * matches, "star" means zero or more matches. For example, | 96 * matches, "star" means zero or more matches. For example, |
| 95 * [parseMetadataStar] corresponds to this grammar snippet: [: | 97 * [parseMetadataStar] corresponds to this grammar snippet: [: |
| 96 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. | 98 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. |
| 99 * |
| 100 * On the extension to support generic methods: |
| 101 * |
| 102 * The syntactic conflict associated with relational expressions is resolved |
| 103 * in favor of generic invocations (for instance, with `foo(m<B, C>(3))` we |
| 104 * parse it as an invocation of `m` with type arguments `B, C` and value |
| 105 * argument `3`, not as two boolean arguments passed to `foo`. It is expected |
| 106 * that this situation is occurs rarely in practice, especially because a comma |
| 107 * or ')' will delimit the expression where we have `3` in the example, |
| 108 * which means that it won't need to be wrapped in parentheses. The work-around |
| 109 * is to add parentheses around the last relational expression (i.e., `(C>(3))` |
| 110 * in the example). |
| 111 * |
| 112 * Relative to the DEP #22 proposal, there is no support for currying |
| 113 * invocations (that is, we cannot evalate a type like `myMethod<T,S>` to |
| 114 * obtain a closure which is non-generic and which will pass the actual values |
| 115 * of `T` and `S` in the given context as type arguments). |
| 97 */ | 116 */ |
| 98 class Parser { | 117 class Parser { |
| 99 final Listener listener; | 118 final Listener listener; |
| 100 bool mayParseFunctionExpressions = true; | 119 bool mayParseFunctionExpressions = true; |
| 101 final bool enableConditionalDirectives; | 120 final bool enableConditionalDirectives; |
| 121 final bool enableGenericMethods; |
| 102 bool asyncAwaitKeywordsEnabled; | 122 bool asyncAwaitKeywordsEnabled; |
| 103 | 123 |
| 104 Parser(this.listener, | 124 Parser(this.listener, |
| 105 {this.enableConditionalDirectives: false, | 125 {this.enableConditionalDirectives: false, |
| 106 this.asyncAwaitKeywordsEnabled: false}); | 126 this.asyncAwaitKeywordsEnabled: false, |
| 127 this.enableGenericMethods: false}); |
| 107 | 128 |
| 108 Token parseUnit(Token token) { | 129 Token parseUnit(Token token) { |
| 109 listener.beginCompilationUnit(token); | 130 listener.beginCompilationUnit(token); |
| 110 int count = 0; | 131 int count = 0; |
| 111 while (!identical(token.kind, EOF_TOKEN)) { | 132 while (!identical(token.kind, EOF_TOKEN)) { |
| 112 token = parseTopLevelDeclaration(token); | 133 token = parseTopLevelDeclaration(token); |
| 113 listener.endTopLevelDeclaration(token); | 134 listener.endTopLevelDeclaration(token); |
| 114 count++; | 135 count++; |
| 115 } | 136 } |
| 116 listener.endCompilationUnit(count, token); | 137 listener.endCompilationUnit(count, token); |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 if (identical(kind, KEYWORD_TOKEN)) { | 538 if (identical(kind, KEYWORD_TOKEN)) { |
| 518 Keyword keyword = (token as KeywordToken).keyword; | 539 Keyword keyword = (token as KeywordToken).keyword; |
| 519 String value = keyword.syntax; | 540 String value = keyword.syntax; |
| 520 return keyword.isPseudo | 541 return keyword.isPseudo |
| 521 || (identical(value, 'dynamic')) | 542 || (identical(value, 'dynamic')) |
| 522 || (identical(value, 'void')); | 543 || (identical(value, 'void')); |
| 523 } | 544 } |
| 524 return false; | 545 return false; |
| 525 } | 546 } |
| 526 | 547 |
| 548 /// 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |