Parse for await (async of ...) (#13244)
This commit is contained in:
@@ -61,6 +61,7 @@ export const ErrorMessages = makeErrorTemplates(
|
||||
"'from' is not allowed as an identifier after 'export default'.",
|
||||
ForInOfLoopInitializer:
|
||||
"'%0' loop variable declaration may not have an initializer.",
|
||||
ForOfAsync: "The left-hand side of a for-of loop may not be 'async'.",
|
||||
ForOfLet: "The left-hand side of a for-of loop may not start with 'let'.",
|
||||
GeneratorInSingleStatementContext:
|
||||
"Generators can only be declared at the top level or inside a block.",
|
||||
|
||||
@@ -1032,7 +1032,16 @@ export default class ExpressionParser extends LValParser {
|
||||
true,
|
||||
);
|
||||
} else if (this.match(tt.name)) {
|
||||
return this.parseAsyncArrowUnaryFunction(id);
|
||||
// If the next token begins with "=", commit to parsing an async
|
||||
// arrow function. (Peeking ahead for "=" lets us avoid a more
|
||||
// expensive full-token lookahead on this common path.)
|
||||
if (this.lookaheadCharCode() === charCodes.equalsTo) {
|
||||
return this.parseAsyncArrowUnaryFunction(id);
|
||||
} else {
|
||||
// Otherwise, treat "async" as an identifier and let calling code
|
||||
// deal with the current tt.name token.
|
||||
return id;
|
||||
}
|
||||
} else if (this.match(tt._do)) {
|
||||
return this.parseDo(true);
|
||||
}
|
||||
|
||||
@@ -539,13 +539,33 @@ export default class StatementParser extends ExpressionParser {
|
||||
return this.parseFor(node, init);
|
||||
}
|
||||
|
||||
// Check whether the first token is possibly a contextual keyword, so that
|
||||
// we can forbid `for (async of` if this turns out to be a for-of loop.
|
||||
const startsWithUnescapedName =
|
||||
this.match(tt.name) && !this.state.containsEsc;
|
||||
|
||||
const refExpressionErrors = new ExpressionErrors();
|
||||
const init = this.parseExpression(true, refExpressionErrors);
|
||||
const isForOf = this.isContextual("of");
|
||||
if (isForOf || this.match(tt._in)) {
|
||||
if (isForOf && startsWithLet) {
|
||||
if (isForOf) {
|
||||
// Check for leading tokens that are forbidden in for-of loops:
|
||||
if (startsWithLet) {
|
||||
this.raise(init.start, Errors.ForOfLet);
|
||||
} else if (
|
||||
// `for await (async of []);` is allowed.
|
||||
awaitAt === -1 &&
|
||||
startsWithUnescapedName &&
|
||||
init.type === "Identifier" &&
|
||||
init.name === "async"
|
||||
) {
|
||||
// This catches the case where the `async` in `for (async of` was
|
||||
// parsed as an identifier. If it was parsed as the start of an async
|
||||
// arrow function (e.g. `for (async of => {} of []);`), the LVal check
|
||||
// further down will raise a more appropriate error.
|
||||
this.raise(init.start, Errors.ForOfAsync);
|
||||
}
|
||||
}
|
||||
if (isForOf || this.match(tt._in)) {
|
||||
this.toAssignable(init, /* isLHS */ true);
|
||||
const description = isForOf ? "for-of statement" : "for-in statement";
|
||||
this.checkLVal(init, description);
|
||||
|
||||
Reference in New Issue
Block a user