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

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2958073002: Remove all type-related peeking. (Closed)
Patch Set: Created 3 years, 5 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 | « no previous file | pkg/front_end/lib/src/fasta/parser/parser.md » ('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 fasta.parser.parser; 5 library fasta.parser.parser;
6 6
7 import '../fasta_codes.dart' 7 import '../fasta_codes.dart'
8 show 8 show
9 FastaCode, 9 FastaCode,
10 FastaMessage, 10 FastaMessage,
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 /// - `'void'` 194 /// - `'void'`
195 /// - `'Function' ( '(' | '<' )` 195 /// - `'Function' ( '(' | '<' )`
196 /// - `identifier ('.' identifier)? ('<' ... '>')? identifer` 196 /// - `identifier ('.' identifier)? ('<' ... '>')? identifer`
197 /// 197 ///
198 /// Otherwise, do nothing. 198 /// Otherwise, do nothing.
199 Optional, 199 Optional,
200 200
201 /// Indicates that the keyword `typedef` has just been seen, and the parser 201 /// Indicates that the keyword `typedef` has just been seen, and the parser
202 /// should parse the following as a type unless it is followed by `=`. 202 /// should parse the following as a type unless it is followed by `=`.
203 Typedef, 203 Typedef,
204
205 /// Indicates that what follows is either a local declaration or an
206 /// expression.
207 ExpressionStatementOrDeclaration,
208
209 /// Indicates that the keyword `const` has just been seen, and what follows
210 /// may be a local variable declaration or an expression.
211 ExpressionStatementOrConstDeclaration,
212
213 /// Indicates that the parser is parsing an expression and has just seen an
214 /// identifier.
215 SendOrFunctionLiteral,
danrubel 2017/06/28 03:22:00 What is 'Send' ? An invocation or call site?
ahe 2017/06/28 08:06:58 "Send" comes from message send. All method invocat
216
217 /// Indicates that the parser has just parsed `for '('` and is looking to
218 /// parse a variable declaration or expression.
219 VariablesDeclarationOrExpression,
204 } 220 }
205 221
206 /// An event generating parser of Dart programs. This parser expects all tokens 222 /// An event generating parser of Dart programs. This parser expects all tokens
207 /// in a linked list (aka a token stream). 223 /// in a linked list (aka a token stream).
208 /// 224 ///
209 /// The class [Scanner] is used to generate a token stream. See the file 225 /// The class [Scanner] is used to generate a token stream. See the file
210 /// [scanner.dart](../scanner.dart). 226 /// [scanner.dart](../scanner.dart).
211 /// 227 ///
212 /// Subclasses of the class [Listener] are used to listen to events. 228 /// Subclasses of the class [Listener] are used to listen to events.
213 /// 229 ///
(...skipping 936 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 bool isGeneralizedFunctionType(Token token) { 1166 bool isGeneralizedFunctionType(Token token) {
1151 return optional('Function', token) && 1167 return optional('Function', token) &&
1152 (optional('<', token.next) || optional('(', token.next)); 1168 (optional('<', token.next) || optional('(', token.next));
1153 } 1169 }
1154 1170
1155 /// Parse a type, if it is appropriate to do so. 1171 /// Parse a type, if it is appropriate to do so.
1156 /// 1172 ///
1157 /// If this method can parse a type, it will return the next (non-null) token 1173 /// If this method can parse a type, it will return the next (non-null) token
1158 /// after the type. Otherwise, it returns null. 1174 /// after the type. Otherwise, it returns null.
1159 Token parseType(Token token, 1175 Token parseType(Token token,
1160 [TypeContinuation continuation = TypeContinuation.Required]) { 1176 [TypeContinuation continuation = TypeContinuation.Required,
1161 Token begin = token; 1177 IdentifierContext continuationContext]) {
1178 /// Returns the close brace, bracket, or parenthesis of [left]. For '<', it
1179 /// may return null.
1180 Token getClose(BeginToken left) => left.endToken;
1181
1182 /// Where the type begins.
1183 Token begin;
1184
1185 /// Non-null if 'void' is the first token.
1186 Token voidToken;
1187
1188 /// True if the tokens at [begin] looks like a type.
1189 bool looksLikeType = false;
1190
1191 /// True if a type that could be a return type for a generalized function
1192 /// type was seen during analysis.
1193 bool hasReturnType = false;
1194
1195 /// The identifier context to use for parsing the type.
1196 IdentifierContext context = IdentifierContext.typeReference;
1197
1198 /// Non-null if type arguments were seen during analysis.
1199 BeginToken typeArguments;
1200
1201 /// The number of function types seen during analysis.
1202 int functionTypes = 0;
1203
1204 /// The start of type variables of function types seen during
1205 /// analysis. Notice that the tokens in this list might be either `'<'` or
1206 /// `'('` as not all function types have type parameters. Also, it is safe
1207 /// to assume that [getClose] will return non-null for all these tokens.
1208 Link<Token> typeVariableStarters = const Link<Token>();
1209
1210 {
1211 // Analyse the next tokens to see if they could be a type.
1212
1213 if (continuation ==
1214 TypeContinuation.ExpressionStatementOrConstDeclaration) {
1215 // This is a special case. The first token is `const` and we need to
1216 // analyze the tokens following the const keyword.
1217 assert(optional("const", token));
1218 begin = token;
1219 token = token.next;
1220 token = listener.injectGenericCommentTypeAssign(token);
1221 assert(begin.next == token);
1222 } else {
1223 // Modify [begin] in case generic type are injected from a comment.
1224 begin = token = listener.injectGenericCommentTypeAssign(token);
1225 }
1226
1227 if (optional("void", token)) {
1228 // `void` is a type.
1229 looksLikeType = true;
1230 voidToken = token;
1231 token = token.next;
1232 } else if (isValidTypeReference(token) &&
1233 !isGeneralizedFunctionType(token)) {
1234 // We're looking at an identifier that could be a type (or `dynamic`).
1235 looksLikeType = true;
1236 token = token.next;
1237 if (optional(".", token) && isValidTypeReference(token.next)) {
1238 // We're looking at `prefix '.' identifier`.
1239 context = IdentifierContext.prefixedTypeReference;
1240 token = token.next.next;
1241 }
1242 if (optional("<", token)) {
1243 Token close = getClose(token);
1244 if (close != null &&
1245 (optional(">", close) || optional(">>", close))) {
1246 // We found some type arguments.
1247 typeArguments = token;
1248 token = close.next;
1249 }
1250 }
1251 }
1252
1253 // If what we have seen so far looks like a type, that could be a return
1254 // type for a generalized function type.
1255 hasReturnType = looksLikeType;
1256
1257 while (optional("Function", token)) {
1258 Token typeVariableStart = token.next;
1259 if (optional("<", token.next)) {
1260 Token close = getClose(token.next);
1261 if (close != null && optional(">", close)) {
1262 token = close;
1263 } else {
1264 break; // Not a function type.
1265 }
1266 }
1267 if (optional("(", token.next)) {
1268 // This is a function type.
1269 Token close = getClose(token.next);
1270 assert(optional(")", close));
1271 looksLikeType = true;
1272 functionTypes++;
1273 typeVariableStarters =
1274 typeVariableStarters.prepend(typeVariableStart);
1275 token = close.next;
1276 } else {
1277 break; // Not a funtion type.
1278 }
1279 }
1280 }
1162 1281
1163 /// Call this function when it's known that [begin] is a type. This 1282 /// Call this function when it's known that [begin] is a type. This
1164 /// function will call the appropriate event methods on [listener] to 1283 /// function will call the appropriate event methods on [listener] to
1165 /// handle the type. 1284 /// handle the type.
1166 Token commitType() { 1285 Token commitType() {
1167 if (isGeneralizedFunctionType(token)) { 1286 assert(typeVariableStarters.length == functionTypes);
1287
1288 if (functionTypes > 0 && !hasReturnType) {
1168 // A function type without return type. 1289 // A function type without return type.
1169 // Push the non-existing return type first. The loop below will 1290 // Push the non-existing return type first. The loop below will
1170 // generate the full type. 1291 // generate the full type.
1171 listener.handleNoType(token); 1292 listener.handleNoType(begin);
1172 } else if (optional("void", token) && 1293 token = begin;
1173 isGeneralizedFunctionType(token.next)) { 1294 } else if (functionTypes > 0 && voidToken != null) {
1174 listener.handleVoidKeyword(token); 1295 listener.handleVoidKeyword(voidToken);
1175 token = token.next; 1296 token = voidToken.next;
1176 } else { 1297 } else {
1177 IdentifierContext context = IdentifierContext.typeReference; 1298 token = parseIdentifier(begin, context);
1178 if (token.isIdentifier && optional(".", token.next)) {
1179 context = IdentifierContext.prefixedTypeReference;
1180 }
1181 token = parseIdentifier(token, context);
1182 token = parseQualifiedRestOpt( 1299 token = parseQualifiedRestOpt(
1183 token, IdentifierContext.typeReferenceContinuation); 1300 token, IdentifierContext.typeReferenceContinuation);
1301 assert(typeArguments == null || typeArguments == token);
1184 token = parseTypeArgumentsOpt(token); 1302 token = parseTypeArgumentsOpt(token);
1185 listener.handleType(begin, token); 1303 listener.handleType(begin, token);
1186 } 1304 }
1187 1305
1188 { 1306 {
1189 Token newBegin = 1307 Token newBegin =
1190 listener.replaceTokenWithGenericCommentTypeAssign(begin, token); 1308 listener.replaceTokenWithGenericCommentTypeAssign(begin, token);
1191 if (!identical(newBegin, begin)) { 1309 if (!identical(newBegin, begin)) {
1192 listener.discardTypeReplacedWithCommentTypeAssign(); 1310 listener.discardTypeReplacedWithCommentTypeAssign();
1193 return parseType(newBegin); 1311 return parseType(newBegin);
1194 } 1312 }
1195 } 1313 }
1196 1314
1197 // While we see a `Function(` treat the pushed type as return type. 1315 // While we see a `Function(` treat the pushed type as return type.
1198 // For example: `int Function() Function(int) Function(String x)`. 1316 // For example: `int Function() Function(int) Function(String x)`.
1199 while (isGeneralizedFunctionType(token)) { 1317 for (int i = 0; i < functionTypes; i++) {
1318 assert(isGeneralizedFunctionType(token));
1200 token = parseFunctionType(token); 1319 token = parseFunctionType(token);
1201 } 1320 }
1321
1202 return token; 1322 return token;
1203 } 1323 }
1204 1324
1325 /// Returns true if [kind] is '=', ';', or ',', that is, if [kind] could be
1326 /// the end of a variable declaration.
1327 bool looksLikeVariableDeclarationEnd(int kind) {
1328 return EQ_TOKEN == kind || SEMICOLON_TOKEN == kind || COMMA_TOKEN == kind;
1329 }
1330
1331 /// Returns true if [token] could be the start of a function body.
1332 bool looksLikeFunctionBody(Token token) {
1333 return optional('{', token) ||
1334 optional('=>', token) ||
1335 optional('async', token) ||
1336 optional('sync', token);
1337 }
1338
1205 switch (continuation) { 1339 switch (continuation) {
1206 case TypeContinuation.Required: 1340 case TypeContinuation.Required:
1207 return commitType(); 1341 return commitType();
1208 1342
1209 optional: 1343 optional:
1210 case TypeContinuation.Optional: 1344 case TypeContinuation.Optional:
1211 if (optional("void", token)) { 1345 if (looksLikeType) {
1212 if (isGeneralizedFunctionType(token.next)) { 1346 if (functionTypes > 0) {
1213 return commitType(); // This is a type, parse it. 1347 return commitType(); // Parse function type.
1214 } else {
1215 listener.handleVoidKeyword(token);
1216 return token.next;
1217 } 1348 }
1218 } else { 1349 if (voidToken != null) {
1219 if (isGeneralizedFunctionType(token)) { 1350 listener.handleVoidKeyword(voidToken);
1220 return commitType(); // Function type without return type, parse it. 1351 return voidToken.next;
1221 } 1352 }
1222 token = listener.injectGenericCommentTypeAssign(token); 1353 if (token.isIdentifier || optional('this', token)) {
1223 Token peek = peekAfterIfType(token); 1354 return commitType(); // Parse type.
1224 if (peek != null && (peek.isIdentifier || optional('this', peek))) {
1225 // This is a type followed by an identifier, parse it.
1226 return commitType();
1227 } 1355 }
1228 listener.handleNoType(token);
1229 return token;
1230 } 1356 }
1231 break; 1357 listener.handleNoType(begin);
1358 return begin;
1232 1359
1233 case TypeContinuation.Typedef: 1360 case TypeContinuation.Typedef:
1234 if (optional('=', peekAfterNominalType(token))) { 1361 if (optional('=', token)) {
1235 return null; // This isn't a type, it's a new-style typedef. 1362 return null; // This isn't a type, it's a new-style typedef.
1236 } 1363 }
1237 continue optional; 1364 continue optional;
1365
1366 case TypeContinuation.ExpressionStatementOrDeclaration:
1367 assert(begin.isIdentifier || identical(begin.stringValue, 'void'));
1368 if (!inPlainSync && optional("await", begin)) {
1369 return parseExpressionStatement(begin);
1370 }
1371
1372 if (looksLikeType && token.isIdentifier) {
1373 // If the identifier token has a type substitution comment /*=T*/,
1374 // then the set of tokens type tokens should be replaced with the
1375 // tokens parsed from the comment.
1376 Token afterId = token.next;
1377
1378 begin =
1379 listener.replaceTokenWithGenericCommentTypeAssign(begin, token);
1380
1381 int afterIdKind = afterId.kind;
1382 if (looksLikeVariableDeclarationEnd(afterIdKind)) {
1383 // We are looking at `type identifier` followed by
1384 // `(',' | '=' | ';')`.
1385
1386 // TODO(ahe): Generate type events and call
1387 // parseVariablesDeclarationRest instead.
1388 return parseVariablesDeclaration(begin);
1389 } else if (OPEN_PAREN_TOKEN == afterIdKind) {
1390 // We are looking at `type identifier '('`.
1391 if (looksLikeFunctionBody(getClose(afterId).next)) {
1392 // We are looking at `type identifier '(' ... ')'` followed
1393 // `( '{' | '=>' | 'async' | 'sync' )`.
1394 return parseFunctionDeclaration(begin);
1395 }
1396 } else if (identical(afterIdKind, LT_TOKEN)) {
1397 // We are looking at `type identifier '<'`.
1398 Token afterTypeVariables = getClose(afterId)?.next;
1399 if (afterTypeVariables != null &&
1400 optional("(", afterTypeVariables)) {
1401 if (looksLikeFunctionBody(getClose(afterTypeVariables).next)) {
1402 // We are looking at "type identifier '<' ... '>' '(' ... ')'"
1403 // followed by '{', '=>', 'async', or 'sync'.
1404 return parseFunctionDeclaration(begin);
1405 }
1406 }
1407 }
1408 // Fall-through to expression statement.
1409 } else {
1410 token = begin;
1411 if (optional(':', token.next)) {
1412 return parseLabeledStatement(token);
1413 } else if (optional('(', token.next)) {
1414 if (looksLikeFunctionBody(getClose(token.next).next)) {
1415 return parseFunctionDeclaration(token);
1416 }
1417 } else if (optional('<', token.next)) {
1418 Token afterTypeVariables = getClose(token.next)?.next;
1419 if (afterTypeVariables != null &&
1420 optional("(", afterTypeVariables)) {
1421 if (looksLikeFunctionBody(getClose(afterTypeVariables).next)) {
1422 return parseFunctionDeclaration(token);
1423 }
1424 }
1425 // Fall through to expression statement.
1426 }
1427 }
1428 return parseExpressionStatement(begin);
1429
1430 case TypeContinuation.ExpressionStatementOrConstDeclaration:
1431 Token identifier;
1432 if (looksLikeType && token.isIdentifier) {
1433 identifier = token;
1434 } else if (begin.next.isIdentifier) {
1435 identifier = begin.next;
1436 }
1437 if (identifier != null) {
1438 if (looksLikeVariableDeclarationEnd(identifier.next.kind)) {
1439 // We are looking at "const type identifier" followed by '=', ';',
1440 // or ','.
1441
1442 // TODO(ahe): Generate type events and call
1443 // parseVariablesDeclarationRest instead.
1444 return parseVariablesDeclaration(begin);
1445 }
1446 // Fall-through to expression statement.
1447 }
1448
1449 return parseExpressionStatement(begin);
1450
1451 case TypeContinuation.SendOrFunctionLiteral:
1452 if (looksLikeType &&
1453 token.isIdentifier &&
1454 isFunctionDeclaration(token.next)) {
1455 return parseFunctionExpression(begin);
1456 } else if (isFunctionDeclaration(begin.next)) {
1457 return parseFunctionExpression(begin);
1458 }
1459 return parseSend(begin, continuationContext);
1460
1461 case TypeContinuation.VariablesDeclarationOrExpression:
1462 if (looksLikeType &&
1463 token.isIdentifier &&
1464 isOneOf4(token.next, '=', ';', ',', 'in')) {
1465 // TODO(ahe): Generate type events and call
1466 // parseVariablesDeclarationNoSemicolonRest instead.
1467 return parseVariablesDeclarationNoSemicolon(begin);
1468 }
1469 return parseExpression(begin);
1238 } 1470 }
1239 1471
1240 throw "Internal error: Unhandled continuation '$continuation'."; 1472 throw "Internal error: Unhandled continuation '$continuation'.";
1241 } 1473 }
1242 1474
1243 /// Parses a generalized function type. 1475 /// Parses a generalized function type.
1244 /// 1476 ///
1245 /// The return type must already be pushed. 1477 /// The return type must already be pushed.
1246 Token parseFunctionType(Token token) { 1478 Token parseFunctionType(Token token) {
1247 assert(optional('Function', token)); 1479 assert(optional('Function', token));
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after
1841 : TypeContinuation.Required); 2073 : TypeContinuation.Required);
1842 if (typeRequired && beforeType == token) { 2074 if (typeRequired && beforeType == token) {
1843 reportRecoverableErrorCode(token, codeTypeRequired); 2075 reportRecoverableErrorCode(token, codeTypeRequired);
1844 } 2076 }
1845 if (hasVar && beforeType != token) { 2077 if (hasVar && beforeType != token) {
1846 reportRecoverableErrorCode(beforeType, codeTypeAfterVar); 2078 reportRecoverableErrorCode(beforeType, codeTypeAfterVar);
1847 } 2079 }
1848 return token; 2080 return token;
1849 } 2081 }
1850 2082
1851 /// Returns the first token after the type starting at [token].
1852 ///
1853 /// This method assumes that [token] is an identifier (or void). Use
1854 /// [peekAfterIfType] if [token] isn't known to be an identifier.
1855 Token peekAfterType(Token token) {
1856 // We are looking at "identifier ...".
1857 Token peek = token;
1858 if (!isGeneralizedFunctionType(token)) {
1859 peek = peekAfterNominalType(token);
1860 }
1861
1862 // We might have just skipped over the return value of the function type.
1863 // Check again, if we are now at a function type position.
1864 while (isGeneralizedFunctionType(peek)) {
1865 peek = peekAfterFunctionType(peek.next);
1866 }
1867 return peek;
1868 }
1869
1870 /// Returns the first token after the nominal type starting at [token].
1871 ///
1872 /// This method assumes that [token] is an identifier (or void).
1873 Token peekAfterNominalType(Token token) {
1874 Token peek = token.next;
1875 if (identical(peek.kind, PERIOD_TOKEN)) {
1876 if (peek.next.isIdentifier) {
1877 // Look past a library prefix.
1878 peek = peek.next.next;
1879 }
1880 }
1881 // We are looking at "qualified ...".
1882 if (identical(peek.kind, LT_TOKEN)) {
1883 // Possibly generic type.
1884 // We are looking at "qualified '<'".
1885 BeginToken beginGroupToken = peek;
1886 Token gtToken = beginGroupToken.endGroup;
1887 if (gtToken != null) {
1888 // We are looking at "qualified '<' ... '>' ...".
1889 peek = gtToken.next;
1890 }
1891 }
1892 return peek;
1893 }
1894
1895 /// Returns the first token after the function type starting at [token].
1896 ///
1897 /// The token must be at the token *after* the `Function` token
1898 /// position. That is, the return type and the `Function` token must have
1899 /// already been skipped.
1900 ///
1901 /// This function only skips over one function type syntax. If necessary,
1902 /// this function must be called multiple times.
1903 ///
1904 /// Example:
1905 ///
1906 /// int Function() Function<T>(int)
1907 /// ^ ^
1908 ///
1909 /// A call to this function must be either at `(` or at `<`. If `token`
1910 /// pointed to the first `(`, then the returned token points to the second
1911 /// `Function` token.
1912 Token peekAfterFunctionType(Token token) {
1913 // Possible inputs are:
1914 // ( ... )
1915 // < ... >( ... )
1916
1917 Token peek = token;
1918 // If there is a generic argument to the function, skip over that one first.
1919 if (identical(peek.kind, LT_TOKEN)) {
1920 BeginToken beginGroupToken = peek;
1921 Token closeToken = beginGroupToken.endGroup;
1922 if (closeToken != null) {
1923 peek = closeToken.next;
1924 }
1925 }
1926
1927 // Now we just need to skip over the formals.
1928 expect('(', peek);
1929
1930 BeginToken beginGroupToken = peek;
1931 Token closeToken = beginGroupToken.endGroup;
1932 if (closeToken != null) {
1933 peek = closeToken.next;
1934 }
1935
1936 return peek;
1937 }
1938
1939 /// If [token] is the start of a type, returns the token after that type.
1940 /// If [token] is not the start of a type, null is returned.
1941 Token peekAfterIfType(Token token) {
1942 if (!optional('void', token) && !token.isIdentifier) {
1943 return null;
1944 }
1945 return peekAfterType(token);
1946 }
1947
1948 Token skipClassBody(Token token) { 2083 Token skipClassBody(Token token) {
1949 if (!optional('{', token)) { 2084 if (!optional('{', token)) {
1950 return reportUnrecoverableErrorCodeWithToken( 2085 return reportUnrecoverableErrorCodeWithToken(
1951 token, codeExpectedClassBodyToSkip) 2086 token, codeExpectedClassBodyToSkip)
1952 .next; 2087 .next;
1953 } 2088 }
1954 BeginToken beginGroupToken = token; 2089 BeginToken beginGroupToken = token;
1955 Token endGroup = beginGroupToken.endGroup; 2090 Token endGroup = beginGroupToken.endGroup;
1956 if (endGroup == null || !identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) { 2091 if (endGroup == null || !identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
1957 return reportUnmatchedToken(beginGroupToken).next; 2092 return reportUnmatchedToken(beginGroupToken).next;
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after
2561 } else { 2696 } else {
2562 token = parseExpression(token); 2697 token = parseExpression(token);
2563 if (inGenerator) { 2698 if (inGenerator) {
2564 reportRecoverableErrorCode(begin.next, codeGeneratorReturnsValue); 2699 reportRecoverableErrorCode(begin.next, codeGeneratorReturnsValue);
2565 } 2700 }
2566 listener.endReturnStatement(true, begin, token); 2701 listener.endReturnStatement(true, begin, token);
2567 } 2702 }
2568 return expectSemicolon(token); 2703 return expectSemicolon(token);
2569 } 2704 }
2570 2705
2571 Token peekIdentifierAfterType(Token token) { 2706 Token parseExpressionStatementOrDeclaration(Token token) {
2572 Token peek = peekAfterType(token); 2707 return parseType(token, TypeContinuation.ExpressionStatementOrDeclaration);
2573 if (peek != null && peek.isIdentifier) { 2708 }
2574 // We are looking at "type identifier". 2709
2575 return peek; 2710 Token parseExpressionStatementOrConstDeclaration(Token token) {
2711 assert(optional('const', token));
2712 if (isModifier(token.next)) {
2713 return parseVariablesDeclaration(token);
2576 } else { 2714 } else {
2577 return null; 2715 return parseType(
2716 token, TypeContinuation.ExpressionStatementOrConstDeclaration);
2578 } 2717 }
2579 } 2718 }
2580 2719
2581 Token peekIdentifierAfterOptionalType(Token token) {
2582 Token peek = peekAfterIfType(token);
2583 if (peek != null && peek.isIdentifier) {
2584 // We are looking at "type identifier".
2585 return peek;
2586 } else if (token.isIdentifier) {
2587 // We are looking at "identifier".
2588 return token;
2589 } else {
2590 return null;
2591 }
2592 }
2593
2594 Token parseExpressionStatementOrDeclaration(Token token) {
2595 if (!inPlainSync && optional("await", token)) {
2596 return parseExpressionStatement(token);
2597 }
2598 assert(token.isIdentifier || identical(token.stringValue, 'void'));
2599 Token identifier = peekIdentifierAfterType(token);
2600 if (identifier != null) {
2601 assert(identifier.isIdentifier);
2602
2603 // If the identifier token has a type substitution comment /*=T*/,
2604 // then the set of tokens type tokens should be replaced with the
2605 // tokens parsed from the comment.
2606 token =
2607 listener.replaceTokenWithGenericCommentTypeAssign(token, identifier);
2608
2609 Token afterId = identifier.next;
2610 int afterIdKind = afterId.kind;
2611 if (identical(afterIdKind, EQ_TOKEN) ||
2612 identical(afterIdKind, SEMICOLON_TOKEN) ||
2613 identical(afterIdKind, COMMA_TOKEN)) {
2614 // We are looking at "type identifier" followed by '=', ';', ','.
2615 return parseVariablesDeclaration(token);
2616 } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) {
2617 // We are looking at "type identifier '('".
2618 BeginToken beginParen = afterId;
2619 Token endParen = beginParen.endGroup;
2620 // TODO(eernst): Check for NPE as described in issue 26252.
2621 Token afterParens = endParen.next;
2622 if (optional('{', afterParens) ||
2623 optional('=>', afterParens) ||
2624 optional('async', afterParens) ||
2625 optional('sync', afterParens)) {
2626 // We are looking at "type identifier '(' ... ')'" followed
2627 // by '{', '=>', 'async', or 'sync'.
2628 return parseFunctionDeclaration(token);
2629 }
2630 } else if (identical(afterIdKind, LT_TOKEN)) {
2631 // We are looking at "type identifier '<'".
2632 BeginToken beginAngle = afterId;
2633 Token endAngle = beginAngle.endGroup;
2634 if (endAngle != null &&
2635 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
2636 BeginToken beginParen = endAngle.next;
2637 Token endParen = beginParen.endGroup;
2638 if (endParen != null) {
2639 Token afterParens = endParen.next;
2640 if (optional('{', afterParens) ||
2641 optional('=>', afterParens) ||
2642 optional('async', afterParens) ||
2643 optional('sync', afterParens)) {
2644 // We are looking at "type identifier '<' ... '>' '(' ... ')'"
2645 // followed by '{', '=>', 'async', or 'sync'.
2646 return parseFunctionDeclaration(token);
2647 }
2648 }
2649 }
2650 }
2651 // Fall-through to expression statement.
2652 } else {
2653 if (optional(':', token.next)) {
2654 return parseLabeledStatement(token);
2655 } else if (optional('(', token.next)) {
2656 BeginToken begin = token.next;
2657 // TODO(eernst): Check for NPE as described in issue 26252.
2658 String afterParens = begin.endGroup.next.stringValue;
2659 if (identical(afterParens, '{') ||
2660 identical(afterParens, '=>') ||
2661 identical(afterParens, 'async') ||
2662 identical(afterParens, 'sync')) {
2663 return parseFunctionDeclaration(token);
2664 }
2665 } else if (optional('<', token.next)) {
2666 BeginToken beginAngle = token.next;
2667 Token endAngle = beginAngle.endGroup;
2668 if (endAngle != null &&
2669 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) {
2670 BeginToken beginParen = endAngle.next;
2671 Token endParen = beginParen.endGroup;
2672 if (endParen != null) {
2673 String afterParens = endParen.next.stringValue;
2674 if (identical(afterParens, '{') ||
2675 identical(afterParens, '=>') ||
2676 identical(afterParens, 'async') ||
2677 identical(afterParens, 'sync')) {
2678 return parseFunctionDeclaration(token);
2679 }
2680 }
2681 }
2682 // Fall through to expression statement.
2683 }
2684 }
2685 return parseExpressionStatement(token);
2686 }
2687
2688 Token parseExpressionStatementOrConstDeclaration(Token token) {
2689 assert(identical(token.stringValue, 'const'));
2690 if (isModifier(token.next)) {
2691 return parseVariablesDeclaration(token);
2692 }
2693 listener.injectGenericCommentTypeAssign(token.next);
2694 Token identifier = peekIdentifierAfterOptionalType(token.next);
2695 if (identifier != null) {
2696 assert(identifier.isIdentifier);
2697 Token afterId = identifier.next;
2698 int afterIdKind = afterId.kind;
2699 if (identical(afterIdKind, EQ_TOKEN) ||
2700 identical(afterIdKind, SEMICOLON_TOKEN) ||
2701 identical(afterIdKind, COMMA_TOKEN)) {
2702 // We are looking at "const type identifier" followed by '=', ';', or
2703 // ','.
2704 return parseVariablesDeclaration(token);
2705 }
2706 // Fall-through to expression statement.
2707 }
2708
2709 return parseExpressionStatement(token);
2710 }
2711
2712 Token parseLabel(Token token) { 2720 Token parseLabel(Token token) {
2713 token = parseIdentifier(token, IdentifierContext.labelDeclaration); 2721 token = parseIdentifier(token, IdentifierContext.labelDeclaration);
2714 Token colon = token; 2722 Token colon = token;
2715 token = expect(':', token); 2723 token = expect(':', token);
2716 listener.handleLabel(colon); 2724 listener.handleLabel(colon);
2717 return token; 2725 return token;
2718 } 2726 }
2719 2727
2720 Token parseLabeledStatement(Token token) { 2728 Token parseLabeledStatement(Token token) {
2721 int labelCount = 0; 2729 int labelCount = 0;
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
3055 3063
3056 Token expressionExpected(Token token) { 3064 Token expressionExpected(Token token) {
3057 token = reportUnrecoverableErrorCodeWithToken(token, codeExpectedExpression) 3065 token = reportUnrecoverableErrorCodeWithToken(token, codeExpectedExpression)
3058 .next; 3066 .next;
3059 listener.handleInvalidExpression(token); 3067 listener.handleInvalidExpression(token);
3060 return token; 3068 return token;
3061 } 3069 }
3062 3070
3063 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { 3071 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
3064 BeginToken beginGroup = token; 3072 BeginToken beginGroup = token;
3065 // TODO(eernst): Check for NPE as described in issue 26252.
3066 Token nextToken = beginGroup.endGroup.next; 3073 Token nextToken = beginGroup.endGroup.next;
3067 int kind = nextToken.kind; 3074 int kind = nextToken.kind;
3068 if (mayParseFunctionExpressions && 3075 if (mayParseFunctionExpressions &&
3069 (identical(kind, FUNCTION_TOKEN) || 3076 (identical(kind, FUNCTION_TOKEN) ||
3070 identical(kind, OPEN_CURLY_BRACKET_TOKEN) || 3077 identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
3071 (identical(kind, KEYWORD_TOKEN) && 3078 (identical(kind, KEYWORD_TOKEN) &&
3072 (optional('async', nextToken) || 3079 (optional('async', nextToken) ||
3073 optional('sync', nextToken))))) { 3080 optional('sync', nextToken))))) {
3074 listener.handleNoTypeVariables(token); 3081 listener.handleNoTypeVariables(token);
3075 return parseUnnamedFunction(token); 3082 return parseUnnamedFunction(token);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
3234 Token colon = token; 3241 Token colon = token;
3235 token = expect(':', token); 3242 token = expect(':', token);
3236 token = parseExpression(token); 3243 token = parseExpression(token);
3237 listener.endLiteralMapEntry(colon, token); 3244 listener.endLiteralMapEntry(colon, token);
3238 return token; 3245 return token;
3239 } 3246 }
3240 3247
3241 Token parseSendOrFunctionLiteral(Token token, IdentifierContext context) { 3248 Token parseSendOrFunctionLiteral(Token token, IdentifierContext context) {
3242 if (!mayParseFunctionExpressions) { 3249 if (!mayParseFunctionExpressions) {
3243 return parseSend(token, context); 3250 return parseSend(token, context);
3244 }
3245 Token peek = peekAfterIfType(token);
3246 if (peek != null &&
3247 identical(peek.kind, IDENTIFIER_TOKEN) &&
3248 isFunctionDeclaration(peek.next)) {
3249 return parseFunctionExpression(token);
3250 } else if (isFunctionDeclaration(token.next)) {
3251 return parseFunctionExpression(token);
3252 } else { 3251 } else {
3253 return parseSend(token, context); 3252 return parseType(token, TypeContinuation.SendOrFunctionLiteral, context);
3254 } 3253 }
3255 } 3254 }
3256 3255
3257 bool isFunctionDeclaration(Token token) { 3256 bool isFunctionDeclaration(Token token) {
3258 if (optional('<', token)) { 3257 if (optional('<', token)) {
3259 BeginToken begin = token; 3258 BeginToken begin = token;
3260 if (begin.endGroup == null) return false; 3259 if (begin.endGroup == null) return false;
3261 token = begin.endGroup.next; 3260 token = begin.endGroup.next;
3262 } 3261 }
3263 if (optional('(', token)) { 3262 if (optional('(', token)) {
3264 BeginToken begin = token; 3263 BeginToken begin = token;
3265 // TODO(eernst): Check for NPE as described in issue 26252.
3266 String afterParens = begin.endGroup.next.stringValue; 3264 String afterParens = begin.endGroup.next.stringValue;
3267 if (identical(afterParens, '{') || 3265 if (identical(afterParens, '{') ||
3268 identical(afterParens, '=>') || 3266 identical(afterParens, '=>') ||
3269 identical(afterParens, 'async') || 3267 identical(afterParens, 'async') ||
3270 identical(afterParens, 'sync')) { 3268 identical(afterParens, 'sync')) {
3271 return true; 3269 return true;
3272 } 3270 }
3273 } 3271 }
3274 return false; 3272 return false;
3275 } 3273 }
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
3510 // The is- and as-operators cannot be chained. 3508 // The is- and as-operators cannot be chained.
3511 reportUnexpectedToken(token); 3509 reportUnexpectedToken(token);
3512 } 3510 }
3513 return token; 3511 return token;
3514 } 3512 }
3515 3513
3516 Token parseVariablesDeclaration(Token token) { 3514 Token parseVariablesDeclaration(Token token) {
3517 return parseVariablesDeclarationMaybeSemicolon(token, true); 3515 return parseVariablesDeclarationMaybeSemicolon(token, true);
3518 } 3516 }
3519 3517
3518 Token parseVariablesDeclarationRest(Token token) {
3519 return parseVariablesDeclarationMaybeSemicolonRest(token, true);
3520 }
3521
3520 Token parseVariablesDeclarationNoSemicolon(Token token) { 3522 Token parseVariablesDeclarationNoSemicolon(Token token) {
3521 // Only called when parsing a for loop, so this is for parsing locals. 3523 // Only called when parsing a for loop, so this is for parsing locals.
3522 return parseVariablesDeclarationMaybeSemicolon(token, false); 3524 return parseVariablesDeclarationMaybeSemicolon(token, false);
3523 } 3525 }
3524 3526
3527 Token parseVariablesDeclarationNoSemicolonRest(Token token) {
3528 // Only called when parsing a for loop, so this is for parsing locals.
3529 return parseVariablesDeclarationMaybeSemicolonRest(token, false);
3530 }
3531
3525 Token parseVariablesDeclarationMaybeSemicolon( 3532 Token parseVariablesDeclarationMaybeSemicolon(
3526 Token token, bool endWithSemicolon) { 3533 Token token, bool endWithSemicolon) {
3527 int count = 1;
3528 token = parseMetadataStar(token); 3534 token = parseMetadataStar(token);
3529 3535
3530 // If the next token has a type substitution comment /*=T*/, then 3536 // If the next token has a type substitution comment /*=T*/, then
3531 // the current 'var' token should be repealed and replaced. 3537 // the current 'var' token should be repealed and replaced.
3532 if (optional('var', token)) { 3538 if (optional('var', token)) {
3533 token = 3539 token =
3534 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); 3540 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next);
3535 } 3541 }
3536 3542
3537 token = parseModifiers(token, MemberKind.Local, isVariable: true); 3543 token = parseModifiers(token, MemberKind.Local, isVariable: true);
3544 return parseVariablesDeclarationMaybeSemicolonRest(token, endWithSemicolon);
3545 }
3546
3547 Token parseVariablesDeclarationMaybeSemicolonRest(
3548 Token token, bool endWithSemicolon) {
3549 int count = 1;
3538 listener.beginVariablesDeclaration(token); 3550 listener.beginVariablesDeclaration(token);
3539 token = parseOptionallyInitializedIdentifier(token); 3551 token = parseOptionallyInitializedIdentifier(token);
3540 while (optional(',', token)) { 3552 while (optional(',', token)) {
3541 token = parseOptionallyInitializedIdentifier(token.next); 3553 token = parseOptionallyInitializedIdentifier(token.next);
3542 ++count; 3554 ++count;
3543 } 3555 }
3544 if (endWithSemicolon) { 3556 if (endWithSemicolon) {
3545 Token semicolon = token; 3557 Token semicolon = token;
3546 token = expectSemicolon(semicolon); 3558 token = expectSemicolon(semicolon);
3547 listener.endVariablesDeclaration(count, semicolon); 3559 listener.endVariablesDeclaration(count, semicolon);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
3598 } 3610 }
3599 3611
3600 Token parseVariablesDeclarationOrExpressionOpt(Token token) { 3612 Token parseVariablesDeclarationOrExpressionOpt(Token token) {
3601 final String value = token.stringValue; 3613 final String value = token.stringValue;
3602 if (identical(value, ';')) { 3614 if (identical(value, ';')) {
3603 listener.handleNoExpression(token); 3615 listener.handleNoExpression(token);
3604 return token; 3616 return token;
3605 } else if (isOneOf4(token, '@', 'var', 'final', 'const')) { 3617 } else if (isOneOf4(token, '@', 'var', 'final', 'const')) {
3606 return parseVariablesDeclarationNoSemicolon(token); 3618 return parseVariablesDeclarationNoSemicolon(token);
3607 } 3619 }
3608 Token identifier = peekIdentifierAfterType(token); 3620 return parseType(token, TypeContinuation.VariablesDeclarationOrExpression);
3609 if (identifier != null) {
3610 assert(identifier.isIdentifier);
3611 if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
3612 return parseVariablesDeclarationNoSemicolon(token);
3613 }
3614 }
3615 return parseExpression(token);
3616 } 3621 }
3617 3622
3618 Token parseForRest(Token forToken, Token leftParenthesis, Token token) { 3623 Token parseForRest(Token forToken, Token leftParenthesis, Token token) {
3619 Token leftSeparator = token; 3624 Token leftSeparator = token;
3620 token = expectSemicolon(token); 3625 token = expectSemicolon(token);
3621 if (optional(';', token)) { 3626 if (optional(';', token)) {
3622 token = parseEmptyStatement(token); 3627 token = parseEmptyStatement(token);
3623 } else { 3628 } else {
3624 token = parseExpressionStatement(token); 3629 token = parseExpressionStatement(token);
3625 } 3630 }
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
4064 return reportUnrecoverableError( 4069 return reportUnrecoverableError(
4065 token, () => code.format(uri, token.charOffset, string)); 4070 token, () => code.format(uri, token.charOffset, string));
4066 } 4071 }
4067 } 4072 }
4068 4073
4069 typedef FastaMessage NoArgument(Uri uri, int charOffset); 4074 typedef FastaMessage NoArgument(Uri uri, int charOffset);
4070 4075
4071 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); 4076 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token);
4072 4077
4073 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); 4078 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string);
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/lib/src/fasta/parser/parser.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698