Chromium Code Reviews| 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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |