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

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

Issue 2999523002: Share code for parsing local functions. (Closed)
Patch Set: Update _BodySkippingParser. Created 3 years, 4 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
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' show Code, Message, Template; 7 import '../fasta_codes.dart' show Code, Message, Template;
8 8
9 import '../fasta_codes.dart' as fasta; 9 import '../fasta_codes.dart' as fasta;
10 10
(...skipping 1185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 // may get injected from a comment. 1196 // may get injected from a comment.
1197 Token formals = parseTypeVariablesOpt(afterId); 1197 Token formals = parseTypeVariablesOpt(afterId);
1198 1198
1199 listener.beginLocalFunctionDeclaration(begin); 1199 listener.beginLocalFunctionDeclaration(begin);
1200 listener.handleModifiers(0); 1200 listener.handleModifiers(0);
1201 if (voidToken != null) { 1201 if (voidToken != null) {
1202 listener.handleVoidKeyword(voidToken); 1202 listener.handleVoidKeyword(voidToken);
1203 } else { 1203 } else {
1204 commitType(); 1204 commitType();
1205 } 1205 }
1206 listener.beginFunctionName(token); 1206 return parseLocalFunctionDeclarationRest(begin, token, formals);
1207 token = parseIdentifier(
1208 token, IdentifierContext.localFunctionDeclaration);
1209 listener.endFunctionName(begin, token);
1210 return parseLocalFunctionDeclarationFromFormals(formals);
1211 } 1207 }
1212 } else if (identical(afterIdKind, LT_TOKEN)) { 1208 } else if (identical(afterIdKind, LT_TOKEN)) {
1213 // We are looking at `type identifier '<'`. 1209 // We are looking at `type identifier '<'`.
1214 Token formals = closeBraceTokenFor(afterId)?.next; 1210 Token formals = closeBraceTokenFor(afterId)?.next;
1215 if (formals != null && optional("(", formals)) { 1211 if (formals != null && optional("(", formals)) {
1216 if (looksLikeFunctionBody(closeBraceTokenFor(formals).next)) { 1212 if (looksLikeFunctionBody(closeBraceTokenFor(formals).next)) {
1217 // We are looking at "type identifier '<' ... '>' '(' ... ')'" 1213 // We are looking at "type identifier '<' ... '>' '(' ... ')'"
1218 // followed by '{', '=>', 'async', or 'sync'. 1214 // followed by '{', '=>', 'async', or 'sync'.
1219 parseTypeVariablesOpt(afterId); 1215 parseTypeVariablesOpt(afterId);
1220 listener.beginLocalFunctionDeclaration(begin); 1216 listener.beginLocalFunctionDeclaration(begin);
1221 listener.handleModifiers(0); 1217 listener.handleModifiers(0);
1222 if (voidToken != null) { 1218 if (voidToken != null) {
1223 listener.handleVoidKeyword(voidToken); 1219 listener.handleVoidKeyword(voidToken);
1224 } else { 1220 } else {
1225 commitType(); 1221 commitType();
1226 } 1222 }
1227 listener.beginFunctionName(token); 1223 return parseLocalFunctionDeclarationRest(begin, token, formals);
1228 token = parseIdentifier(
1229 token, IdentifierContext.localFunctionDeclaration);
1230 listener.endFunctionName(begin, token);
1231 return parseLocalFunctionDeclarationFromFormals(formals);
1232 } 1224 }
1233 } 1225 }
1234 } 1226 }
1235 // Fall-through to expression statement. 1227 // Fall-through to expression statement.
1236 } else { 1228 } else {
1237 token = begin; 1229 token = begin;
1238 if (optional(':', token.next)) { 1230 if (optional(':', token.next)) {
1239 return parseLabeledStatement(token); 1231 return parseLabeledStatement(token);
1240 } else if (optional('(', token.next)) { 1232 } else if (optional('(', token.next)) {
1241 if (looksLikeFunctionBody(closeBraceTokenFor(token.next).next)) { 1233 if (looksLikeFunctionBody(closeBraceTokenFor(token.next).next)) {
1242 // We are looking at `identifier '(' ... ')'` followed by `'{'`, 1234 // We are looking at `identifier '(' ... ')'` followed by `'{'`,
1243 // `'=>'`, `'async'`, or `'sync'`. 1235 // `'=>'`, `'async'`, or `'sync'`.
1244 1236
1245 // Although it looks like there are no type variables here, they 1237 // Although it looks like there are no type variables here, they
1246 // may get injected from a comment. 1238 // may get injected from a comment.
1247 Token formals = parseTypeVariablesOpt(token.next); 1239 Token formals = parseTypeVariablesOpt(token.next);
1248 1240
1249 listener.beginLocalFunctionDeclaration(token); 1241 listener.beginLocalFunctionDeclaration(token);
1250 listener.handleModifiers(0); 1242 listener.handleModifiers(0);
1251 listener.handleNoType(token); 1243 listener.handleNoType(token);
1252 listener.beginFunctionName(token); 1244 return parseLocalFunctionDeclarationRest(begin, token, formals);
1253 token = parseIdentifier(
1254 token, IdentifierContext.localFunctionDeclaration);
1255 listener.endFunctionName(begin, token);
1256 return parseLocalFunctionDeclarationFromFormals(formals);
1257 } 1245 }
1258 } else if (optional('<', token.next)) { 1246 } else if (optional('<', token.next)) {
1259 Token afterTypeVariables = closeBraceTokenFor(token.next)?.next; 1247 Token afterTypeVariables = closeBraceTokenFor(token.next)?.next;
1260 if (afterTypeVariables != null && 1248 if (afterTypeVariables != null &&
1261 optional("(", afterTypeVariables)) { 1249 optional("(", afterTypeVariables)) {
1262 if (looksLikeFunctionBody( 1250 if (looksLikeFunctionBody(
1263 closeBraceTokenFor(afterTypeVariables).next)) { 1251 closeBraceTokenFor(afterTypeVariables).next)) {
1264 // We are looking at `identifier '<' ... '>' '(' ... ')'` 1252 // We are looking at `identifier '<' ... '>' '(' ... ')'`
1265 // followed by `'{'`, `'=>'`, `'async'`, or `'sync'`. 1253 // followed by `'{'`, `'=>'`, `'async'`, or `'sync'`.
1266 parseTypeVariablesOpt(token.next); 1254 parseTypeVariablesOpt(token.next);
1267 listener.beginLocalFunctionDeclaration(token); 1255 listener.beginLocalFunctionDeclaration(token);
1268 listener.handleModifiers(0); 1256 listener.handleModifiers(0);
1269 listener.handleNoType(token); 1257 listener.handleNoType(token);
1270 listener.beginFunctionName(token); 1258 return parseLocalFunctionDeclarationRest(
1271 token = parseIdentifier( 1259 begin, token, afterTypeVariables);
1272 token, IdentifierContext.localFunctionDeclaration);
1273 listener.endFunctionName(begin, token);
1274 return parseLocalFunctionDeclarationFromFormals(
1275 afterTypeVariables);
1276 } 1260 }
1277 } 1261 }
1278 // Fall through to expression statement. 1262 // Fall through to expression statement.
1279 } 1263 }
1280 } 1264 }
1281 return parseExpressionStatement(begin); 1265 return parseExpressionStatement(begin);
1282 1266
1283 case TypeContinuation.ExpressionStatementOrConstDeclaration: 1267 case TypeContinuation.ExpressionStatementOrConstDeclaration:
1284 Token identifier; 1268 Token identifier;
1285 if (looksLikeType && token.isIdentifier) { 1269 if (looksLikeType && token.isIdentifier) {
(...skipping 1078 matching lines...) Expand 10 before | Expand all | Expand 10 after
2364 return token.next; 2348 return token.next;
2365 } else { 2349 } else {
2366 return parseIdentifier(token, IdentifierContext.operatorName); 2350 return parseIdentifier(token, IdentifierContext.operatorName);
2367 } 2351 }
2368 } 2352 }
2369 2353
2370 Token parseFunctionExpression(Token token) { 2354 Token parseFunctionExpression(Token token) {
2371 Token beginToken = token; 2355 Token beginToken = token;
2372 listener.beginFunctionExpression(token); 2356 listener.beginFunctionExpression(token);
2373 token = parseFormalParameters(token, MemberKind.Local); 2357 token = parseFormalParameters(token, MemberKind.Local);
2374 AsyncModifier savedAsyncModifier = asyncState; 2358 token = parseAsyncOptBody(token, true, false);
2375 token = parseAsyncModifier(token);
2376 bool isBlock = optional('{', token);
2377 token = parseFunctionBody(token, true, false);
2378 asyncState = savedAsyncModifier;
2379 listener.endFunctionExpression(beginToken, token); 2359 listener.endFunctionExpression(beginToken, token);
2380 return isBlock ? token.next : token; 2360 return token;
2381 } 2361 }
2382 2362
2383 /// Parses the rest of a local function declaration starting from formal 2363 /// Parses the rest of a local function declaration starting from its [name]
2384 /// parameters. 2364 /// but then skips any type parameters and continue parsing from [formals]
2365 /// (the formal parameters).
2385 /// 2366 ///
2386 /// Precondition: the parser has previously generated these events: 2367 /// Precondition: the parser has previously generated these events:
2387 /// 2368 ///
2388 /// - Type variables. 2369 /// - Type variables.
2389 /// - beginLocalFunctionDeclaration. 2370 /// - beginLocalFunctionDeclaration.
2390 /// - Modifiers. 2371 /// - Modifiers.
2391 /// - Return type. 2372 /// - Return type.
2392 /// - Function name. 2373 Token parseLocalFunctionDeclarationRest(
2393 Token parseLocalFunctionDeclarationFromFormals(Token token) { 2374 Token begin, Token name, Token formals) {
2394 token = parseFormalParametersOpt(token, MemberKind.Local); 2375 Token token = name;
2376 listener.beginFunctionName(token);
2377 token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration);
2378 listener.endFunctionName(begin, token);
2379 token = parseFormalParametersOpt(formals, MemberKind.Local);
2395 token = parseInitializersOpt(token); 2380 token = parseInitializersOpt(token);
2396 AsyncModifier savedAsyncModifier = asyncState; 2381 token = parseAsyncOptBody(token, false, false);
2397 token = parseAsyncModifier(token);
2398 token = parseFunctionBody(token, false, true);
2399 asyncState = savedAsyncModifier;
2400 token = token.next;
2401 listener.endLocalFunctionDeclaration(token); 2382 listener.endLocalFunctionDeclaration(token);
2402 return token; 2383 return token.next;
2403 } 2384 }
2404 2385
2405 /// Parses a named function expression which isn't legal syntax in Dart. 2386 /// Parses a named function expression which isn't legal syntax in Dart.
2406 /// Useful for recovering from Javascript code being pasted into a Dart 2387 /// Useful for recovering from Javascript code being pasted into a Dart
2407 /// proram, as it will interpret `function foo() {}` as a named function 2388 /// proram, as it will interpret `function foo() {}` as a named function
2408 /// expression with return type `function` and name `foo`. 2389 /// expression with return type `function` and name `foo`.
2409 Token parseNamedFunctionExpression(Token token) { 2390 Token parseNamedFunctionExpression(Token token) {
2410 Token beginToken = token; 2391 Token beginToken = token;
2411 listener.beginNamedFunctionExpression(token); 2392 listener.beginNamedFunctionExpression(token);
2412 listener.handleModifiers(0); 2393 listener.handleModifiers(0);
2413 token = parseType(token, TypeContinuation.Optional); 2394 token = parseType(token, TypeContinuation.Optional);
2414 if (token != beginToken) { 2395 if (token != beginToken) {
2415 reportRecoverableError(token, fasta.messageReturnTypeFunctionExpression); 2396 reportRecoverableError(token, fasta.messageReturnTypeFunctionExpression);
2416 } 2397 }
2417 listener.beginFunctionName(token); 2398 listener.beginFunctionName(token);
2418 Token nameToken = token; 2399 Token nameToken = token;
2419 token = parseIdentifier(token, IdentifierContext.functionExpressionName); 2400 token = parseIdentifier(token, IdentifierContext.functionExpressionName);
2420 reportRecoverableError(nameToken, fasta.messageNamedFunctionExpression); 2401 reportRecoverableError(nameToken, fasta.messageNamedFunctionExpression);
2421 listener.endFunctionName(beginToken, token); 2402 listener.endFunctionName(beginToken, token);
2422 token = parseTypeVariablesOpt(token); 2403 token = parseTypeVariablesOpt(token);
2423 token = parseFormalParameters(token, MemberKind.Local); 2404 token = parseFormalParameters(token, MemberKind.Local);
2424 listener.handleNoInitializers(); 2405 listener.handleNoInitializers();
2406 token = parseAsyncOptBody(token, true, false);
2407 listener.endNamedFunctionExpression(token);
2408 return token;
2409 }
2410
2411 /// Parses a function body optionally preceded by an async modifier (see
2412 /// [parseAsyncModifier]). This method is used in both expression context
2413 /// (when [isExpression] is true) and statement context. In statement context
2414 /// (when [isExpression] is false), and if the function body is on the form
2415 /// `=> expression`, a trailing semicolon is required.
2416 ///
2417 /// It's an error if there's no function body unless [allowAbstract] is true.
2418 Token parseAsyncOptBody(Token token, bool isExpression, bool allowAbstract) {
2425 AsyncModifier savedAsyncModifier = asyncState; 2419 AsyncModifier savedAsyncModifier = asyncState;
2426 token = parseAsyncModifier(token); 2420 token = parseAsyncModifier(token);
2427 bool isBlock = optional('{', token); 2421 token = parseFunctionBody(token, isExpression, allowAbstract);
2428 token = parseFunctionBody(token, true, false);
2429 asyncState = savedAsyncModifier; 2422 asyncState = savedAsyncModifier;
2430 listener.endNamedFunctionExpression(token); 2423 return token;
2431 return isBlock ? token.next : token;
2432 } 2424 }
2433 2425
2434 Token parseConstructorReference(Token token) { 2426 Token parseConstructorReference(Token token) {
2435 Token start = token; 2427 Token start = token;
2436 listener.beginConstructorReference(start); 2428 listener.beginConstructorReference(start);
2437 token = parseIdentifier(token, IdentifierContext.constructorReference); 2429 token = parseIdentifier(token, IdentifierContext.constructorReference);
2438 token = parseQualifiedRestOpt( 2430 token = parseQualifiedRestOpt(
2439 token, IdentifierContext.constructorReferenceContinuation); 2431 token, IdentifierContext.constructorReferenceContinuation);
2440 token = parseTypeArgumentsOpt(token); 2432 token = parseTypeArgumentsOpt(token);
2441 Token period = null; 2433 Token period = null;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2482 expectSemicolon(token); 2474 expectSemicolon(token);
2483 listener.handleFunctionBodySkipped(token, true); 2475 listener.handleFunctionBodySkipped(token, true);
2484 } else { 2476 } else {
2485 token = skipBlock(token); 2477 token = skipBlock(token);
2486 listener.handleFunctionBodySkipped(token, false); 2478 listener.handleFunctionBodySkipped(token, false);
2487 } 2479 }
2488 } 2480 }
2489 return token; 2481 return token;
2490 } 2482 }
2491 2483
2484 /// Parses a function body. This method is used in both expression context
2485 /// (when [isExpression] is true) and statement context. In statement context
2486 /// (when [isExpression] is false), and if the function body is on the form
2487 /// `=> expression`, a trailing semicolon is required.
2488 ///
2489 /// It's an error if there's no function body unless [allowAbstract] is true.
2492 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { 2490 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
2493 if (optional(';', token)) { 2491 if (optional(';', token)) {
2494 if (!allowAbstract) { 2492 if (!allowAbstract) {
2495 reportRecoverableError(token, fasta.messageExpectedBody); 2493 reportRecoverableError(token, fasta.messageExpectedBody);
2496 } 2494 }
2497 listener.handleEmptyFunctionBody(token); 2495 listener.handleEmptyFunctionBody(token);
2498 return token; 2496 return token;
2499 } else if (optional('=>', token)) { 2497 } else if (optional('=>', token)) {
2500 Token begin = token; 2498 Token begin = token;
2501 token = parseExpression(token.next); 2499 token = parseExpression(token.next);
(...skipping 28 matching lines...) Expand all
2530 } 2528 }
2531 2529
2532 listener.beginBlockFunctionBody(begin); 2530 listener.beginBlockFunctionBody(begin);
2533 token = token.next; 2531 token = token.next;
2534 while (notEofOrValue('}', token)) { 2532 while (notEofOrValue('}', token)) {
2535 token = parseStatement(token); 2533 token = parseStatement(token);
2536 ++statementCount; 2534 ++statementCount;
2537 } 2535 }
2538 listener.endBlockFunctionBody(statementCount, begin, token); 2536 listener.endBlockFunctionBody(statementCount, begin, token);
2539 expect('}', token); 2537 expect('}', token);
2540 return token; 2538 return isExpression ? token.next : token;
2541 } 2539 }
2542 2540
2543 Token skipAsyncModifier(Token token) { 2541 Token skipAsyncModifier(Token token) {
2544 String value = token.stringValue; 2542 String value = token.stringValue;
2545 if (identical(value, 'async')) { 2543 if (identical(value, 'async')) {
2546 token = token.next; 2544 token = token.next;
2547 value = token.stringValue; 2545 value = token.stringValue;
2548 2546
2549 if (identical(value, '*')) { 2547 if (identical(value, '*')) {
2550 token = token.next; 2548 token = token.next;
(...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after
4049 } 4047 }
4050 4048
4051 Token reportUnexpectedToken(Token token) { 4049 Token reportUnexpectedToken(Token token) {
4052 return reportUnrecoverableErrorWithToken( 4050 return reportUnrecoverableErrorWithToken(
4053 token, fasta.templateUnexpectedToken); 4051 token, fasta.templateUnexpectedToken);
4054 } 4052 }
4055 } 4053 }
4056 4054
4057 // TODO(ahe): Remove when analyzer supports generalized function syntax. 4055 // TODO(ahe): Remove when analyzer supports generalized function syntax.
4058 typedef _MessageWithArgument<T> = Message Function(T); 4056 typedef _MessageWithArgument<T> = Message Function(T);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698