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 fasta.parser.parser; | 5 library fasta.parser.parser; |
6 | 6 |
7 import '../fasta_codes.dart' show FastaCode, FastaMessage; | 7 import '../fasta_codes.dart' show FastaCode, FastaMessage; |
8 | 8 |
9 import '../fasta_codes.dart' as fasta; | 9 import '../fasta_codes.dart' as fasta; |
10 | 10 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 | 56 |
57 import 'listener.dart' show Listener; | 57 import 'listener.dart' show Listener; |
58 | 58 |
59 import 'identifier_context.dart' show IdentifierContext; | 59 import 'identifier_context.dart' show IdentifierContext; |
60 | 60 |
61 /// Returns true if [token] is the symbol or keyword [value]. | 61 /// Returns true if [token] is the symbol or keyword [value]. |
62 bool optional(String value, Token token) { | 62 bool optional(String value, Token token) { |
63 return identical(value, token.stringValue); | 63 return identical(value, token.stringValue); |
64 } | 64 } |
65 | 65 |
| 66 // TODO(ahe): Convert this to an enum. |
66 class FormalParameterType { | 67 class FormalParameterType { |
67 final String type; | 68 final String type; |
68 const FormalParameterType(this.type); | 69 |
| 70 final TypeContinuation typeContinuation; |
| 71 |
| 72 const FormalParameterType(this.type, this.typeContinuation); |
| 73 |
69 bool get isRequired => this == REQUIRED; | 74 bool get isRequired => this == REQUIRED; |
| 75 |
70 bool get isPositional => this == POSITIONAL; | 76 bool get isPositional => this == POSITIONAL; |
| 77 |
71 bool get isNamed => this == NAMED; | 78 bool get isNamed => this == NAMED; |
72 static final REQUIRED = const FormalParameterType('required'); | 79 |
73 static final POSITIONAL = const FormalParameterType('positional'); | 80 static final REQUIRED = const FormalParameterType( |
74 static final NAMED = const FormalParameterType('named'); | 81 'required', TypeContinuation.NormalFormalParameter); |
| 82 |
| 83 static final POSITIONAL = const FormalParameterType( |
| 84 'positional', TypeContinuation.OptionalPositionalFormalParameter); |
| 85 |
| 86 static final NAMED = |
| 87 const FormalParameterType('named', TypeContinuation.NamedFormalParameter); |
75 } | 88 } |
76 | 89 |
77 enum MemberKind { | 90 enum MemberKind { |
78 /// A catch block, not a real member. | 91 /// A catch block, not a real member. |
79 Catch, | 92 Catch, |
80 | 93 |
81 /// A factory | 94 /// A factory |
82 Factory, | 95 Factory, |
83 | 96 |
84 /// Old-style typedef. | 97 /// Old-style typedef. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 /// Indicates that a type may follow. If the following matches one of these | 147 /// Indicates that a type may follow. If the following matches one of these |
135 /// productions, it is parsed as a type: | 148 /// productions, it is parsed as a type: |
136 /// | 149 /// |
137 /// - `'void'` | 150 /// - `'void'` |
138 /// - `'Function' ( '(' | '<' )` | 151 /// - `'Function' ( '(' | '<' )` |
139 /// - `identifier ('.' identifier)? ('<' ... '>')? identifer` | 152 /// - `identifier ('.' identifier)? ('<' ... '>')? identifer` |
140 /// | 153 /// |
141 /// Otherwise, do nothing. | 154 /// Otherwise, do nothing. |
142 Optional, | 155 Optional, |
143 | 156 |
| 157 /// Same as [Optional], but we have seen `var`. |
| 158 OptionalAfterVar, |
| 159 |
144 /// Indicates that the keyword `typedef` has just been seen, and the parser | 160 /// Indicates that the keyword `typedef` has just been seen, and the parser |
145 /// should parse the following as a type unless it is followed by `=`. | 161 /// should parse the following as a type unless it is followed by `=`. |
146 Typedef, | 162 Typedef, |
147 | 163 |
148 /// Indicates that what follows is either a local declaration or an | 164 /// Indicates that what follows is either a local declaration or an |
149 /// expression. | 165 /// expression. |
150 ExpressionStatementOrDeclaration, | 166 ExpressionStatementOrDeclaration, |
151 | 167 |
152 /// Indicates that the keyword `const` has just been seen, and what follows | 168 /// Indicates that the keyword `const` has just been seen, and what follows |
153 /// may be a local variable declaration or an expression. | 169 /// may be a local variable declaration or an expression. |
154 ExpressionStatementOrConstDeclaration, | 170 ExpressionStatementOrConstDeclaration, |
155 | 171 |
156 /// Indicates that the parser is parsing an expression and has just seen an | 172 /// Indicates that the parser is parsing an expression and has just seen an |
157 /// identifier. | 173 /// identifier. |
158 SendOrFunctionLiteral, | 174 SendOrFunctionLiteral, |
159 | 175 |
160 /// Indicates that the parser has just parsed `for '('` and is looking to | 176 /// Indicates that the parser has just parsed `for '('` and is looking to |
161 /// parse a variable declaration or expression. | 177 /// parse a variable declaration or expression. |
162 VariablesDeclarationOrExpression, | 178 VariablesDeclarationOrExpression, |
| 179 |
| 180 /// Indicates that an optional type followed by a normal formal parameter is |
| 181 /// expected. |
| 182 NormalFormalParameter, |
| 183 |
| 184 /// Indicates that an optional type followed by an optional positional formal |
| 185 /// parameter is expected. |
| 186 OptionalPositionalFormalParameter, |
| 187 |
| 188 /// Indicates that an optional type followed by a named formal parameter is |
| 189 /// expected. |
| 190 NamedFormalParameter, |
| 191 |
| 192 /// Same as [NormalFormalParameter], but we have seen `var`. |
| 193 NormalFormalParameterAfterVar, |
| 194 |
| 195 /// Same as [OptionalPositionalFormalParameter], but we have seen `var`. |
| 196 OptionalPositionalFormalParameterAfterVar, |
| 197 |
| 198 /// Same as [NamedFormalParameter], but we have seen `var`. |
| 199 NamedFormalParameterAfterVar, |
163 } | 200 } |
164 | 201 |
165 /// An event generating parser of Dart programs. This parser expects all tokens | 202 /// An event generating parser of Dart programs. This parser expects all tokens |
166 /// in a linked list (aka a token stream). | 203 /// in a linked list (aka a token stream). |
167 /// | 204 /// |
168 /// The class [Scanner] is used to generate a token stream. See the file | 205 /// The class [Scanner] is used to generate a token stream. See the file |
169 /// [scanner.dart](../scanner.dart). | 206 /// [scanner.dart](../scanner.dart). |
170 /// | 207 /// |
171 /// Subclasses of the class [Listener] are used to listen to events. | 208 /// Subclasses of the class [Listener] are used to listen to events. |
172 /// | 209 /// |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 IdentifierContext.partNameContinuation); | 583 IdentifierContext.partNameContinuation); |
547 } else { | 584 } else { |
548 token = parseLiteralStringOrRecoverExpression(token); | 585 token = parseLiteralStringOrRecoverExpression(token); |
549 } | 586 } |
550 Token semicolon = token; | 587 Token semicolon = token; |
551 token = expect(';', token); | 588 token = expect(';', token); |
552 listener.endPartOf(partKeyword, semicolon, hasName); | 589 listener.endPartOf(partKeyword, semicolon, hasName); |
553 return token; | 590 return token; |
554 } | 591 } |
555 | 592 |
556 Token parseMetadataStar(Token token, {bool forParameter: false}) { | 593 Token parseMetadataStar(Token token, |
| 594 // TODO(ahe): Remove [forParameter]. |
| 595 {bool forParameter: false}) { |
557 token = listener.injectGenericCommentTypeAssign(token); | 596 token = listener.injectGenericCommentTypeAssign(token); |
558 listener.beginMetadataStar(token); | 597 listener.beginMetadataStar(token); |
559 int count = 0; | 598 int count = 0; |
560 while (optional('@', token)) { | 599 while (optional('@', token)) { |
561 token = parseMetadata(token); | 600 token = parseMetadata(token); |
562 count++; | 601 count++; |
563 } | 602 } |
564 listener.endMetadataStar(count, forParameter); | 603 listener.endMetadataStar(count, forParameter); |
565 return token; | 604 return token; |
566 } | 605 } |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 token = parseFormalParameter(token, FormalParameterType.REQUIRED, kind); | 722 token = parseFormalParameter(token, FormalParameterType.REQUIRED, kind); |
684 } while (optional(',', token)); | 723 } while (optional(',', token)); |
685 listener.endFormalParameters(parameterCount, begin, token, kind); | 724 listener.endFormalParameters(parameterCount, begin, token, kind); |
686 return expect(')', token); | 725 return expect(')', token); |
687 } | 726 } |
688 | 727 |
689 Token parseFormalParameter( | 728 Token parseFormalParameter( |
690 Token token, FormalParameterType parameterKind, MemberKind memberKind) { | 729 Token token, FormalParameterType parameterKind, MemberKind memberKind) { |
691 token = parseMetadataStar(token, forParameter: true); | 730 token = parseMetadataStar(token, forParameter: true); |
692 listener.beginFormalParameter(token, memberKind); | 731 listener.beginFormalParameter(token, memberKind); |
693 | |
694 bool inFunctionType = memberKind == MemberKind.GeneralizedFunctionType; | |
695 token = parseModifiers(token, memberKind, parameterKind: parameterKind); | 732 token = parseModifiers(token, memberKind, parameterKind: parameterKind); |
696 bool isNamedParameter = parameterKind == FormalParameterType.NAMED; | |
697 | |
698 Token thisKeyword = null; | |
699 Token nameToken; | |
700 if (inFunctionType) { | |
701 if (isNamedParameter || token.isIdentifier) { | |
702 nameToken = token; | |
703 token = parseIdentifier( | |
704 token, IdentifierContext.formalParameterDeclaration); | |
705 } else { | |
706 listener.handleNoName(token); | |
707 } | |
708 } else { | |
709 if (optional('this', token)) { | |
710 thisKeyword = token; | |
711 token = expect('.', token.next); | |
712 nameToken = token; | |
713 token = parseIdentifier(token, IdentifierContext.fieldInitializer); | |
714 } else { | |
715 nameToken = token; | |
716 token = parseIdentifier( | |
717 token, IdentifierContext.formalParameterDeclaration); | |
718 } | |
719 } | |
720 if (isNamedParameter && nameToken.lexeme.startsWith("_")) { | |
721 reportRecoverableErrorCode(nameToken, fasta.codePrivateNamedParameter); | |
722 } | |
723 | |
724 token = listener.injectGenericCommentTypeList(token); | |
725 if (optional('(', token)) { | |
726 Token inlineFunctionTypeStart = token; | |
727 listener.beginFunctionTypedFormalParameter(token); | |
728 listener.handleNoTypeVariables(token); | |
729 token = parseFormalParameters(token, MemberKind.FunctionTypedParameter); | |
730 listener.endFunctionTypedFormalParameter(thisKeyword, parameterKind); | |
731 // Generalized function types don't allow inline function types. | |
732 // The following isn't allowed: | |
733 // int Function(int bar(String x)). | |
734 if (memberKind == MemberKind.GeneralizedFunctionType) { | |
735 reportRecoverableErrorCode( | |
736 inlineFunctionTypeStart, fasta.codeInvalidInlineFunctionType); | |
737 } | |
738 } else if (optional('<', token)) { | |
739 Token inlineFunctionTypeStart = token; | |
740 listener.beginFunctionTypedFormalParameter(token); | |
741 token = parseTypeVariablesOpt(token); | |
742 token = parseFormalParameters(token, MemberKind.FunctionTypedParameter); | |
743 listener.endFunctionTypedFormalParameter(thisKeyword, parameterKind); | |
744 // Generalized function types don't allow inline function types. | |
745 // The following isn't allowed: | |
746 // int Function(int bar(String x)). | |
747 if (memberKind == MemberKind.GeneralizedFunctionType) { | |
748 reportRecoverableErrorCode( | |
749 inlineFunctionTypeStart, fasta.codeInvalidInlineFunctionType); | |
750 } | |
751 } | |
752 String value = token.stringValue; | |
753 if ((identical('=', value)) || (identical(':', value))) { | |
754 Token equal = token; | |
755 token = parseExpression(token.next); | |
756 listener.handleValuedFormalParameter(equal, token); | |
757 if (parameterKind.isRequired) { | |
758 reportRecoverableErrorCode( | |
759 equal, fasta.codeRequiredParameterWithDefault); | |
760 } else if (parameterKind.isPositional && identical(':', value)) { | |
761 reportRecoverableErrorCode( | |
762 equal, fasta.codePositionalParameterWithEquals); | |
763 } else if (inFunctionType || | |
764 memberKind == MemberKind.FunctionTypeAlias || | |
765 memberKind == MemberKind.FunctionTypedParameter) { | |
766 reportRecoverableErrorCode( | |
767 equal.next, fasta.codeFunctionTypeDefaultValue); | |
768 } | |
769 } else { | |
770 listener.handleFormalParameterWithoutValue(token); | |
771 } | |
772 listener.endFormalParameter( | |
773 thisKeyword, nameToken, parameterKind, memberKind); | |
774 return token; | 733 return token; |
775 } | 734 } |
776 | 735 |
777 Token parseOptionalFormalParameters( | 736 Token parseOptionalFormalParameters( |
778 Token token, bool isNamed, MemberKind kind) { | 737 Token token, bool isNamed, MemberKind kind) { |
779 Token begin = token; | 738 Token begin = token; |
780 listener.beginOptionalFormalParameters(begin); | 739 listener.beginOptionalFormalParameters(begin); |
781 assert((isNamed && optional('{', token)) || optional('[', token)); | 740 assert((isNamed && optional('{', token)) || optional('[', token)); |
782 int parameterCount = 0; | 741 int parameterCount = 0; |
783 do { | 742 do { |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1120 return optional('Function', token) && | 1079 return optional('Function', token) && |
1121 (optional('<', token.next) || optional('(', token.next)); | 1080 (optional('<', token.next) || optional('(', token.next)); |
1122 } | 1081 } |
1123 | 1082 |
1124 /// Parse a type, if it is appropriate to do so. | 1083 /// Parse a type, if it is appropriate to do so. |
1125 /// | 1084 /// |
1126 /// If this method can parse a type, it will return the next (non-null) token | 1085 /// If this method can parse a type, it will return the next (non-null) token |
1127 /// after the type. Otherwise, it returns null. | 1086 /// after the type. Otherwise, it returns null. |
1128 Token parseType(Token token, | 1087 Token parseType(Token token, |
1129 [TypeContinuation continuation = TypeContinuation.Required, | 1088 [TypeContinuation continuation = TypeContinuation.Required, |
1130 IdentifierContext continuationContext]) { | 1089 IdentifierContext continuationContext, |
| 1090 MemberKind memberKind]) { |
1131 /// Returns the close brace, bracket, or parenthesis of [left]. For '<', it | 1091 /// Returns the close brace, bracket, or parenthesis of [left]. For '<', it |
1132 /// may return null. | 1092 /// may return null. |
1133 Token getClose(BeginToken left) => left.endToken; | 1093 Token getClose(BeginToken left) => left.endToken; |
1134 | 1094 |
| 1095 /// True if we've seen the `var` keyword. |
| 1096 bool hasVar = false; |
| 1097 |
1135 /// Where the type begins. | 1098 /// Where the type begins. |
1136 Token begin; | 1099 Token begin; |
1137 | 1100 |
1138 /// Non-null if 'void' is the first token. | 1101 /// Non-null if 'void' is the first token. |
1139 Token voidToken; | 1102 Token voidToken; |
1140 | 1103 |
1141 /// True if the tokens at [begin] looks like a type. | 1104 /// True if the tokens at [begin] looks like a type. |
1142 bool looksLikeType = false; | 1105 bool looksLikeType = false; |
1143 | 1106 |
1144 /// True if a type that could be a return type for a generalized function | 1107 /// True if a type that could be a return type for a generalized function |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1277 token = token.next; | 1240 token = token.next; |
1278 if (optional("<", token)) { | 1241 if (optional("<", token)) { |
1279 // Skip type parameters, they were parsed above. | 1242 // Skip type parameters, they were parsed above. |
1280 token = getClose(token).next; | 1243 token = getClose(token).next; |
1281 } | 1244 } |
1282 token = | 1245 token = |
1283 parseFormalParameters(token, MemberKind.GeneralizedFunctionType); | 1246 parseFormalParameters(token, MemberKind.GeneralizedFunctionType); |
1284 listener.endFunctionType(functionToken, token); | 1247 listener.endFunctionType(functionToken, token); |
1285 } | 1248 } |
1286 | 1249 |
| 1250 if (hasVar) { |
| 1251 reportRecoverableErrorCode(begin, fasta.codeTypeAfterVar); |
| 1252 } |
| 1253 |
1287 return token; | 1254 return token; |
1288 } | 1255 } |
1289 | 1256 |
1290 /// Returns true if [kind] is '=', ';', or ',', that is, if [kind] could be | 1257 /// Returns true if [kind] is '=', ';', or ',', that is, if [kind] could be |
1291 /// the end of a variable declaration. | 1258 /// the end of a variable declaration. |
1292 bool looksLikeVariableDeclarationEnd(int kind) { | 1259 bool looksLikeVariableDeclarationEnd(int kind) { |
1293 return EQ_TOKEN == kind || SEMICOLON_TOKEN == kind || COMMA_TOKEN == kind; | 1260 return EQ_TOKEN == kind || SEMICOLON_TOKEN == kind || COMMA_TOKEN == kind; |
1294 } | 1261 } |
1295 | 1262 |
1296 /// Returns true if [token] could be the start of a function body. | 1263 /// Returns true if [token] could be the start of a function body. |
1297 bool looksLikeFunctionBody(Token token) { | 1264 bool looksLikeFunctionBody(Token token) { |
1298 return optional('{', token) || | 1265 return optional('{', token) || |
1299 optional('=>', token) || | 1266 optional('=>', token) || |
1300 optional('async', token) || | 1267 optional('async', token) || |
1301 optional('sync', token); | 1268 optional('sync', token); |
1302 } | 1269 } |
1303 | 1270 |
| 1271 FormalParameterType parameterKind; |
1304 switch (continuation) { | 1272 switch (continuation) { |
1305 case TypeContinuation.Required: | 1273 case TypeContinuation.Required: |
1306 return commitType(); | 1274 return commitType(); |
1307 | 1275 |
1308 optional: | 1276 optional: |
1309 case TypeContinuation.Optional: | 1277 case TypeContinuation.Optional: |
1310 if (looksLikeType) { | 1278 if (looksLikeType) { |
1311 if (functionTypes > 0) { | 1279 if (functionTypes > 0) { |
1312 return commitType(); // Parse function type. | 1280 return commitType(); // Parse function type. |
1313 } | 1281 } |
1314 if (voidToken != null) { | 1282 if (voidToken != null) { |
1315 listener.handleVoidKeyword(voidToken); | 1283 listener.handleVoidKeyword(voidToken); |
1316 return voidToken.next; | 1284 return voidToken.next; |
1317 } | 1285 } |
1318 if (token.isIdentifier || optional('this', token)) { | 1286 if (token.isIdentifier || optional('this', token)) { |
1319 return commitType(); // Parse type. | 1287 return commitType(); // Parse type. |
1320 } | 1288 } |
1321 } | 1289 } |
1322 listener.handleNoType(begin); | 1290 listener.handleNoType(begin); |
1323 return begin; | 1291 return begin; |
1324 | 1292 |
| 1293 case TypeContinuation.OptionalAfterVar: |
| 1294 hasVar = true; |
| 1295 continue optional; |
| 1296 |
1325 case TypeContinuation.Typedef: | 1297 case TypeContinuation.Typedef: |
1326 if (optional('=', token)) { | 1298 if (optional('=', token)) { |
1327 return null; // This isn't a type, it's a new-style typedef. | 1299 return null; // This isn't a type, it's a new-style typedef. |
1328 } | 1300 } |
1329 continue optional; | 1301 continue optional; |
1330 | 1302 |
1331 case TypeContinuation.ExpressionStatementOrDeclaration: | 1303 case TypeContinuation.ExpressionStatementOrDeclaration: |
1332 assert(begin.isIdentifier || identical(begin.stringValue, 'void')); | 1304 assert(begin.isIdentifier || identical(begin.stringValue, 'void')); |
1333 if (!inPlainSync && optional("await", begin)) { | 1305 if (!inPlainSync && optional("await", begin)) { |
1334 return parseExpressionStatement(begin); | 1306 return parseExpressionStatement(begin); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1425 | 1397 |
1426 case TypeContinuation.VariablesDeclarationOrExpression: | 1398 case TypeContinuation.VariablesDeclarationOrExpression: |
1427 if (looksLikeType && | 1399 if (looksLikeType && |
1428 token.isIdentifier && | 1400 token.isIdentifier && |
1429 isOneOf4(token.next, '=', ';', ',', 'in')) { | 1401 isOneOf4(token.next, '=', ';', ',', 'in')) { |
1430 // TODO(ahe): Generate type events and call | 1402 // TODO(ahe): Generate type events and call |
1431 // parseVariablesDeclarationNoSemicolonRest instead. | 1403 // parseVariablesDeclarationNoSemicolonRest instead. |
1432 return parseVariablesDeclarationNoSemicolon(begin); | 1404 return parseVariablesDeclarationNoSemicolon(begin); |
1433 } | 1405 } |
1434 return parseExpression(begin); | 1406 return parseExpression(begin); |
| 1407 |
| 1408 case TypeContinuation.NormalFormalParameter: |
| 1409 case TypeContinuation.NormalFormalParameterAfterVar: |
| 1410 parameterKind = FormalParameterType.REQUIRED; |
| 1411 hasVar = continuation == TypeContinuation.NormalFormalParameterAfterVar; |
| 1412 continue handleParameters; |
| 1413 |
| 1414 case TypeContinuation.OptionalPositionalFormalParameter: |
| 1415 case TypeContinuation.OptionalPositionalFormalParameterAfterVar: |
| 1416 parameterKind = FormalParameterType.POSITIONAL; |
| 1417 hasVar = continuation == |
| 1418 TypeContinuation.OptionalPositionalFormalParameterAfterVar; |
| 1419 continue handleParameters; |
| 1420 |
| 1421 case TypeContinuation.NamedFormalParameterAfterVar: |
| 1422 hasVar = true; |
| 1423 continue handleParameters; |
| 1424 |
| 1425 handleParameters: |
| 1426 case TypeContinuation.NamedFormalParameter: |
| 1427 parameterKind ??= FormalParameterType.NAMED; |
| 1428 bool inFunctionType = memberKind == MemberKind.GeneralizedFunctionType; |
| 1429 bool isNamedParameter = parameterKind == FormalParameterType.NAMED; |
| 1430 |
| 1431 bool untyped = false; |
| 1432 if (!looksLikeType || optional("this", begin)) { |
| 1433 untyped = true; |
| 1434 token = begin; |
| 1435 } |
| 1436 |
| 1437 Token thisKeyword; |
| 1438 Token nameToken = token; |
| 1439 IdentifierContext nameContext = |
| 1440 IdentifierContext.formalParameterDeclaration; |
| 1441 token = token.next; |
| 1442 if (inFunctionType) { |
| 1443 if (isNamedParameter || nameToken.isIdentifier) { |
| 1444 nameContext = IdentifierContext.formalParameterDeclaration; |
| 1445 } else { |
| 1446 // No name required in a function type. |
| 1447 nameContext = null; |
| 1448 token = nameToken; |
| 1449 } |
| 1450 } else if (optional('this', nameToken)) { |
| 1451 thisKeyword = nameToken; |
| 1452 token = expect('.', token); |
| 1453 nameToken = token; |
| 1454 nameContext = IdentifierContext.fieldInitializer; |
| 1455 token = token.next; |
| 1456 } else if (!nameToken.isIdentifier) { |
| 1457 untyped = true; |
| 1458 nameToken = begin; |
| 1459 token = nameToken.next; |
| 1460 } |
| 1461 if (isNamedParameter && nameToken.lexeme.startsWith("_")) { |
| 1462 // TODO(ahe): Move this to after commiting the type. |
| 1463 reportRecoverableErrorCode( |
| 1464 nameToken, fasta.codePrivateNamedParameter); |
| 1465 } |
| 1466 |
| 1467 token = listener.injectGenericCommentTypeList(token); |
| 1468 |
| 1469 Token inlineFunctionTypeStart; |
| 1470 if (optional("<", token)) { |
| 1471 Token closer = getClose(token); |
| 1472 if (closer != null) { |
| 1473 if (optional("(", closer.next)) { |
| 1474 inlineFunctionTypeStart = token; |
| 1475 token = token.next; |
| 1476 } |
| 1477 } |
| 1478 } else if (optional("(", token)) { |
| 1479 inlineFunctionTypeStart = token; |
| 1480 token = getClose(token).next; |
| 1481 } |
| 1482 |
| 1483 if (inlineFunctionTypeStart != null) { |
| 1484 token = parseTypeVariablesOpt(inlineFunctionTypeStart); |
| 1485 listener.beginFunctionTypedFormalParameter(inlineFunctionTypeStart); |
| 1486 if (!untyped) { |
| 1487 if (voidToken != null) { |
| 1488 listener.handleVoidKeyword(voidToken); |
| 1489 } else { |
| 1490 Token saved = token; |
| 1491 commitType(); |
| 1492 token = saved; |
| 1493 } |
| 1494 } else { |
| 1495 listener.handleNoType(begin); |
| 1496 } |
| 1497 token = |
| 1498 parseFormalParameters(token, MemberKind.FunctionTypedParameter); |
| 1499 listener.endFunctionTypedFormalParameter(); |
| 1500 |
| 1501 // Generalized function types don't allow inline function types. |
| 1502 // The following isn't allowed: |
| 1503 // int Function(int bar(String x)). |
| 1504 if (memberKind == MemberKind.GeneralizedFunctionType) { |
| 1505 reportRecoverableErrorCode( |
| 1506 inlineFunctionTypeStart, fasta.codeInvalidInlineFunctionType); |
| 1507 } |
| 1508 } else if (untyped) { |
| 1509 listener.handleNoType(begin); |
| 1510 } else { |
| 1511 Token saved = token; |
| 1512 commitType(); |
| 1513 token = saved; |
| 1514 } |
| 1515 |
| 1516 if (nameContext != null) { |
| 1517 parseIdentifier(nameToken, nameContext); |
| 1518 } else { |
| 1519 listener.handleNoName(nameToken); |
| 1520 } |
| 1521 |
| 1522 String value = token.stringValue; |
| 1523 if ((identical('=', value)) || (identical(':', value))) { |
| 1524 Token equal = token; |
| 1525 token = parseExpression(token.next); |
| 1526 listener.handleValuedFormalParameter(equal, token); |
| 1527 if (parameterKind.isRequired) { |
| 1528 reportRecoverableErrorCode( |
| 1529 equal, fasta.codeRequiredParameterWithDefault); |
| 1530 } else if (parameterKind.isPositional && identical(':', value)) { |
| 1531 reportRecoverableErrorCode( |
| 1532 equal, fasta.codePositionalParameterWithEquals); |
| 1533 } else if (inFunctionType || |
| 1534 memberKind == MemberKind.FunctionTypeAlias || |
| 1535 memberKind == MemberKind.FunctionTypedParameter) { |
| 1536 reportRecoverableErrorCode( |
| 1537 equal.next, fasta.codeFunctionTypeDefaultValue); |
| 1538 } |
| 1539 } else { |
| 1540 listener.handleFormalParameterWithoutValue(token); |
| 1541 } |
| 1542 listener.endFormalParameter( |
| 1543 thisKeyword, nameToken, parameterKind, memberKind); |
| 1544 |
| 1545 return token; |
1435 } | 1546 } |
1436 | 1547 |
1437 throw "Internal error: Unhandled continuation '$continuation'."; | 1548 throw "Internal error: Unhandled continuation '$continuation'."; |
1438 } | 1549 } |
1439 | 1550 |
1440 Token parseTypeArgumentsOpt(Token token) { | 1551 Token parseTypeArgumentsOpt(Token token) { |
1441 return parseStuff( | 1552 return parseStuff( |
1442 token, | 1553 token, |
1443 (t) => listener.beginTypeArguments(t), | 1554 (t) => listener.beginTypeArguments(t), |
1444 (t) => parseType(t), | 1555 (t) => parseType(t), |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1557 for (Token modifier in modifiers) { | 1668 for (Token modifier in modifiers) { |
1558 if (optional("var", modifier) || | 1669 if (optional("var", modifier) || |
1559 optional("final", modifier) || | 1670 optional("final", modifier) || |
1560 optional("const", modifier)) { | 1671 optional("const", modifier)) { |
1561 varFinalOrConst = modifier; | 1672 varFinalOrConst = modifier; |
1562 break; | 1673 break; |
1563 } | 1674 } |
1564 } | 1675 } |
1565 Token token = parseModifiers(start, | 1676 Token token = parseModifiers(start, |
1566 isTopLevel ? MemberKind.TopLevelField : MemberKind.NonStaticField, | 1677 isTopLevel ? MemberKind.TopLevelField : MemberKind.NonStaticField, |
1567 isVariable: true); | 1678 isVarAllowed: true); |
1568 | 1679 |
1569 if (token != name) { | 1680 if (token != name) { |
1570 reportRecoverableErrorCodeWithToken(token, fasta.codeExtraneousModifier); | 1681 reportRecoverableErrorCodeWithToken(token, fasta.codeExtraneousModifier); |
1571 token = name; | 1682 token = name; |
1572 } | 1683 } |
1573 | 1684 |
1574 IdentifierContext context = isTopLevel | 1685 IdentifierContext context = isTopLevel |
1575 ? IdentifierContext.topLevelVariableDeclaration | 1686 ? IdentifierContext.topLevelVariableDeclaration |
1576 : IdentifierContext.fieldDeclaration; | 1687 : IdentifierContext.fieldDeclaration; |
1577 token = parseIdentifier(token, context); | 1688 token = parseIdentifier(token, context); |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1912 } | 2023 } |
1913 | 2024 |
1914 /// This method is used in most locations where modifiers can occur. However, | 2025 /// This method is used in most locations where modifiers can occur. However, |
1915 /// it isn't used when parsing a class or when parsing the modifiers of a | 2026 /// it isn't used when parsing a class or when parsing the modifiers of a |
1916 /// member function (non-local), but is used when parsing their formal | 2027 /// member function (non-local), but is used when parsing their formal |
1917 /// parameters. | 2028 /// parameters. |
1918 /// | 2029 /// |
1919 /// When parsing the formal parameters of any function, [parameterKind] is | 2030 /// When parsing the formal parameters of any function, [parameterKind] is |
1920 /// non-null. | 2031 /// non-null. |
1921 Token parseModifiers(Token token, MemberKind memberKind, | 2032 Token parseModifiers(Token token, MemberKind memberKind, |
1922 {FormalParameterType parameterKind, bool isVariable: false}) { | 2033 {FormalParameterType parameterKind, bool isVarAllowed: false}) { |
1923 bool returnTypeAllowed = | |
1924 !isVariable && memberKind != MemberKind.GeneralizedFunctionType; | |
1925 bool typeRequired = | |
1926 isVariable || memberKind == MemberKind.GeneralizedFunctionType; | |
1927 int count = 0; | 2034 int count = 0; |
1928 | 2035 |
1929 int currentOrder = -1; | 2036 int currentOrder = -1; |
1930 bool hasVar = false; | 2037 TypeContinuation typeContinuation = parameterKind?.typeContinuation; |
| 2038 |
1931 while (token.kind == KEYWORD_TOKEN) { | 2039 while (token.kind == KEYWORD_TOKEN) { |
1932 if (token.type.isPseudo) { | 2040 if (token.type.isPseudo) { |
1933 // A pseudo keyword is never a modifier. | 2041 // A pseudo keyword is never a modifier. |
1934 break; | 2042 break; |
1935 } | 2043 } |
1936 if (token.type.isBuiltIn) { | 2044 if (token.type.isBuiltIn) { |
1937 // A built-in identifier can only be a modifier as long as it is | 2045 // A built-in identifier can only be a modifier as long as it is |
1938 // followed by another modifier or an identifier. Otherwise, it is the | 2046 // followed by another modifier or an identifier. Otherwise, it is the |
1939 // identifier. | 2047 // identifier. |
1940 if (token.next.kind != KEYWORD_TOKEN && !token.next.isIdentifier) { | 2048 if (token.next.kind != KEYWORD_TOKEN && !token.next.isIdentifier) { |
1941 break; | 2049 break; |
1942 } | 2050 } |
1943 } | 2051 } |
1944 int order = modifierOrder(token); | 2052 int order = modifierOrder(token); |
1945 if (order < 3) { | 2053 if (order < 3) { |
1946 // `abstract` isn't parsed with this method. | 2054 // `abstract` isn't parsed with this method. |
1947 if (order > currentOrder) { | 2055 if (order > currentOrder) { |
1948 currentOrder = order; | 2056 currentOrder = order; |
1949 if (optional("var", token)) { | 2057 if (optional("var", token)) { |
1950 if (!isVariable && parameterKind == null) { | 2058 if (!isVarAllowed && parameterKind == null) { |
1951 reportRecoverableErrorCodeWithToken( | 2059 reportRecoverableErrorCodeWithToken( |
1952 token, fasta.codeExtraneousModifier); | 2060 token, fasta.codeExtraneousModifier); |
1953 } | 2061 } |
1954 hasVar = true; | 2062 switch (typeContinuation ?? TypeContinuation.Required) { |
1955 typeRequired = false; | 2063 case TypeContinuation.NormalFormalParameter: |
| 2064 typeContinuation = |
| 2065 TypeContinuation.NormalFormalParameterAfterVar; |
| 2066 break; |
| 2067 |
| 2068 case TypeContinuation.OptionalPositionalFormalParameter: |
| 2069 typeContinuation = |
| 2070 TypeContinuation.OptionalPositionalFormalParameterAfterVar; |
| 2071 break; |
| 2072 |
| 2073 case TypeContinuation.NamedFormalParameter: |
| 2074 typeContinuation = |
| 2075 TypeContinuation.NamedFormalParameterAfterVar; |
| 2076 break; |
| 2077 |
| 2078 default: |
| 2079 typeContinuation = TypeContinuation.OptionalAfterVar; |
| 2080 break; |
| 2081 } |
1956 } else if (optional("final", token)) { | 2082 } else if (optional("final", token)) { |
1957 if (!isVariable && parameterKind == null) { | 2083 if (!isVarAllowed && parameterKind == null) { |
1958 reportRecoverableErrorCodeWithToken( | 2084 reportRecoverableErrorCodeWithToken( |
1959 token, fasta.codeExtraneousModifier); | 2085 token, fasta.codeExtraneousModifier); |
1960 } | 2086 } |
1961 typeRequired = false; | 2087 typeContinuation ??= TypeContinuation.Optional; |
1962 } else if (optional("const", token)) { | 2088 } else if (optional("const", token)) { |
1963 if (!isVariable) { | 2089 if (!isVarAllowed) { |
1964 reportRecoverableErrorCodeWithToken( | 2090 reportRecoverableErrorCodeWithToken( |
1965 token, fasta.codeExtraneousModifier); | 2091 token, fasta.codeExtraneousModifier); |
1966 } | 2092 } |
1967 typeRequired = false; | 2093 typeContinuation ??= TypeContinuation.Optional; |
1968 } else if (optional("static", token)) { | 2094 } else if (optional("static", token)) { |
1969 if (parameterKind != null) { | 2095 if (parameterKind != null) { |
1970 reportRecoverableErrorCodeWithToken( | 2096 reportRecoverableErrorCodeWithToken( |
1971 token, fasta.codeExtraneousModifier); | 2097 token, fasta.codeExtraneousModifier); |
1972 } else if (memberKind == MemberKind.NonStaticMethod) { | 2098 } else if (memberKind == MemberKind.NonStaticMethod) { |
1973 memberKind = MemberKind.StaticMethod; | 2099 memberKind = MemberKind.StaticMethod; |
1974 } else if (memberKind == MemberKind.NonStaticField) { | 2100 } else if (memberKind == MemberKind.NonStaticField) { |
1975 memberKind = MemberKind.StaticField; | 2101 memberKind = MemberKind.StaticField; |
1976 } else { | 2102 } else { |
1977 reportRecoverableErrorCodeWithToken( | 2103 reportRecoverableErrorCodeWithToken( |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2014 reportRecoverableErrorCodeWithToken( | 2140 reportRecoverableErrorCodeWithToken( |
2015 token, fasta.codeExtraneousModifier); | 2141 token, fasta.codeExtraneousModifier); |
2016 token = token.next; | 2142 token = token.next; |
2017 } | 2143 } |
2018 } else { | 2144 } else { |
2019 break; | 2145 break; |
2020 } | 2146 } |
2021 } | 2147 } |
2022 listener.handleModifiers(count); | 2148 listener.handleModifiers(count); |
2023 | 2149 |
2024 Token beforeType = token; | 2150 typeContinuation ??= |
2025 token = parseType( | 2151 (isVarAllowed || memberKind == MemberKind.GeneralizedFunctionType) |
2026 token, | 2152 ? TypeContinuation.Required |
2027 returnTypeAllowed || !typeRequired | 2153 : TypeContinuation.Optional; |
2028 ? TypeContinuation.Optional | 2154 |
2029 : TypeContinuation.Required); | 2155 token = parseType(token, typeContinuation, null, memberKind); |
2030 if (typeRequired && beforeType == token) { | |
2031 reportRecoverableErrorCode(token, fasta.codeTypeRequired); | |
2032 } | |
2033 if (hasVar && beforeType != token) { | |
2034 reportRecoverableErrorCode(beforeType, fasta.codeTypeAfterVar); | |
2035 } | |
2036 return token; | 2156 return token; |
2037 } | 2157 } |
2038 | 2158 |
2039 Token skipClassBody(Token token) { | 2159 Token skipClassBody(Token token) { |
2040 if (!optional('{', token)) { | 2160 if (!optional('{', token)) { |
2041 return reportUnrecoverableErrorCodeWithToken( | 2161 return reportUnrecoverableErrorCodeWithToken( |
2042 token, fasta.codeExpectedClassBodyToSkip) | 2162 token, fasta.codeExpectedClassBodyToSkip) |
2043 .next; | 2163 .next; |
2044 } | 2164 } |
2045 BeginToken beginGroupToken = token; | 2165 BeginToken beginGroupToken = token; |
(...skipping 1446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3492 Token token, bool endWithSemicolon) { | 3612 Token token, bool endWithSemicolon) { |
3493 token = parseMetadataStar(token); | 3613 token = parseMetadataStar(token); |
3494 | 3614 |
3495 // If the next token has a type substitution comment /*=T*/, then | 3615 // If the next token has a type substitution comment /*=T*/, then |
3496 // the current 'var' token should be repealed and replaced. | 3616 // the current 'var' token should be repealed and replaced. |
3497 if (optional('var', token)) { | 3617 if (optional('var', token)) { |
3498 token = | 3618 token = |
3499 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); | 3619 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); |
3500 } | 3620 } |
3501 | 3621 |
3502 token = parseModifiers(token, MemberKind.Local, isVariable: true); | 3622 token = parseModifiers(token, MemberKind.Local, isVarAllowed: true); |
3503 return parseVariablesDeclarationMaybeSemicolonRest(token, endWithSemicolon); | 3623 return parseVariablesDeclarationMaybeSemicolonRest(token, endWithSemicolon); |
3504 } | 3624 } |
3505 | 3625 |
3506 Token parseVariablesDeclarationMaybeSemicolonRest( | 3626 Token parseVariablesDeclarationMaybeSemicolonRest( |
3507 Token token, bool endWithSemicolon) { | 3627 Token token, bool endWithSemicolon) { |
3508 int count = 1; | 3628 int count = 1; |
3509 listener.beginVariablesDeclaration(token); | 3629 listener.beginVariablesDeclaration(token); |
3510 token = parseOptionallyInitializedIdentifier(token); | 3630 token = parseOptionallyInitializedIdentifier(token); |
3511 while (optional(',', token)) { | 3631 while (optional(',', token)) { |
3512 token = parseOptionallyInitializedIdentifier(token.next); | 3632 token = parseOptionallyInitializedIdentifier(token.next); |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4029 return reportUnrecoverableError( | 4149 return reportUnrecoverableError( |
4030 token, () => code.format(uri, token.charOffset, string)); | 4150 token, () => code.format(uri, token.charOffset, string)); |
4031 } | 4151 } |
4032 } | 4152 } |
4033 | 4153 |
4034 typedef FastaMessage NoArgument(Uri uri, int charOffset); | 4154 typedef FastaMessage NoArgument(Uri uri, int charOffset); |
4035 | 4155 |
4036 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); | 4156 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); |
4037 | 4157 |
4038 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); | 4158 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); |
OLD | NEW |