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' | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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); |
OLD | NEW |