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

Unified Diff: sdk/lib/_internal/compiler/implementation/scanner/parser.dart

Issue 675113002: Support async/await in the dart2js frontend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments Created 6 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/scanner/parser.dart
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index 33fbfeb982fc34067e43f7b5438407afd48eea68..b13a7b5ca47a281beb3bf5cd5556bc820dfbbde5 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -41,6 +41,8 @@ class FormalParameterType {
class Parser {
final Listener listener;
bool mayParseFunctionExpressions = true;
+ bool yieldIsKeyword = false;
+ bool awaitIsKeyword = false;
Parser(this.listener);
@@ -864,7 +866,12 @@ class Parser {
Token token = parseIdentifier(name);
token = parseFormalParametersOpt(token);
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
token = parseFunctionBody(token, false, externalModifier != null);
+ yieldIsKeyword = previousYieldIsKeyword;
+ awaitIsKeyword = previousAwaitIsKeyword;
listener.endTopLevelMethod(start, getOrSet, token);
return token.next;
}
@@ -1206,12 +1213,17 @@ class Parser {
token = parseQualifiedRestOpt(token);
token = parseFormalParametersOpt(token);
token = parseInitializersOpt(token);
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
if (optional('=', token)) {
token = parseRedirectingFactoryBody(token);
} else {
token = parseFunctionBody(
token, false, staticModifier == null || externalModifier != null);
}
+ yieldIsKeyword = previousYieldIsKeyword;
+ awaitIsKeyword = previousAwaitIsKeyword;
listener.endMethod(getOrSet, start, token);
return token.next;
}
@@ -1234,6 +1246,9 @@ class Parser {
token = token.next; // Skip 'factory'.
token = parseConstructorReference(token);
token = parseFormalParameters(token);
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
if (optional('=', token)) {
token = parseRedirectingFactoryBody(token);
} else {
@@ -1277,21 +1292,31 @@ class Parser {
listener.endFunctionName(token);
token = parseFormalParametersOpt(token);
token = parseInitializersOpt(token);
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
if (optional('=', token)) {
token = parseRedirectingFactoryBody(token);
} else {
token = parseFunctionBody(token, false, true);
}
+ yieldIsKeyword = previousYieldIsKeyword;
+ awaitIsKeyword = previousAwaitIsKeyword;
listener.endFunction(getOrSet, token);
return token.next;
}
- Token parseUnamedFunction(Token token) {
- listener.beginUnamedFunction(token);
+ Token parseUnnamedFunction(Token token) {
+ listener.beginUnnamedFunction(token);
token = parseFormalParameters(token);
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
bool isBlock = optional('{', token);
token = parseFunctionBody(token, true, false);
- listener.endUnamedFunction(token);
+ yieldIsKeyword = previousYieldIsKeyword;
+ awaitIsKeyword = previousAwaitIsKeyword;
+ listener.endUnnamedFunction(token);
return isBlock ? token.next : token;
}
@@ -1311,8 +1336,13 @@ class Parser {
listener.endFunctionName(token);
token = parseFormalParameters(token);
listener.handleNoInitializers();
+ bool previousYieldIsKeyword = yieldIsKeyword;
+ bool previousAwaitIsKeyword = awaitIsKeyword;
+ token = parseAsyncModifier(token);
bool isBlock = optional('{', token);
token = parseFunctionBody(token, true, false);
+ yieldIsKeyword = previousYieldIsKeyword;
+ awaitIsKeyword = previousAwaitIsKeyword;
listener.endFunction(null, token);
return isBlock ? token.next : token;
}
@@ -1378,6 +1408,48 @@ class Parser {
return token;
}
+ /// `async*` and `sync*` are parsed a two tokens, [token] and [star]. This
+ /// method checks that there is no whitespace between [token] and [star].
+ void checkStarredModifier(Token token, Token star, String name) {
+ if (star.charOffset > token.charOffset + token.charCount) {
+ listener.reportError(new TokenPair(token, star),
+ MessageKind.INVALID_STARRED_KEYWORD, {'keyword': name});
+ }
+ }
+
+ Token parseAsyncModifier(Token token) {
+ Token async;
+ Token star;
+ awaitIsKeyword = false;
+ yieldIsKeyword = false;
+ if (optional('async', token)) {
+ awaitIsKeyword = true;
+ async = token;
+ token = token.next;
+ if (optional('*', token)) {
+ yieldIsKeyword = true;
+ star = token;
+ token = token.next;
+ checkStarredModifier(async, star, 'async*');
+ }
+ } else if (optional('sync', token)) {
+ async = token;
+ token = token.next;
+ if (optional('*', token)) {
+ yieldIsKeyword = true;
+ star = token;
+ token = token.next;
+
+ checkStarredModifier(async, star, 'sync*');
+ } else {
+ listener.reportError(async,
+ MessageKind.INVALID_SYNC_MODIFIER);
+ }
+ }
+ listener.handleAsyncModifier(async, star);
+ return token;
+ }
+
Token parseStatement(Token token) {
final value = token.stringValue;
if (identical(token.kind, IDENTIFIER_TOKEN)) {
@@ -1390,8 +1462,14 @@ class Parser {
return parseVariablesDeclaration(token);
} else if (identical(value, 'if')) {
return parseIfStatement(token);
+ } else if (awaitIsKeyword && identical(value, 'await')) {
+ if (identical(token.next.stringValue, 'for')) {
+ return parseForStatement(token, token.next);
+ } else {
+ return parseExpressionStatement(token);
+ }
} else if (identical(value, 'for')) {
- return parseForStatement(token);
+ return parseForStatement(null, token);
} else if (identical(value, 'rethrow')) {
return parseRethrowStatement(token);
} else if (identical(value, 'throw') && optional(';', token.next)) {
@@ -1415,6 +1493,8 @@ class Parser {
return parseAssertStatement(token);
} else if (identical(value, ';')) {
return parseEmptyStatement(token);
+ } else if (yieldIsKeyword && identical(value, 'yield')) {
+ return parseYieldStatement(token);
} else if (identical(value, 'const')) {
return parseExpressionStatementOrConstDeclaration(token);
} else if (token.isIdentifier()) {
@@ -1424,6 +1504,23 @@ class Parser {
}
}
+ Token parseYieldStatement(Token token) {
+ Token begin = token;
+ listener.beginYieldStatement(begin);
+ assert(identical('yield', token.stringValue));
+ token = token.next;
+ Token starToken;
+ if (optional('*', token)) {
+ starToken = token;
+ token = token.next;
+ checkStarredModifier(begin, starToken, 'yield*');
+ }
+ token = parseExpression(token);
+ listener.endYieldStatement(begin, starToken, token);
+ return expectSemicolon(token);
+ }
+
+
Token parseReturnStatement(Token token) {
Token begin = token;
listener.beginReturnStatement(begin);
@@ -1478,7 +1575,10 @@ class Parser {
BeginGroupToken beginParen = afterId;
Token endParen = beginParen.endGroup;
Token afterParens = endParen.next;
- if (optional('{', afterParens) || optional('=>', afterParens)) {
+ if (optional('{', afterParens) ||
+ optional('=>', afterParens) ||
+ optional('async', afterParens) ||
+ optional('sync', afterParens)) {
// We are looking at "type identifier '(' ... ')'" followed
// by '=>' or '{'.
return parseFunctionDeclaration(token);
@@ -1491,7 +1591,10 @@ class Parser {
} else if (optional('(', token.next)) {
BeginGroupToken begin = token.next;
String afterParens = begin.endGroup.next.stringValue;
- if (identical(afterParens, '{') || identical(afterParens, '=>')) {
+ if (identical(afterParens, '{') ||
+ identical(afterParens, '=>') ||
+ identical(afterParens, 'async') ||
+ identical(afterParens, 'sync')) {
return parseFunctionDeclaration(token);
}
}
@@ -1672,7 +1775,9 @@ class Parser {
Token parseUnaryExpression(Token token, bool allowCascades) {
String value = token.stringValue;
// Prefix:
- if (identical(value, '+')) {
+ if (awaitIsKeyword && optional('await', token)) {
+ return parseAwaitExpression(token, allowCascades);
+ } else if (identical(value, '+')) {
// Dart no longer allows prefix-plus.
listener.reportError(token, MessageKind.UNSUPPORTED_PREFIX_PLUS);
return parseUnaryExpression(token.next, allowCascades);
@@ -1767,11 +1872,14 @@ class Parser {
Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
BeginGroupToken beginGroup = token;
- int kind = beginGroup.endGroup.next.kind;
+ Token nextToken = beginGroup.endGroup.next;
+ int kind = nextToken.kind;
if (mayParseFunctionExpressions &&
- (identical(kind, FUNCTION_TOKEN)
- || identical(kind, OPEN_CURLY_BRACKET_TOKEN))) {
- return parseUnamedFunction(token);
+ (identical(kind, FUNCTION_TOKEN) ||
+ identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
+ (identical(kind, KEYWORD_TOKEN) &&
+ (nextToken.value == 'async' || nextToken.value == 'sync')))) {
+ return parseUnnamedFunction(token);
} else {
bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
@@ -1893,7 +2001,10 @@ class Parser {
if (optional('(', token)) {
BeginGroupToken begin = token;
String afterParens = begin.endGroup.next.stringValue;
- if (identical(afterParens, '{') || identical(afterParens, '=>')) {
+ if (identical(afterParens, '{') ||
+ identical(afterParens, '=>') ||
+ identical(afterParens, 'async') ||
+ identical(afterParens, 'sync')) {
return true;
}
}
@@ -2151,15 +2262,18 @@ class Parser {
return token;
}
- Token parseForStatement(Token token) {
+ Token parseForStatement(Token awaitToken, Token token) {
Token forToken = token;
listener.beginForStatement(forToken);
token = expect('for', token);
token = expect('(', token);
token = parseVariablesDeclarationOrExpressionOpt(token);
if (optional('in', token)) {
- return parseForInRest(forToken, token);
+ return parseForInRest(awaitToken, forToken, token);
} else {
+ if (awaitToken != null) {
+ listener.reportError(awaitToken, MessageKind.INVALID_AWAIT_FOR);
+ }
return parseForRest(forToken, token);
}
}
@@ -2206,13 +2320,13 @@ class Parser {
return token;
}
- Token parseForInRest(Token forToken, Token token) {
+ Token parseForInRest(Token awaitToken, Token forToken, Token token) {
assert(optional('in', token));
Token inKeyword = token;
token = parseExpression(token.next);
token = expect(')', token);
token = parseStatement(token);
- listener.endForIn(forToken, inKeyword, token);
+ listener.endForIn(awaitToken, forToken, inKeyword, token);
return token;
}
@@ -2251,6 +2365,15 @@ class Parser {
return expect('}', token);
}
+ Token parseAwaitExpression(Token token, bool allowCascades) {
+ Token awaitToken = token;
+ listener.beginAwaitExpression(awaitToken);
+ token = expect('await', token);
+ token = parseUnaryExpression(token, allowCascades);
+ listener.endAwaitExpression(awaitToken, token);
+ return token;
+ }
+
Token parseThrowExpression(Token token, bool allowCascades) {
Token throwToken = token;
listener.beginThrowExpression(throwToken);

Powered by Google App Engine
This is Rietveld 408576698