From 7cbe0f9ef347fd0d4c43b51792cc3fa1847ce062 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 4 May 2021 12:12:30 +0200 Subject: [PATCH] Add explicit exception for 'async of' not starting arrow in for init context FIX: Fix issue where the library couldn't parse 'for (async of ...)'. Closes #1031 --- acorn/src/expression.js | 7 +++++-- acorn/src/state.js | 1 + test/tests-asyncawait.js | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/acorn/src/expression.js b/acorn/src/expression.js index 0d1b3fa8a..9ee0951f9 100644 --- a/acorn/src/expression.js +++ b/acorn/src/expression.js @@ -124,8 +124,10 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { } let startPos = this.start, startLoc = this.startLoc - if (this.type === tt.parenL || this.type === tt.name) + if (this.type === tt.parenL || this.type === tt.name) { this.potentialArrowAt = this.start + this.forbidAsyncOfArrow = !!noIn + } let left = this.parseMaybeConditional(noIn, refDestructuringErrors) if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc) if (this.type.isAssign) { @@ -414,7 +416,8 @@ pp.parseExprAtom = function(refDestructuringErrors) { if (canBeArrow && !this.canInsertSemicolon()) { if (this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) - if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc) { + if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc && + (!this.forbidAsyncOfArrow || this.value !== "of" || this.containsEsc)) { id = this.parseIdent(false) if (this.canInsertSemicolon() || !this.eat(tt.arrow)) this.unexpected() diff --git a/acorn/src/state.js b/acorn/src/state.js index 6bfa56298..8545ce568 100644 --- a/acorn/src/state.js +++ b/acorn/src/state.js @@ -65,6 +65,7 @@ export class Parser { // Used to signify the start of a potential arrow function this.potentialArrowAt = -1 + this.forbidAsyncOfArrow = false // Positions to delayed-check that yield/await does not exist in default parameters. this.yieldPos = this.awaitPos = this.awaitIdentPos = 0 diff --git a/test/tests-asyncawait.js b/test/tests-asyncawait.js index 7b0f4107c..6cbbed757 100644 --- a/test/tests-asyncawait.js +++ b/test/tests-asyncawait.js @@ -3522,6 +3522,8 @@ test( test("({ async delete() {} })", {}, {ecmaVersion: 8}) +test("for (async of []) {}", {}, {ecmaVersion: 8}) + testFail("abc: async function a() {}", "Unexpected token (1:5)", {ecmaVersion: 8}) testFail("(async() => { await 4 ** 2 })()", "Unexpected token (1:22)", {ecmaVersion: 8})