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

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

Issue 2650813002: Restructure parser error handling and recovery. (Closed)
Patch Set: Address comments. Created 3 years, 11 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
« no previous file with comments | « pkg/dart_parser/lib/src/listener.dart ('k') | pkg/fasta/lib/src/kernel/body_builder.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 dart_parser.parser; 5 library dart_parser.parser;
6 6
7 import 'package:dart_scanner/src/keyword.dart' show 7 import 'package:dart_scanner/src/keyword.dart' show
8 Keyword; 8 Keyword;
9 9
10 import 'package:dart_scanner/src/precedence.dart' show 10 import 'package:dart_scanner/src/precedence.dart' show
11 ASSIGNMENT_PRECEDENCE, 11 ASSIGNMENT_PRECEDENCE,
12 AS_INFO, 12 AS_INFO,
13 CASCADE_PRECEDENCE, 13 CASCADE_PRECEDENCE,
14 EOF_INFO,
14 EQUALITY_PRECEDENCE, 15 EQUALITY_PRECEDENCE,
15 GT_INFO, 16 GT_INFO,
16 IS_INFO, 17 IS_INFO,
17 MINUS_MINUS_INFO, 18 MINUS_MINUS_INFO,
18 OPEN_PAREN_INFO, 19 OPEN_PAREN_INFO,
19 OPEN_SQUARE_BRACKET_INFO, 20 OPEN_SQUARE_BRACKET_INFO,
20 PERIOD_INFO, 21 PERIOD_INFO,
21 PLUS_PLUS_INFO, 22 PLUS_PLUS_INFO,
22 POSTFIX_PRECEDENCE, 23 POSTFIX_PRECEDENCE,
23 PrecedenceInfo, 24 PrecedenceInfo,
24 QUESTION_INFO, 25 QUESTION_INFO,
25 QUESTION_PERIOD_INFO, 26 QUESTION_PERIOD_INFO,
26 RELATIONAL_PRECEDENCE; 27 RELATIONAL_PRECEDENCE;
27 28
28 import 'package:dart_scanner/src/token.dart' show 29 import 'package:dart_scanner/src/token.dart' show
30 BadInputToken,
29 BeginGroupToken, 31 BeginGroupToken,
30 ErrorToken, 32 ErrorToken,
31 KeywordToken, 33 KeywordToken,
32 SymbolToken, 34 SymbolToken,
33 Token, 35 Token,
36 UnmatchedToken,
37 UnterminatedToken,
34 isUserDefinableOperator; 38 isUserDefinableOperator;
35 39
36 import 'package:dart_scanner/src/token_constants.dart' show 40 import 'package:dart_scanner/src/token_constants.dart' show
37 BAD_INPUT_TOKEN, 41 BAD_INPUT_TOKEN,
38 COMMA_TOKEN, 42 COMMA_TOKEN,
39 DOUBLE_TOKEN, 43 DOUBLE_TOKEN,
40 EOF_TOKEN, 44 EOF_TOKEN,
41 EQ_TOKEN, 45 EQ_TOKEN,
42 FUNCTION_TOKEN, 46 FUNCTION_TOKEN,
43 GT_TOKEN, 47 GT_TOKEN,
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 listener.handleNoFormalParameters(token); 417 listener.handleNoFormalParameters(token);
414 return token; 418 return token;
415 } 419 }
416 } 420 }
417 421
418 Token skipFormalParameters(Token token) { 422 Token skipFormalParameters(Token token) {
419 // TODO(ahe): Shouldn't this be `beginFormalParameters`? 423 // TODO(ahe): Shouldn't this be `beginFormalParameters`?
420 listener.beginOptionalFormalParameters(token); 424 listener.beginOptionalFormalParameters(token);
421 if (!optional('(', token)) { 425 if (!optional('(', token)) {
422 if (optional(';', token)) { 426 if (optional(';', token)) {
423 listener.reportError(token, ErrorKind.ExpectedOpenParens); 427 reportRecoverableError(token, ErrorKind.ExpectedOpenParens);
424 return token; 428 return token;
425 } 429 }
426 return listener.unexpected(token); 430 return reportUnrecoverableError(
431 token, ErrorKind.ExpectedButGot, {"expected": "("});
427 } 432 }
428 BeginGroupToken beginGroupToken = token; 433 BeginGroupToken beginGroupToken = token;
429 Token endToken = beginGroupToken.endGroup; 434 Token endToken = beginGroupToken.endGroup;
430 listener.endFormalParameters(0, token, endToken); 435 listener.endFormalParameters(0, token, endToken);
431 return endToken.next; 436 return endToken.next;
432 } 437 }
433 438
434 Token parseFormalParameters(Token token) { 439 Token parseFormalParameters(Token token) {
435 Token begin = token; 440 Token begin = token;
436 listener.beginFormalParameters(begin); 441 listener.beginFormalParameters(begin);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 token = parseFormalParameters(token); 495 token = parseFormalParameters(token);
491 listener.endFunctionTypedFormalParameter(token); 496 listener.endFunctionTypedFormalParameter(token);
492 } 497 }
493 String value = token.stringValue; 498 String value = token.stringValue;
494 if ((identical('=', value)) || (identical(':', value))) { 499 if ((identical('=', value)) || (identical(':', value))) {
495 // TODO(ahe): Validate that these are only used for optional parameters. 500 // TODO(ahe): Validate that these are only used for optional parameters.
496 Token equal = token; 501 Token equal = token;
497 token = parseExpression(token.next); 502 token = parseExpression(token.next);
498 listener.handleValuedFormalParameter(equal, token); 503 listener.handleValuedFormalParameter(equal, token);
499 if (type.isRequired) { 504 if (type.isRequired) {
500 listener.reportError( 505 reportRecoverableError(
501 equal, ErrorKind.RequiredParameterWithDefault); 506 equal, ErrorKind.RequiredParameterWithDefault);
502 } else if (type.isPositional && identical(':', value)) { 507 } else if (type.isPositional && identical(':', value)) {
503 listener.reportError( 508 reportRecoverableError(
504 equal, ErrorKind.PositionalParameterWithEquals); 509 equal, ErrorKind.PositionalParameterWithEquals);
505 } 510 }
506 } 511 }
507 listener.endFormalParameter(thisKeyword); 512 listener.endFormalParameter(thisKeyword);
508 return token; 513 return token;
509 } 514 }
510 515
511 Token parseOptionalFormalParameters(Token token, bool isNamed) { 516 Token parseOptionalFormalParameters(Token token, bool isNamed) {
512 Token begin = token; 517 Token begin = token;
513 listener.beginOptionalFormalParameters(begin); 518 listener.beginOptionalFormalParameters(begin);
514 assert((isNamed && optional('{', token)) || optional('[', token)); 519 assert((isNamed && optional('{', token)) || optional('[', token));
515 int parameterCount = 0; 520 int parameterCount = 0;
516 do { 521 do {
517 token = token.next; 522 token = token.next;
518 if (isNamed && optional('}', token)) { 523 if (isNamed && optional('}', token)) {
519 break; 524 break;
520 } else if (!isNamed && optional(']', token)) { 525 } else if (!isNamed && optional(']', token)) {
521 break; 526 break;
522 } 527 }
523 var type = 528 var type =
524 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; 529 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
525 token = parseFormalParameter(token, type); 530 token = parseFormalParameter(token, type);
526 ++parameterCount; 531 ++parameterCount;
527 } while (optional(',', token)); 532 } while (optional(',', token));
528 if (parameterCount == 0) { 533 if (parameterCount == 0) {
529 listener.reportError( 534 reportRecoverableError(
530 token, 535 token,
531 isNamed 536 isNamed
532 ? ErrorKind.EmptyNamedParameterList 537 ? ErrorKind.EmptyNamedParameterList
533 : ErrorKind.EmptyOptionalParameterList); 538 : ErrorKind.EmptyOptionalParameterList);
534 } 539 }
535 listener.endOptionalFormalParameters(parameterCount, begin, token); 540 listener.endOptionalFormalParameters(parameterCount, begin, token);
536 if (isNamed) { 541 if (isNamed) {
537 return expect('}', token); 542 return expect('}', token);
538 } else { 543 } else {
539 return expect(']', token); 544 return expect(']', token);
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 Token parseQualifiedRest(Token token) { 661 Token parseQualifiedRest(Token token) {
657 assert(optional('.', token)); 662 assert(optional('.', token));
658 Token period = token; 663 Token period = token;
659 token = parseIdentifier(token.next); 664 token = parseIdentifier(token.next);
660 listener.handleQualified(period); 665 listener.handleQualified(period);
661 return token; 666 return token;
662 } 667 }
663 668
664 Token skipBlock(Token token) { 669 Token skipBlock(Token token) {
665 if (!optional('{', token)) { 670 if (!optional('{', token)) {
666 return listener.expectedBlockToSkip(token); 671 return reportUnrecoverableError(token, ErrorKind.ExpectedBlockToSkip);
667 } 672 }
668 BeginGroupToken beginGroupToken = token; 673 BeginGroupToken beginGroupToken = token;
669 Token endGroup = beginGroupToken.endGroup; 674 Token endGroup = beginGroupToken.endGroup;
670 if (endGroup == null) { 675 if (endGroup == null) {
671 return listener.unmatched(beginGroupToken); 676 return reportUnrecoverableError(
677 beginGroupToken, ErrorKind.UnmatchedToken);
672 } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { 678 } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
673 return listener.unmatched(beginGroupToken); 679 return reportUnrecoverableError(
680 beginGroupToken, ErrorKind.UnmatchedToken);
674 } 681 }
675 return beginGroupToken.endGroup; 682 return beginGroupToken.endGroup;
676 } 683 }
677 684
678 Token parseEnum(Token token) { 685 Token parseEnum(Token token) {
679 listener.beginEnum(token); 686 listener.beginEnum(token);
680 Token enumKeyword = token; 687 Token enumKeyword = token;
681 token = parseIdentifier(token.next); 688 token = parseIdentifier(token.next);
682 token = expect('{', token); 689 token = expect('{', token);
683 int count = 0; 690 int count = 0;
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 listener.endClassDeclaration( 775 listener.endClassDeclaration(
769 interfacesCount, begin, extendsKeyword, implementsKeyword, token); 776 interfacesCount, begin, extendsKeyword, implementsKeyword, token);
770 return token.next; 777 return token.next;
771 } 778 }
772 779
773 Token parseStringPart(Token token) { 780 Token parseStringPart(Token token) {
774 if (identical(token.kind, STRING_TOKEN)) { 781 if (identical(token.kind, STRING_TOKEN)) {
775 listener.handleStringPart(token); 782 listener.handleStringPart(token);
776 return token.next; 783 return token.next;
777 } else { 784 } else {
778 return listener.expected('string', token); 785 return reportUnrecoverableError(token, ErrorKind.ExpectedString);
779 } 786 }
780 } 787 }
781 788
782 Token parseIdentifier(Token token) { 789 Token parseIdentifier(Token token) {
783 if (!token.isIdentifier()) { 790 if (!token.isIdentifier()) {
784 token = listener.expectedIdentifier(token); 791 token = reportUnrecoverableError(token, ErrorKind.ExpectedIdentifier);
785 } 792 }
786 listener.handleIdentifier(token); 793 listener.handleIdentifier(token);
787 return token.next; 794 return token.next;
788 } 795 }
789 796
790 Token expect(String string, Token token) { 797 Token expect(String string, Token token) {
791 if (!identical(string, token.stringValue)) { 798 if (!identical(string, token.stringValue)) {
792 return listener.expected(string, token); 799 return reportUnrecoverableError(
800 token, ErrorKind.ExpectedButGot, {"expected": string});
793 } 801 }
794 return token.next; 802 return token.next;
795 } 803 }
796 804
797 Token parseTypeVariable(Token token) { 805 Token parseTypeVariable(Token token) {
798 listener.beginTypeVariable(token); 806 listener.beginTypeVariable(token);
799 token = parseIdentifier(token); 807 token = parseIdentifier(token);
800 Token extendsOrSuper = null; 808 Token extendsOrSuper = null;
801 if (optional('extends', token) || optional('super', token)) { 809 if (optional('extends', token) || optional('super', token)) {
802 extendsOrSuper = token; 810 extendsOrSuper = token;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 return !identical(token.kind, EOF_TOKEN) && 844 return !identical(token.kind, EOF_TOKEN) &&
837 !identical(value, token.stringValue); 845 !identical(value, token.stringValue);
838 } 846 }
839 847
840 Token parseType(Token token) { 848 Token parseType(Token token) {
841 Token begin = token; 849 Token begin = token;
842 if (isValidTypeReference(token)) { 850 if (isValidTypeReference(token)) {
843 token = parseIdentifier(token); 851 token = parseIdentifier(token);
844 token = parseQualifiedRestOpt(token); 852 token = parseQualifiedRestOpt(token);
845 } else { 853 } else {
846 token = listener.expectedType(token); 854 token = reportUnrecoverableError(token, ErrorKind.ExpectedType);
847 } 855 }
848 token = parseTypeArgumentsOpt(token); 856 token = parseTypeArgumentsOpt(token);
849 listener.endType(begin, token); 857 listener.endType(begin, token);
850 return token; 858 return token;
851 } 859 }
852 860
853 Token parseTypeArgumentsOpt(Token token) { 861 Token parseTypeArgumentsOpt(Token token) {
854 return parseStuff( 862 return parseStuff(
855 token, 863 token,
856 (t) => listener.beginTypeArguments(t), 864 (t) => listener.beginTypeArguments(t),
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
891 handleNoStuff(token); 899 handleNoStuff(token);
892 return token; 900 return token;
893 } 901 }
894 902
895 Token parseTopLevelMember(Token token) { 903 Token parseTopLevelMember(Token token) {
896 Token start = token; 904 Token start = token;
897 listener.beginTopLevelMember(token); 905 listener.beginTopLevelMember(token);
898 906
899 Link<Token> identifiers = findMemberName(token); 907 Link<Token> identifiers = findMemberName(token);
900 if (identifiers.isEmpty) { 908 if (identifiers.isEmpty) {
901 return listener.expectedDeclaration(start); 909 return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
902 } 910 }
903 Token afterName = identifiers.head; 911 Token afterName = identifiers.head;
904 identifiers = identifiers.tail; 912 identifiers = identifiers.tail;
905 913
906 if (identifiers.isEmpty) { 914 if (identifiers.isEmpty) {
907 return listener.expectedDeclaration(start); 915 return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
908 } 916 }
909 Token name = identifiers.head; 917 Token name = identifiers.head;
910 identifiers = identifiers.tail; 918 identifiers = identifiers.tail;
911 Token getOrSet; 919 Token getOrSet;
912 if (!identifiers.isEmpty) { 920 if (!identifiers.isEmpty) {
913 String value = identifiers.head.stringValue; 921 String value = identifiers.head.stringValue;
914 if ((identical(value, 'get')) || (identical(value, 'set'))) { 922 if ((identical(value, 'get')) || (identical(value, 'set'))) {
915 getOrSet = identifiers.head; 923 getOrSet = identifiers.head;
916 identifiers = identifiers.tail; 924 identifiers = identifiers.tail;
917 } 925 }
(...skipping 24 matching lines...) Expand all
942 if (getOrSet != null) { 950 if (getOrSet != null) {
943 // If we found a "get" keyword, this must be an abstract 951 // If we found a "get" keyword, this must be an abstract
944 // getter. 952 // getter.
945 isField = (!identical(getOrSet.stringValue, 'get')); 953 isField = (!identical(getOrSet.stringValue, 'get'));
946 // TODO(ahe): This feels like a hack. 954 // TODO(ahe): This feels like a hack.
947 } else { 955 } else {
948 isField = true; 956 isField = true;
949 } 957 }
950 break; 958 break;
951 } else { 959 } else {
952 token = listener.unexpected(token); 960 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
953 if (identical(token.kind, EOF_TOKEN)) return token; 961 if (identical(token.kind, EOF_TOKEN)) return token;
954 } 962 }
955 } 963 }
956 var modifiers = identifiers.reverse(); 964 var modifiers = identifiers.reverse();
957 return isField 965 return isField
958 ? parseFields(start, modifiers, type, getOrSet, name, true) 966 ? parseFields(start, modifiers, type, getOrSet, name, true)
959 : parseTopLevelMethod(start, modifiers, type, getOrSet, name); 967 : parseTopLevelMethod(start, modifiers, type, getOrSet, name);
960 } 968 }
961 969
962 bool isVarFinalOrConst(Token token) { 970 bool isVarFinalOrConst(Token token) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1013 parseModifier(varFinalOrConst); 1021 parseModifier(varFinalOrConst);
1014 modifierCount++; 1022 modifierCount++;
1015 hasTypeOrModifier = true; 1023 hasTypeOrModifier = true;
1016 modifierList.remove(varFinalOrConst); 1024 modifierList.remove(varFinalOrConst);
1017 } 1025 }
1018 listener.handleModifiers(modifierCount); 1026 listener.handleModifiers(modifierCount);
1019 var kind = hasTypeOrModifier 1027 var kind = hasTypeOrModifier
1020 ? ErrorKind.ExtraneousModifier 1028 ? ErrorKind.ExtraneousModifier
1021 : ErrorKind.ExtraneousModifierReplace; 1029 : ErrorKind.ExtraneousModifierReplace;
1022 for (Token modifier in modifierList) { 1030 for (Token modifier in modifierList) {
1023 listener.reportError(modifier, kind, {'modifier': modifier}); 1031 reportRecoverableError(modifier, kind, {'modifier': modifier});
1024 } 1032 }
1025 return null; 1033 return null;
1026 } 1034 }
1027 1035
1028 /// Removes the optional `covariant` token from the modifiers, if there 1036 /// Removes the optional `covariant` token from the modifiers, if there
1029 /// is no `static` in the list, and `covariant` is the first modifier. 1037 /// is no `static` in the list, and `covariant` is the first modifier.
1030 Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) { 1038 Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) {
1031 if (modifiers.isEmpty || 1039 if (modifiers.isEmpty ||
1032 !identical(modifiers.first.stringValue, 'covariant')) { 1040 !identical(modifiers.first.stringValue, 'covariant')) {
1033 return modifiers; 1041 return modifiers;
(...skipping 20 matching lines...) Expand all
1054 bool hasModifier = false; 1062 bool hasModifier = false;
1055 if (varFinalOrConst != null) { 1063 if (varFinalOrConst != null) {
1056 hasModifier = true; 1064 hasModifier = true;
1057 isVar = optional('var', varFinalOrConst); 1065 isVar = optional('var', varFinalOrConst);
1058 } 1066 }
1059 1067
1060 if (getOrSet != null) { 1068 if (getOrSet != null) {
1061 var kind = (hasModifier || hasType) 1069 var kind = (hasModifier || hasType)
1062 ? ErrorKind.ExtraneousModifier 1070 ? ErrorKind.ExtraneousModifier
1063 : ErrorKind.ExtraneousModifierReplace; 1071 : ErrorKind.ExtraneousModifierReplace;
1064 listener.reportError(getOrSet, kind, {'modifier': getOrSet}); 1072 reportRecoverableError(getOrSet, kind, {'modifier': getOrSet});
1065 } 1073 }
1066 1074
1067 if (!hasType) { 1075 if (!hasType) {
1068 listener.handleNoType(name); 1076 listener.handleNoType(name);
1069 } else if (optional('void', type)) { 1077 } else if (optional('void', type)) {
1070 listener.handleNoType(name); 1078 listener.handleNoType(name);
1071 // TODO(ahe): This error is reported twice, second time is from 1079 // TODO(ahe): This error is reported twice, second time is from
1072 // [parseVariablesDeclarationMaybeSemicolon] via 1080 // [parseVariablesDeclarationMaybeSemicolon] via
1073 // [PartialFieldListElement.parseNode]. 1081 // [PartialFieldListElement.parseNode].
1074 listener.reportError(type, ErrorKind.InvalidVoid); 1082 reportRecoverableError(type, ErrorKind.InvalidVoid);
1075 } else { 1083 } else {
1076 parseType(type); 1084 parseType(type);
1077 if (isVar) { 1085 if (isVar) {
1078 listener.reportError(modifiers.head, ErrorKind.ExtraneousModifier, 1086 reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier,
1079 {'modifier': modifiers.head}); 1087 {'modifier': modifiers.head});
1080 } 1088 }
1081 } 1089 }
1082 1090
1083 Token token = parseIdentifier(name); 1091 Token token = parseIdentifier(name);
1084 1092
1085 int fieldCount = 1; 1093 int fieldCount = 1;
1086 token = parseFieldInitializerOpt(token); 1094 token = parseFieldInitializerOpt(token);
1087 while (optional(',', token)) { 1095 while (optional(',', token)) {
1088 token = parseIdentifier(token.next); 1096 token = parseIdentifier(token.next);
(...skipping 12 matching lines...) Expand all
1101 1109
1102 Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type, 1110 Token parseTopLevelMethod(Token start, Link<Token> modifiers, Token type,
1103 Token getOrSet, Token name) { 1111 Token getOrSet, Token name) {
1104 Token externalModifier; 1112 Token externalModifier;
1105 // TODO(johnniwinther): Move error reporting to resolution to give more 1113 // TODO(johnniwinther): Move error reporting to resolution to give more
1106 // specific error messages. 1114 // specific error messages.
1107 for (Token modifier in modifiers) { 1115 for (Token modifier in modifiers) {
1108 if (externalModifier == null && optional('external', modifier)) { 1116 if (externalModifier == null && optional('external', modifier)) {
1109 externalModifier = modifier; 1117 externalModifier = modifier;
1110 } else { 1118 } else {
1111 listener.reportError( 1119 reportRecoverableError(
1112 modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier}); 1120 modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
1113 } 1121 }
1114 } 1122 }
1115 if (externalModifier != null) { 1123 if (externalModifier != null) {
1116 parseModifier(externalModifier); 1124 parseModifier(externalModifier);
1117 listener.handleModifiers(1); 1125 listener.handleModifiers(1);
1118 } else { 1126 } else {
1119 listener.handleModifiers(0); 1127 listener.handleModifiers(0);
1120 } 1128 }
1121 1129
(...skipping 10 matching lines...) Expand all
1132 listener.handleNoTypeVariables(token); 1140 listener.handleNoTypeVariables(token);
1133 } 1141 }
1134 token = parseFormalParametersOpt(token); 1142 token = parseFormalParametersOpt(token);
1135 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; 1143 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled;
1136 token = parseAsyncModifier(token); 1144 token = parseAsyncModifier(token);
1137 token = parseFunctionBody(token, false, externalModifier != null); 1145 token = parseFunctionBody(token, false, externalModifier != null);
1138 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; 1146 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled;
1139 Token endToken = token; 1147 Token endToken = token;
1140 token = token.next; 1148 token = token.next;
1141 if (token.kind == BAD_INPUT_TOKEN) { 1149 if (token.kind == BAD_INPUT_TOKEN) {
1142 token = listener.unexpected(token); 1150 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
1143 } 1151 }
1144 listener.endTopLevelMethod(start, getOrSet, endToken); 1152 listener.endTopLevelMethod(start, getOrSet, endToken);
1145 return token; 1153 return token;
1146 } 1154 }
1147 1155
1148 /// Looks ahead to find the name of a member. Returns a link of the modifiers, 1156 /// Looks ahead to find the name of a member. Returns a link of the modifiers,
1149 /// set/get, (operator) name, and either the start of the method body or the 1157 /// set/get, (operator) name, and either the start of the method body or the
1150 /// end of the declaration. 1158 /// end of the declaration.
1151 /// 1159 ///
1152 /// Examples: 1160 /// Examples:
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1209 // type '.' ... 1217 // type '.' ...
1210 if (token.next.next.isIdentifier()) { 1218 if (token.next.next.isIdentifier()) {
1211 // type '.' identifier 1219 // type '.' identifier
1212 token = token.next.next; 1220 token = token.next.next;
1213 } 1221 }
1214 } 1222 }
1215 if (optional('<', token.next)) { 1223 if (optional('<', token.next)) {
1216 if (token.next is BeginGroupToken) { 1224 if (token.next is BeginGroupToken) {
1217 BeginGroupToken beginGroup = token.next; 1225 BeginGroupToken beginGroup = token.next;
1218 if (beginGroup.endGroup == null) { 1226 if (beginGroup.endGroup == null) {
1219 listener.unmatched(beginGroup); 1227 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken);
1220 } 1228 }
1221 token = beginGroup.endGroup; 1229 token = beginGroup.endGroup;
1222 } 1230 }
1223 } 1231 }
1224 } 1232 }
1225 token = token.next; 1233 token = token.next;
1226 } 1234 }
1227 return const Link<Token>(); 1235 return const Link<Token>();
1228 } 1236 }
1229 1237
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } while (optional(',', token)); 1280 } while (optional(',', token));
1273 mayParseFunctionExpressions = old; 1281 mayParseFunctionExpressions = old;
1274 listener.endInitializers(count, begin, token); 1282 listener.endInitializers(count, begin, token);
1275 return token; 1283 return token;
1276 } 1284 }
1277 1285
1278 Token parseLiteralStringOrRecoverExpression(Token token) { 1286 Token parseLiteralStringOrRecoverExpression(Token token) {
1279 if (identical(token.kind, STRING_TOKEN)) { 1287 if (identical(token.kind, STRING_TOKEN)) {
1280 return parseLiteralString(token); 1288 return parseLiteralString(token);
1281 } else { 1289 } else {
1282 listener.reportError(token, ErrorKind.ExpectedString); 1290 reportRecoverableError(token, ErrorKind.ExpectedString);
1283 return parseExpression(token); 1291 return parseExpression(token);
1284 } 1292 }
1285 } 1293 }
1286 1294
1287 Token expectSemicolon(Token token) { 1295 Token expectSemicolon(Token token) {
1288 return expect(';', token); 1296 return expect(';', token);
1289 } 1297 }
1290 1298
1291 bool isModifier(Token token) { 1299 bool isModifier(Token token) {
1292 final String value = token.stringValue; 1300 final String value = token.stringValue;
(...skipping 11 matching lines...) Expand all
1304 return token.next; 1312 return token.next;
1305 } 1313 }
1306 1314
1307 void parseModifierList(Link<Token> tokens) { 1315 void parseModifierList(Link<Token> tokens) {
1308 int count = 0; 1316 int count = 0;
1309 for (; !tokens.isEmpty; tokens = tokens.tail) { 1317 for (; !tokens.isEmpty; tokens = tokens.tail) {
1310 Token token = tokens.head; 1318 Token token = tokens.head;
1311 if (isModifier(token)) { 1319 if (isModifier(token)) {
1312 parseModifier(token); 1320 parseModifier(token);
1313 } else { 1321 } else {
1314 listener.unexpected(token); 1322 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
1315 // Skip the remaining modifiers. 1323 // Skip the remaining modifiers.
1316 break; 1324 break;
1317 } 1325 }
1318 count++; 1326 count++;
1319 } 1327 }
1320 listener.handleModifiers(count); 1328 listener.handleModifiers(count);
1321 } 1329 }
1322 1330
1323 Token parseModifiers(Token token) { 1331 Token parseModifiers(Token token) {
1324 int count = 0; 1332 int count = 0;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1365 */ 1373 */
1366 Token peekAfterIfType(Token token) { 1374 Token peekAfterIfType(Token token) {
1367 if (!optional('void', token) && !token.isIdentifier()) { 1375 if (!optional('void', token) && !token.isIdentifier()) {
1368 return null; 1376 return null;
1369 } 1377 }
1370 return peekAfterType(token); 1378 return peekAfterType(token);
1371 } 1379 }
1372 1380
1373 Token skipClassBody(Token token) { 1381 Token skipClassBody(Token token) {
1374 if (!optional('{', token)) { 1382 if (!optional('{', token)) {
1375 return listener.expectedClassBodyToSkip(token); 1383 return reportUnrecoverableError(token, ErrorKind.ExpectedClassBodyToSkip);
1376 } 1384 }
1377 BeginGroupToken beginGroupToken = token; 1385 BeginGroupToken beginGroupToken = token;
1378 Token endGroup = beginGroupToken.endGroup; 1386 Token endGroup = beginGroupToken.endGroup;
1379 if (endGroup == null) { 1387 if (endGroup == null) {
1380 return listener.unmatched(beginGroupToken); 1388 return reportUnrecoverableError(
1389 beginGroupToken, ErrorKind.UnmatchedToken);
1381 } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { 1390 } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
1382 return listener.unmatched(beginGroupToken); 1391 return reportUnrecoverableError(
1392 beginGroupToken, ErrorKind.UnmatchedToken);
1383 } 1393 }
1384 return endGroup; 1394 return endGroup;
1385 } 1395 }
1386 1396
1387 Token parseClassBody(Token token) { 1397 Token parseClassBody(Token token) {
1388 Token begin = token; 1398 Token begin = token;
1389 listener.beginClassBody(token); 1399 listener.beginClassBody(token);
1390 if (!optional('{', token)) { 1400 if (!optional('{', token)) {
1391 token = listener.expectedClassBody(token); 1401 token = reportUnrecoverableError(token, ErrorKind.ExpectedClassBody);
1392 } 1402 }
1393 token = token.next; 1403 token = token.next;
1394 int count = 0; 1404 int count = 0;
1395 while (notEofOrValue('}', token)) { 1405 while (notEofOrValue('}', token)) {
1396 token = parseMember(token); 1406 token = parseMember(token);
1397 ++count; 1407 ++count;
1398 } 1408 }
1399 expect('}', token); 1409 expect('}', token);
1400 listener.endClassBody(count, begin, token); 1410 listener.endClassBody(count, begin, token);
1401 return token; 1411 return token;
(...skipping 16 matching lines...) Expand all
1418 listener.beginMember(token); 1428 listener.beginMember(token);
1419 if (isFactoryDeclaration(token)) { 1429 if (isFactoryDeclaration(token)) {
1420 token = parseFactoryMethod(token); 1430 token = parseFactoryMethod(token);
1421 listener.endMember(); 1431 listener.endMember();
1422 assert(token != null); 1432 assert(token != null);
1423 return token; 1433 return token;
1424 } 1434 }
1425 1435
1426 Link<Token> identifiers = findMemberName(token); 1436 Link<Token> identifiers = findMemberName(token);
1427 if (identifiers.isEmpty) { 1437 if (identifiers.isEmpty) {
1428 return listener.expectedDeclaration(start); 1438 return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
1429 } 1439 }
1430 Token afterName = identifiers.head; 1440 Token afterName = identifiers.head;
1431 identifiers = identifiers.tail; 1441 identifiers = identifiers.tail;
1432 1442
1433 if (identifiers.isEmpty) { 1443 if (identifiers.isEmpty) {
1434 return listener.expectedDeclaration(start); 1444 return reportUnrecoverableError(start, ErrorKind.ExpectedDeclaration);
1435 } 1445 }
1436 Token name = identifiers.head; 1446 Token name = identifiers.head;
1437 identifiers = identifiers.tail; 1447 identifiers = identifiers.tail;
1438 if (!identifiers.isEmpty) { 1448 if (!identifiers.isEmpty) {
1439 if (optional('operator', identifiers.head)) { 1449 if (optional('operator', identifiers.head)) {
1440 name = identifiers.head; 1450 name = identifiers.head;
1441 identifiers = identifiers.tail; 1451 identifiers = identifiers.tail;
1442 } 1452 }
1443 } 1453 }
1444 Token getOrSet; 1454 Token getOrSet;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1476 isField = (!identical(getOrSet.stringValue, 'get')); 1486 isField = (!identical(getOrSet.stringValue, 'get'));
1477 // TODO(ahe): This feels like a hack. 1487 // TODO(ahe): This feels like a hack.
1478 } else { 1488 } else {
1479 isField = true; 1489 isField = true;
1480 } 1490 }
1481 break; 1491 break;
1482 } else if ((identical(value, '=')) || (identical(value, ','))) { 1492 } else if ((identical(value, '=')) || (identical(value, ','))) {
1483 isField = true; 1493 isField = true;
1484 break; 1494 break;
1485 } else { 1495 } else {
1486 token = listener.unexpected(token); 1496 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
1487 if (identical(token.kind, EOF_TOKEN)) { 1497 if (identical(token.kind, EOF_TOKEN)) {
1488 // TODO(ahe): This is a hack, see parseTopLevelMember. 1498 // TODO(ahe): This is a hack, see parseTopLevelMember.
1489 listener.endFields(1, start, token); 1499 listener.endFields(1, start, token);
1490 listener.endMember(); 1500 listener.endMember();
1491 return token; 1501 return token;
1492 } 1502 }
1493 } 1503 }
1494 } 1504 }
1495 1505
1496 var modifiers = identifiers.reverse(); 1506 var modifiers = identifiers.reverse();
(...skipping 11 matching lines...) Expand all
1508 Token constModifier; 1518 Token constModifier;
1509 int modifierCount = 0; 1519 int modifierCount = 0;
1510 int allowedModifierCount = 1; 1520 int allowedModifierCount = 1;
1511 // TODO(johnniwinther): Move error reporting to resolution to give more 1521 // TODO(johnniwinther): Move error reporting to resolution to give more
1512 // specific error messages. 1522 // specific error messages.
1513 for (Token modifier in modifiers) { 1523 for (Token modifier in modifiers) {
1514 if (externalModifier == null && optional('external', modifier)) { 1524 if (externalModifier == null && optional('external', modifier)) {
1515 modifierCount++; 1525 modifierCount++;
1516 externalModifier = modifier; 1526 externalModifier = modifier;
1517 if (modifierCount != allowedModifierCount) { 1527 if (modifierCount != allowedModifierCount) {
1518 listener.reportError(modifier, ErrorKind.ExtraneousModifier, 1528 reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
1519 {'modifier': modifier}); 1529 {'modifier': modifier});
1520 } 1530 }
1521 allowedModifierCount++; 1531 allowedModifierCount++;
1522 } else if (staticModifier == null && optional('static', modifier)) { 1532 } else if (staticModifier == null && optional('static', modifier)) {
1523 modifierCount++; 1533 modifierCount++;
1524 staticModifier = modifier; 1534 staticModifier = modifier;
1525 if (modifierCount != allowedModifierCount) { 1535 if (modifierCount != allowedModifierCount) {
1526 listener.reportError(modifier, ErrorKind.ExtraneousModifier, 1536 reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
1527 {'modifier': modifier}); 1537 {'modifier': modifier});
1528 } 1538 }
1529 } else if (constModifier == null && optional('const', modifier)) { 1539 } else if (constModifier == null && optional('const', modifier)) {
1530 modifierCount++; 1540 modifierCount++;
1531 constModifier = modifier; 1541 constModifier = modifier;
1532 if (modifierCount != allowedModifierCount) { 1542 if (modifierCount != allowedModifierCount) {
1533 listener.reportError(modifier, ErrorKind.ExtraneousModifier, 1543 reportRecoverableError(modifier, ErrorKind.ExtraneousModifier,
1534 {'modifier': modifier}); 1544 {'modifier': modifier});
1535 } 1545 }
1536 } else { 1546 } else {
1537 listener.reportError( 1547 reportRecoverableError(
1538 modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier}); 1548 modifier, ErrorKind.ExtraneousModifier, {'modifier': modifier});
1539 } 1549 }
1540 } 1550 }
1541 if (getOrSet != null && constModifier != null) { 1551 if (getOrSet != null && constModifier != null) {
1542 listener.reportError(constModifier, ErrorKind.ExtraneousModifier, 1552 reportRecoverableError(constModifier, ErrorKind.ExtraneousModifier,
1543 {'modifier': constModifier}); 1553 {'modifier': constModifier});
1544 } 1554 }
1545 parseModifierList(modifiers); 1555 parseModifierList(modifiers);
1546 1556
1547 if (type == null) { 1557 if (type == null) {
1548 listener.handleNoType(name); 1558 listener.handleNoType(name);
1549 } else { 1559 } else {
1550 parseReturnTypeOpt(type); 1560 parseReturnTypeOpt(type);
1551 } 1561 }
1552 Token token; 1562 Token token;
1553 if (optional('operator', name)) { 1563 if (optional('operator', name)) {
1554 token = parseOperatorName(name); 1564 token = parseOperatorName(name);
1555 if (staticModifier != null) { 1565 if (staticModifier != null) {
1556 listener.reportError(staticModifier, ErrorKind.ExtraneousModifier, 1566 reportRecoverableError(staticModifier, ErrorKind.ExtraneousModifier,
1557 {'modifier': staticModifier}); 1567 {'modifier': staticModifier});
1558 } 1568 }
1559 } else { 1569 } else {
1560 token = parseIdentifier(name); 1570 token = parseIdentifier(name);
1561 } 1571 }
1562 1572
1563 token = parseQualifiedRestOpt(token); 1573 token = parseQualifiedRestOpt(token);
1564 if (getOrSet == null) { 1574 if (getOrSet == null) {
1565 token = parseTypeVariablesOpt(token); 1575 token = parseTypeVariablesOpt(token);
1566 } else { 1576 } else {
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
1734 listener.endRedirectingFactoryBody(equals, semicolon); 1744 listener.endRedirectingFactoryBody(equals, semicolon);
1735 return token; 1745 return token;
1736 } 1746 }
1737 1747
1738 Token skipFunctionBody(Token token, bool isExpression, bool allowAbstract) { 1748 Token skipFunctionBody(Token token, bool isExpression, bool allowAbstract) {
1739 assert(!isExpression); 1749 assert(!isExpression);
1740 token = skipAsyncModifier(token); 1750 token = skipAsyncModifier(token);
1741 String value = token.stringValue; 1751 String value = token.stringValue;
1742 if (identical(value, ';')) { 1752 if (identical(value, ';')) {
1743 if (!allowAbstract) { 1753 if (!allowAbstract) {
1744 listener.reportError(token, ErrorKind.ExpectedBody); 1754 reportRecoverableError(token, ErrorKind.ExpectedBody);
1745 } 1755 }
1746 listener.handleNoFunctionBody(token); 1756 listener.handleNoFunctionBody(token);
1747 } else { 1757 } else {
1748 if (identical(value, '=>')) { 1758 if (identical(value, '=>')) {
1749 token = parseExpression(token.next); 1759 token = parseExpression(token.next);
1750 expectSemicolon(token); 1760 expectSemicolon(token);
1751 } else if (value == '=') { 1761 } else if (value == '=') {
1752 token = parseRedirectingFactoryBody(token); 1762 token = parseRedirectingFactoryBody(token);
1753 expectSemicolon(token); 1763 expectSemicolon(token);
1754 } else { 1764 } else {
1755 token = skipBlock(token); 1765 token = skipBlock(token);
1756 } 1766 }
1757 listener.handleFunctionBodySkipped(token); 1767 listener.handleFunctionBodySkipped(token);
1758 } 1768 }
1759 return token; 1769 return token;
1760 } 1770 }
1761 1771
1762 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { 1772 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
1763 if (optional(';', token)) { 1773 if (optional(';', token)) {
1764 if (!allowAbstract) { 1774 if (!allowAbstract) {
1765 listener.reportError(token, ErrorKind.ExpectedBody); 1775 reportRecoverableError(token, ErrorKind.ExpectedBody);
1766 } 1776 }
1767 listener.endFunctionBody(0, null, token); 1777 listener.endFunctionBody(0, null, token);
1768 return token; 1778 return token;
1769 } else if (optional('=>', token)) { 1779 } else if (optional('=>', token)) {
1770 Token begin = token; 1780 Token begin = token;
1771 token = parseExpression(token.next); 1781 token = parseExpression(token.next);
1772 if (!isExpression) { 1782 if (!isExpression) {
1773 expectSemicolon(token); 1783 expectSemicolon(token);
1774 listener.endReturnStatement(true, begin, token); 1784 listener.endReturnStatement(true, begin, token);
1775 } else { 1785 } else {
1776 listener.endReturnStatement(true, begin, null); 1786 listener.endReturnStatement(true, begin, null);
1777 } 1787 }
1778 return token; 1788 return token;
1779 } 1789 }
1780 Token begin = token; 1790 Token begin = token;
1781 int statementCount = 0; 1791 int statementCount = 0;
1782 if (!optional('{', token)) { 1792 if (!optional('{', token)) {
1783 return listener.expectedFunctionBody(token); 1793 return reportUnrecoverableError(token, ErrorKind.ExpectedFunctionBody);
1784 } 1794 }
1785 1795
1786 listener.beginFunctionBody(begin); 1796 listener.beginFunctionBody(begin);
1787 token = token.next; 1797 token = token.next;
1788 while (notEofOrValue('}', token)) { 1798 while (notEofOrValue('}', token)) {
1789 token = parseStatement(token); 1799 token = parseStatement(token);
1790 ++statementCount; 1800 ++statementCount;
1791 } 1801 }
1792 listener.endFunctionBody(statementCount, begin, token); 1802 listener.endFunctionBody(statementCount, begin, token);
1793 expect('}', token); 1803 expect('}', token);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1827 token = token.next; 1837 token = token.next;
1828 } 1838 }
1829 } else if (optional('sync', token)) { 1839 } else if (optional('sync', token)) {
1830 async = token; 1840 async = token;
1831 token = token.next; 1841 token = token.next;
1832 if (optional('*', token)) { 1842 if (optional('*', token)) {
1833 asyncAwaitKeywordsEnabled = true; 1843 asyncAwaitKeywordsEnabled = true;
1834 star = token; 1844 star = token;
1835 token = token.next; 1845 token = token.next;
1836 } else { 1846 } else {
1837 listener.reportError(async, ErrorKind.InvalidSyncModifier); 1847 reportRecoverableError(async, ErrorKind.InvalidSyncModifier);
1838 } 1848 }
1839 } 1849 }
1840 listener.handleAsyncModifier(async, star); 1850 listener.handleAsyncModifier(async, star);
1841 return token; 1851 return token;
1842 } 1852 }
1843 1853
1844 Token parseStatement(Token token) { 1854 Token parseStatement(Token token) {
1845 final value = token.stringValue; 1855 final value = token.stringValue;
1846 if (identical(token.kind, IDENTIFIER_TOKEN)) { 1856 if (identical(token.kind, IDENTIFIER_TOKEN)) {
1847 return parseExpressionStatementOrDeclaration(token); 1857 return parseExpressionStatementOrDeclaration(token);
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
2132 continue; 2142 continue;
2133 } 2143 }
2134 } 2144 }
2135 if (!mayParseFunctionExpressions && identical(value, '{')) { 2145 if (!mayParseFunctionExpressions && identical(value, '{')) {
2136 break; 2146 break;
2137 } 2147 }
2138 if (token is BeginGroupToken) { 2148 if (token is BeginGroupToken) {
2139 BeginGroupToken begin = token; 2149 BeginGroupToken begin = token;
2140 token = (begin.endGroup != null) ? begin.endGroup : token; 2150 token = (begin.endGroup != null) ? begin.endGroup : token;
2141 } else if (token is ErrorToken) { 2151 } else if (token is ErrorToken) {
2142 listener.reportErrorToken(token); 2152 reportErrorToken(token, false);
2143 } 2153 }
2144 token = token.next; 2154 token = token.next;
2145 } 2155 }
2146 return token; 2156 return token;
2147 } 2157 }
2148 2158
2149 Token parseExpression(Token token) { 2159 Token parseExpression(Token token) {
2150 listener.beginExpression(token); 2160 listener.beginExpression(token);
2151 return optional('throw', token) 2161 return optional('throw', token)
2152 ? parseThrowExpression(token, true) 2162 ? parseThrowExpression(token, true)
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
2202 token = parseUnaryExpression(token.next, allowCascades); 2212 token = parseUnaryExpression(token.next, allowCascades);
2203 listener.handleBinaryExpression(operator); 2213 listener.handleBinaryExpression(operator);
2204 } else if ((identical(info, OPEN_PAREN_INFO)) || 2214 } else if ((identical(info, OPEN_PAREN_INFO)) ||
2205 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { 2215 (identical(info, OPEN_SQUARE_BRACKET_INFO))) {
2206 token = parseArgumentOrIndexStar(token); 2216 token = parseArgumentOrIndexStar(token);
2207 } else if ((identical(info, PLUS_PLUS_INFO)) || 2217 } else if ((identical(info, PLUS_PLUS_INFO)) ||
2208 (identical(info, MINUS_MINUS_INFO))) { 2218 (identical(info, MINUS_MINUS_INFO))) {
2209 listener.handleUnaryPostfixAssignmentExpression(token); 2219 listener.handleUnaryPostfixAssignmentExpression(token);
2210 token = token.next; 2220 token = token.next;
2211 } else { 2221 } else {
2212 token = listener.unexpected(token); 2222 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2213 } 2223 }
2214 } else if (identical(info, IS_INFO)) { 2224 } else if (identical(info, IS_INFO)) {
2215 token = parseIsOperatorRest(token); 2225 token = parseIsOperatorRest(token);
2216 } else if (identical(info, AS_INFO)) { 2226 } else if (identical(info, AS_INFO)) {
2217 token = parseAsOperatorRest(token); 2227 token = parseAsOperatorRest(token);
2218 } else if (identical(info, QUESTION_INFO)) { 2228 } else if (identical(info, QUESTION_INFO)) {
2219 token = parseConditionalExpressionRest(token); 2229 token = parseConditionalExpressionRest(token);
2220 } else { 2230 } else {
2221 // Left associative, so we recurse at the next higher 2231 // Left associative, so we recurse at the next higher
2222 // precedence level. 2232 // precedence level.
(...skipping 19 matching lines...) Expand all
2242 listener.beginCascade(token); 2252 listener.beginCascade(token);
2243 assert(optional('..', token)); 2253 assert(optional('..', token));
2244 Token cascadeOperator = token; 2254 Token cascadeOperator = token;
2245 token = token.next; 2255 token = token.next;
2246 if (optional('[', token)) { 2256 if (optional('[', token)) {
2247 token = parseArgumentOrIndexStar(token); 2257 token = parseArgumentOrIndexStar(token);
2248 } else if (token.isIdentifier()) { 2258 } else if (token.isIdentifier()) {
2249 token = parseSend(token); 2259 token = parseSend(token);
2250 listener.handleBinaryExpression(cascadeOperator); 2260 listener.handleBinaryExpression(cascadeOperator);
2251 } else { 2261 } else {
2252 return listener.unexpected(token); 2262 return reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2253 } 2263 }
2254 Token mark; 2264 Token mark;
2255 do { 2265 do {
2256 mark = token; 2266 mark = token;
2257 if (optional('.', token)) { 2267 if (optional('.', token)) {
2258 Token period = token; 2268 Token period = token;
2259 token = parseSend(token.next); 2269 token = parseSend(token.next);
2260 listener.handleBinaryExpression(period); 2270 listener.handleBinaryExpression(period);
2261 } 2271 }
2262 token = parseArgumentOrIndexStar(token); 2272 token = parseArgumentOrIndexStar(token);
2263 } while (!identical(mark, token)); 2273 } while (!identical(mark, token));
2264 2274
2265 if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) { 2275 if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) {
2266 Token assignment = token; 2276 Token assignment = token;
2267 token = parseExpressionWithoutCascade(token.next); 2277 token = parseExpressionWithoutCascade(token.next);
2268 listener.handleAssignmentExpression(assignment); 2278 listener.handleAssignmentExpression(assignment);
2269 } 2279 }
2270 listener.endCascade(); 2280 listener.endCascade();
2271 return token; 2281 return token;
2272 } 2282 }
2273 2283
2274 Token parseUnaryExpression(Token token, bool allowCascades) { 2284 Token parseUnaryExpression(Token token, bool allowCascades) {
2275 String value = token.stringValue; 2285 String value = token.stringValue;
2276 // Prefix: 2286 // Prefix:
2277 if (asyncAwaitKeywordsEnabled && optional('await', token)) { 2287 if (asyncAwaitKeywordsEnabled && optional('await', token)) {
2278 return parseAwaitExpression(token, allowCascades); 2288 return parseAwaitExpression(token, allowCascades);
2279 } else if (identical(value, '+')) { 2289 } else if (identical(value, '+')) {
2280 // Dart no longer allows prefix-plus. 2290 // Dart no longer allows prefix-plus.
2281 listener.reportError(token, ErrorKind.UnsupportedPrefixPlus); 2291 reportRecoverableError(token, ErrorKind.UnsupportedPrefixPlus);
2282 return parseUnaryExpression(token.next, allowCascades); 2292 return parseUnaryExpression(token.next, allowCascades);
2283 } else if ((identical(value, '!')) || 2293 } else if ((identical(value, '!')) ||
2284 (identical(value, '-')) || 2294 (identical(value, '-')) ||
2285 (identical(value, '~'))) { 2295 (identical(value, '~'))) {
2286 Token operator = token; 2296 Token operator = token;
2287 // Right associative, so we recurse at the same precedence 2297 // Right associative, so we recurse at the same precedence
2288 // level. 2298 // level.
2289 token = parsePrecedenceExpression( 2299 token = parsePrecedenceExpression(
2290 token.next, POSTFIX_PRECEDENCE, allowCascades); 2300 token.next, POSTFIX_PRECEDENCE, allowCascades);
2291 listener.handleUnaryPrefixExpression(operator); 2301 listener.handleUnaryPrefixExpression(operator);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
2347 } else if (value == 'super') { 2357 } else if (value == 'super') {
2348 return parseSuperExpression(token); 2358 return parseSuperExpression(token);
2349 } else if (value == 'new') { 2359 } else if (value == 'new') {
2350 return parseNewExpression(token); 2360 return parseNewExpression(token);
2351 } else if (value == 'const') { 2361 } else if (value == 'const') {
2352 return parseConstExpression(token); 2362 return parseConstExpression(token);
2353 } else if (value == 'void') { 2363 } else if (value == 'void') {
2354 return parseFunctionExpression(token); 2364 return parseFunctionExpression(token);
2355 } else if (asyncAwaitKeywordsEnabled && 2365 } else if (asyncAwaitKeywordsEnabled &&
2356 (value == 'yield' || value == 'async')) { 2366 (value == 'yield' || value == 'async')) {
2357 return listener.expectedExpression(token); 2367 return reportUnrecoverableError(token, ErrorKind.ExpectedExpression);
2358 } else if (token.isIdentifier()) { 2368 } else if (token.isIdentifier()) {
2359 return parseSendOrFunctionLiteral(token); 2369 return parseSendOrFunctionLiteral(token);
2360 } else { 2370 } else {
2361 return listener.expectedExpression(token); 2371 return reportUnrecoverableError(token, ErrorKind.ExpectedExpression);
2362 } 2372 }
2363 } else if (kind == OPEN_PAREN_TOKEN) { 2373 } else if (kind == OPEN_PAREN_TOKEN) {
2364 return parseParenthesizedExpressionOrFunctionLiteral(token); 2374 return parseParenthesizedExpressionOrFunctionLiteral(token);
2365 } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') { 2375 } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') {
2366 listener.handleNoTypeArguments(token); 2376 listener.handleNoTypeArguments(token);
2367 return parseLiteralListSuffix(token, null); 2377 return parseLiteralListSuffix(token, null);
2368 } else if (kind == OPEN_CURLY_BRACKET_TOKEN) { 2378 } else if (kind == OPEN_CURLY_BRACKET_TOKEN) {
2369 listener.handleNoTypeArguments(token); 2379 listener.handleNoTypeArguments(token);
2370 return parseLiteralMapSuffix(token, null); 2380 return parseLiteralMapSuffix(token, null);
2371 } else if (kind == LT_TOKEN) { 2381 } else if (kind == LT_TOKEN) {
2372 return parseLiteralListOrMapOrFunction(token, null); 2382 return parseLiteralListOrMapOrFunction(token, null);
2373 } else { 2383 } else {
2374 return listener.expectedExpression(token); 2384 return reportUnrecoverableError(token, ErrorKind.ExpectedExpression);
2375 } 2385 }
2376 } 2386 }
2377 2387
2378 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { 2388 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
2379 BeginGroupToken beginGroup = token; 2389 BeginGroupToken beginGroup = token;
2380 // TODO(eernst): Check for NPE as described in issue 26252. 2390 // TODO(eernst): Check for NPE as described in issue 26252.
2381 Token nextToken = beginGroup.endGroup.next; 2391 Token nextToken = beginGroup.endGroup.next;
2382 int kind = nextToken.kind; 2392 int kind = nextToken.kind;
2383 if (mayParseFunctionExpressions && 2393 if (mayParseFunctionExpressions &&
2384 (identical(kind, FUNCTION_TOKEN) || 2394 (identical(kind, FUNCTION_TOKEN) ||
(...skipping 12 matching lines...) Expand all
2397 } 2407 }
2398 2408
2399 Token parseParenthesizedExpression(Token token) { 2409 Token parseParenthesizedExpression(Token token) {
2400 // We expect [begin] to be of type [BeginGroupToken], but we don't know for 2410 // We expect [begin] to be of type [BeginGroupToken], but we don't know for
2401 // sure until after calling expect. 2411 // sure until after calling expect.
2402 var begin = token; 2412 var begin = token;
2403 token = expect('(', token); 2413 token = expect('(', token);
2404 // [begin] is now known to have type [BeginGroupToken]. 2414 // [begin] is now known to have type [BeginGroupToken].
2405 token = parseExpression(token); 2415 token = parseExpression(token);
2406 if (!identical(begin.endGroup, token)) { 2416 if (!identical(begin.endGroup, token)) {
2407 listener.unexpected(token); 2417 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2408 token = begin.endGroup; 2418 token = begin.endGroup;
2409 } 2419 }
2410 listener.handleParenthesizedExpression(begin); 2420 listener.handleParenthesizedExpression(begin);
2411 return expect(')', token); 2421 return expect(')', token);
2412 } 2422 }
2413 2423
2414 Token parseThisExpression(Token token) { 2424 Token parseThisExpression(Token token) {
2415 listener.handleThisExpression(token); 2425 listener.handleThisExpression(token);
2416 token = token.next; 2426 token = token.next;
2417 if (optional('(', token)) { 2427 if (optional('(', token)) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
2499 Token nextToken = beginGroup.endGroup.next; 2509 Token nextToken = beginGroup.endGroup.next;
2500 int kind = nextToken.kind; 2510 int kind = nextToken.kind;
2501 if (identical(kind, FUNCTION_TOKEN) || 2511 if (identical(kind, FUNCTION_TOKEN) ||
2502 identical(kind, OPEN_CURLY_BRACKET_TOKEN) || 2512 identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
2503 (identical(kind, KEYWORD_TOKEN) && 2513 (identical(kind, KEYWORD_TOKEN) &&
2504 (nextToken.value == 'async' || nextToken.value == 'sync'))) { 2514 (nextToken.value == 'async' || nextToken.value == 'sync'))) {
2505 return parseUnnamedFunction(token); 2515 return parseUnnamedFunction(token);
2506 } 2516 }
2507 // Fall through. 2517 // Fall through.
2508 } 2518 }
2509 listener.unexpected(token); 2519 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2510 return null; 2520 return null;
2511 } 2521 }
2512 2522
2513 /// genericListLiteral | genericMapLiteral | genericFunctionLiteral. 2523 /// genericListLiteral | genericMapLiteral | genericFunctionLiteral.
2514 /// 2524 ///
2515 /// Where 2525 /// Where
2516 /// genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']' 2526 /// genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']'
2517 /// genericMapLiteral ::= 2527 /// genericMapLiteral ::=
2518 /// typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' 2528 /// typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
2519 /// genericFunctionLiteral ::= 2529 /// genericFunctionLiteral ::=
2520 /// typeParameters formalParameterList functionBody 2530 /// typeParameters formalParameterList functionBody
2521 /// Provide token for [constKeyword] if preceded by 'const', null if not. 2531 /// Provide token for [constKeyword] if preceded by 'const', null if not.
2522 Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) { 2532 Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) {
2523 assert(optional('<', token)); 2533 assert(optional('<', token));
2524 BeginGroupToken begin = token; 2534 BeginGroupToken begin = token;
2525 if (constKeyword == null && 2535 if (constKeyword == null &&
2526 begin.endGroup != null && 2536 begin.endGroup != null &&
2527 identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) { 2537 identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) {
2528 token = parseTypeVariablesOpt(token); 2538 token = parseTypeVariablesOpt(token);
2529 return parseLiteralFunctionSuffix(token); 2539 return parseLiteralFunctionSuffix(token);
2530 } else { 2540 } else {
2531 token = parseTypeArgumentsOpt(token); 2541 token = parseTypeArgumentsOpt(token);
2532 if (optional('{', token)) { 2542 if (optional('{', token)) {
2533 return parseLiteralMapSuffix(token, constKeyword); 2543 return parseLiteralMapSuffix(token, constKeyword);
2534 } else if ((optional('[', token)) || (optional('[]', token))) { 2544 } else if ((optional('[', token)) || (optional('[]', token))) {
2535 return parseLiteralListSuffix(token, constKeyword); 2545 return parseLiteralListSuffix(token, constKeyword);
2536 } 2546 }
2537 listener.unexpected(token); 2547 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2538 return null; 2548 return null;
2539 } 2549 }
2540 } 2550 }
2541 2551
2542 Token parseMapLiteralEntry(Token token) { 2552 Token parseMapLiteralEntry(Token token) {
2543 listener.beginLiteralMapEntry(token); 2553 listener.beginLiteralMapEntry(token);
2544 // Assume the listener rejects non-string keys. 2554 // Assume the listener rejects non-string keys.
2545 token = parseExpression(token); 2555 token = parseExpression(token);
2546 Token colon = token; 2556 Token colon = token;
2547 token = expect(':', token); 2557 token = expect(':', token);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2582 } 2592 }
2583 } 2593 }
2584 return false; 2594 return false;
2585 } 2595 }
2586 2596
2587 Token parseRequiredArguments(Token token) { 2597 Token parseRequiredArguments(Token token) {
2588 if (optional('(', token)) { 2598 if (optional('(', token)) {
2589 token = parseArguments(token); 2599 token = parseArguments(token);
2590 } else { 2600 } else {
2591 listener.handleNoArguments(token); 2601 listener.handleNoArguments(token);
2592 token = listener.unexpected(token); 2602 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2593 } 2603 }
2594 return token; 2604 return token;
2595 } 2605 }
2596 2606
2597 Token parseNewExpression(Token token) { 2607 Token parseNewExpression(Token token) {
2598 Token newKeyword = token; 2608 Token newKeyword = token;
2599 token = expect('new', token); 2609 token = expect('new', token);
2600 token = parseConstructorReference(token); 2610 token = parseConstructorReference(token);
2601 token = parseRequiredArguments(token); 2611 token = parseRequiredArguments(token);
2602 listener.handleNewExpression(newKeyword); 2612 listener.handleNewExpression(newKeyword);
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
2780 if (optional('!', token.next)) { 2790 if (optional('!', token.next)) {
2781 token = token.next; 2791 token = token.next;
2782 not = token; 2792 not = token;
2783 } 2793 }
2784 token = parseType(token.next); 2794 token = parseType(token.next);
2785 listener.handleIsOperator(operator, not, token); 2795 listener.handleIsOperator(operator, not, token);
2786 String value = token.stringValue; 2796 String value = token.stringValue;
2787 if (identical(value, 'is') || identical(value, 'as')) { 2797 if (identical(value, 'is') || identical(value, 'as')) {
2788 // The is- and as-operators cannot be chained, but they can take part of 2798 // The is- and as-operators cannot be chained, but they can take part of
2789 // expressions like: foo is Foo || foo is Bar. 2799 // expressions like: foo is Foo || foo is Bar.
2790 listener.unexpected(token); 2800 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2791 } 2801 }
2792 return token; 2802 return token;
2793 } 2803 }
2794 2804
2795 Token parseAsOperatorRest(Token token) { 2805 Token parseAsOperatorRest(Token token) {
2796 assert(optional('as', token)); 2806 assert(optional('as', token));
2797 Token operator = token; 2807 Token operator = token;
2798 token = parseType(token.next); 2808 token = parseType(token.next);
2799 listener.handleAsOperator(operator, token); 2809 listener.handleAsOperator(operator, token);
2800 String value = token.stringValue; 2810 String value = token.stringValue;
2801 if (identical(value, 'is') || identical(value, 'as')) { 2811 if (identical(value, 'is') || identical(value, 'as')) {
2802 // The is- and as-operators cannot be chained. 2812 // The is- and as-operators cannot be chained.
2803 listener.unexpected(token); 2813 reportUnrecoverableError(token, ErrorKind.UnexpectedToken);
2804 } 2814 }
2805 return token; 2815 return token;
2806 } 2816 }
2807 2817
2808 Token parseVariablesDeclaration(Token token) { 2818 Token parseVariablesDeclaration(Token token) {
2809 return parseVariablesDeclarationMaybeSemicolon(token, true); 2819 return parseVariablesDeclarationMaybeSemicolon(token, true);
2810 } 2820 }
2811 2821
2812 Token parseVariablesDeclarationNoSemicolon(Token token) { 2822 Token parseVariablesDeclarationNoSemicolon(Token token) {
2813 // Only called when parsing a for loop, so this is for parsing locals. 2823 // Only called when parsing a for loop, so this is for parsing locals.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2866 Token parseForStatement(Token awaitToken, Token token) { 2876 Token parseForStatement(Token awaitToken, Token token) {
2867 Token forToken = token; 2877 Token forToken = token;
2868 listener.beginForStatement(forToken); 2878 listener.beginForStatement(forToken);
2869 token = expect('for', token); 2879 token = expect('for', token);
2870 token = expect('(', token); 2880 token = expect('(', token);
2871 token = parseVariablesDeclarationOrExpressionOpt(token); 2881 token = parseVariablesDeclarationOrExpressionOpt(token);
2872 if (optional('in', token)) { 2882 if (optional('in', token)) {
2873 return parseForInRest(awaitToken, forToken, token); 2883 return parseForInRest(awaitToken, forToken, token);
2874 } else { 2884 } else {
2875 if (awaitToken != null) { 2885 if (awaitToken != null) {
2876 listener.reportError(awaitToken, ErrorKind.InvalidAwaitFor); 2886 reportRecoverableError(awaitToken, ErrorKind.InvalidAwaitFor);
2877 } 2887 }
2878 return parseForRest(forToken, token); 2888 return parseForRest(forToken, token);
2879 } 2889 }
2880 } 2890 }
2881 2891
2882 Token parseVariablesDeclarationOrExpressionOpt(Token token) { 2892 Token parseVariablesDeclarationOrExpressionOpt(Token token) {
2883 final String value = token.stringValue; 2893 final String value = token.stringValue;
2884 if (identical(value, ';')) { 2894 if (identical(value, ';')) {
2885 listener.handleNoExpression(token); 2895 listener.handleNoExpression(token);
2886 return token; 2896 return token;
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
3118 } 3128 }
3119 Token caseKeyword = token; 3129 Token caseKeyword = token;
3120 token = parseExpression(token.next); 3130 token = parseExpression(token.next);
3121 Token colonToken = token; 3131 Token colonToken = token;
3122 token = expect(':', token); 3132 token = expect(':', token);
3123 listener.handleCaseMatch(caseKeyword, colonToken); 3133 listener.handleCaseMatch(caseKeyword, colonToken);
3124 expressionCount++; 3134 expressionCount++;
3125 peek = peekPastLabels(token); 3135 peek = peekPastLabels(token);
3126 } else { 3136 } else {
3127 if (expressionCount == 0) { 3137 if (expressionCount == 0) {
3128 listener.expected("case", token); 3138 // TODO(ahe): This is probably easy to recover from.
3139 reportUnrecoverableError(
3140 token, ErrorKind.ExpectedButGot, {"expected": "case"});
3129 } 3141 }
3130 break; 3142 break;
3131 } 3143 }
3132 } 3144 }
3133 listener.beginSwitchCase(labelCount, expressionCount, begin); 3145 listener.beginSwitchCase(labelCount, expressionCount, begin);
3134 // Finally zero or more statements. 3146 // Finally zero or more statements.
3135 int statementCount = 0; 3147 int statementCount = 0;
3136 while (!identical(token.kind, EOF_TOKEN)) { 3148 while (!identical(token.kind, EOF_TOKEN)) {
3137 String value = peek.stringValue; 3149 String value = peek.stringValue;
3138 if ((identical(value, 'case')) || 3150 if ((identical(value, 'case')) ||
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
3193 hasTarget = true; 3205 hasTarget = true;
3194 } 3206 }
3195 listener.handleContinueStatement(hasTarget, continueKeyword, token); 3207 listener.handleContinueStatement(hasTarget, continueKeyword, token);
3196 return expectSemicolon(token); 3208 return expectSemicolon(token);
3197 } 3209 }
3198 3210
3199 Token parseEmptyStatement(Token token) { 3211 Token parseEmptyStatement(Token token) {
3200 listener.handleEmptyStatement(token); 3212 listener.handleEmptyStatement(token);
3201 return expectSemicolon(token); 3213 return expectSemicolon(token);
3202 } 3214 }
3215
3216 /// Don't call this method. Should only be used as a last resort when there
3217 /// is no feasible way to recover from a parser error.
3218 Token reportUnrecoverableError(Token token, ErrorKind kind, [Map arguments]) {
3219 Token next;
3220 if (token is ErrorToken) {
3221 next = reportErrorToken(token, false);
3222 } else {
3223 arguments ??= {};
3224 arguments.putIfAbsent("actual", () => token.value);
3225 next = listener.handleUnrecoverableError(token, kind, arguments);
3226 }
3227 return next ?? skipToEof(token);
3228 }
3229
3230 void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) {
3231 if (token is ErrorToken) {
3232 reportErrorToken(token, true);
3233 } else {
3234 arguments ??= {};
3235 listener.handleRecoverableError(token, kind, arguments);
3236 }
3237 }
3238
3239 Token reportErrorToken(ErrorToken token, bool isRecoverable) {
3240 ErrorKind kind;
3241 Map arguments = const {};
3242 if (token is BadInputToken) {
3243 String hex = token.character.toRadixString(16);
3244 if (hex.length < 4) {
3245 String padding = "0000".substring(hex.length);
3246 hex = "$padding$hex";
3247 }
3248 kind = ErrorKind.InvalidInputCharacter;
3249 arguments = {'characterHex': hex};
3250 } else if (token is UnterminatedToken) {
3251 switch (token.start) {
3252 case '1e':
3253 kind = ErrorKind.MissingExponent;
3254 break;
3255 case '"':
3256 case "'":
3257 case '"""':
3258 case "'''":
3259 case 'r"':
3260 case "r'":
3261 case 'r"""':
3262 case "r'''":
3263 kind = ErrorKind.UnterminatedString;
3264 arguments = {'quote': token.start};
3265 break;
3266 case '0x':
3267 kind = ErrorKind.ExpectedHexDigit;
3268 break;
3269 case r'$':
3270 kind = ErrorKind.MalformedStringLiteral;
3271 break;
3272 case '/*':
3273 kind = ErrorKind.UnterminatedComment;
3274 break;
3275 default:
3276 kind = ErrorKind.UnterminatedToken;
3277 break;
3278 }
3279 } else if (token is UnmatchedToken) {
3280 String begin = token.begin.value;
3281 String end = closeBraceFor(begin);
3282 kind = ErrorKind.UnmatchedToken;
3283 arguments = {'begin': begin, 'end': end};
3284 } else {
3285 return listener.handleUnrecoverableError(
3286 token, ErrorKind.Unspecified, {"text": token.assertionMessage});
3287 }
3288 if (isRecoverable) {
3289 listener.handleRecoverableError(token, kind, arguments);
3290 return null;
3291 } else {
3292 return listener.handleUnrecoverableError(token, kind, arguments);
3293 }
3294 }
3203 } 3295 }
3296
3297 String closeBraceFor(String openBrace) {
3298 return const {
3299 '(': ')',
3300 '[': ']',
3301 '{': '}',
3302 '<': '>',
3303 r'${': '}',
3304 }[openBrace];
3305 }
3306
3307 Token skipToEof(Token token) {
3308 while (!identical(token.info, EOF_INFO)) {
3309 token = token.next;
3310 }
3311 return token;
3312 }
OLDNEW
« no previous file with comments | « pkg/dart_parser/lib/src/listener.dart ('k') | pkg/fasta/lib/src/kernel/body_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698