Skip to content

Commit

Permalink
fix await and yield in class field initializer
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea authored and marijnh committed Apr 24, 2021
1 parent 206ec4c commit 44ed579
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 10 deletions.
11 changes: 8 additions & 3 deletions acorn-loose/src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ lp.parseParenExpression = function() {
}

lp.parseMaybeAssign = function(noIn) {
if (this.toks.isContextual("yield")) {
// `yield` should be an identifier reference if it's not in generator functions.
if (this.inGenerator && this.toks.isContextual("yield")) {
let node = this.startNode()
this.next()
if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type !== tt.star && !this.tok.type.startsExpr)) {
Expand Down Expand Up @@ -580,28 +581,31 @@ lp.parseFunctionParams = function(params) {
}

lp.parseMethod = function(isGenerator, isAsync) {
let node = this.startNode(), oldInAsync = this.inAsync, oldInFunction = this.inFunction
let node = this.startNode(), oldInAsync = this.inAsync, oldInGenerator = this.inGenerator, oldInFunction = this.inFunction
this.initFunction(node)
if (this.options.ecmaVersion >= 6)
node.generator = !!isGenerator
if (this.options.ecmaVersion >= 8)
node.async = !!isAsync
this.inAsync = node.async
this.inGenerator = node.generator
this.inFunction = true
node.params = this.parseFunctionParams()
node.body = this.parseBlock()
this.toks.adaptDirectivePrologue(node.body.body)
this.inAsync = oldInAsync
this.inGenerator = oldInGenerator
this.inFunction = oldInFunction
return this.finishNode(node, "FunctionExpression")
}

lp.parseArrowExpression = function(node, params, isAsync) {
let oldInAsync = this.inAsync, oldInFunction = this.inFunction
let oldInAsync = this.inAsync, oldInGenerator = this.inGenerator, oldInFunction = this.inFunction
this.initFunction(node)
if (this.options.ecmaVersion >= 8)
node.async = !!isAsync
this.inAsync = node.async
this.inGenerator = false
this.inFunction = true
node.params = this.toAssignableList(params, true)
node.expression = this.tok.type !== tt.braceL
Expand All @@ -612,6 +616,7 @@ lp.parseArrowExpression = function(node, params, isAsync) {
this.toks.adaptDirectivePrologue(node.body.body)
}
this.inAsync = oldInAsync
this.inGenerator = oldInGenerator
this.inFunction = oldInFunction
return this.finishNode(node, "ArrowFunctionExpression")
}
Expand Down
1 change: 1 addition & 0 deletions acorn-loose/src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class LooseParser {
this.curLineStart = 0
this.nextLineStart = this.lineEnd(this.curLineStart) + 1
this.inAsync = false
this.inGenerator = false
this.inFunction = false
}

Expand Down
15 changes: 13 additions & 2 deletions acorn-loose/src/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,16 @@ lp.parseClass = function(isStatement) {
element.value = this.parseMethod(isGenerator, isAsync)
this.finishNode(element, "MethodDefinition")
} else {
element.value = this.eat(tt.eq) ? this.parseMaybeAssign() : null
if (this.eat(tt.eq)) {
const oldInAsync = this.inAsync, oldInGenerator = this.inGenerator
this.inAsync = false
this.inGenerator = false
element.value = this.parseMaybeAssign()
this.inAsync = oldInAsync
this.inGenerator = oldInGenerator
} else {
element.value = null
}
this.semicolon()
this.finishNode(element, "PropertyDefinition")
}
Expand Down Expand Up @@ -351,7 +360,7 @@ lp.parseClassElementName = function(element) {
}

lp.parseFunction = function(node, isStatement, isAsync) {
let oldInAsync = this.inAsync, oldInFunction = this.inFunction
let oldInAsync = this.inAsync, oldInGenerator = this.inGenerator, oldInFunction = this.inFunction
this.initFunction(node)
if (this.options.ecmaVersion >= 6) {
node.generator = this.eat(tt.star)
Expand All @@ -362,11 +371,13 @@ lp.parseFunction = function(node, isStatement, isAsync) {
if (this.tok.type === tt.name) node.id = this.parseIdent()
else if (isStatement === true) node.id = this.dummyIdent()
this.inAsync = node.async
this.inGenerator = node.generator
this.inFunction = true
node.params = this.parseFunctionParams()
node.body = this.parseBlock()
this.toks.adaptDirectivePrologue(node.body.body)
this.inAsync = oldInAsync
this.inGenerator = oldInGenerator
this.inFunction = oldInFunction
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
}
Expand Down
4 changes: 2 additions & 2 deletions acorn/src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ export class Parser {
}

get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }
get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }
get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }
get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 && !this.currentThisScope().inClassFieldInit }
get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 && !this.currentThisScope().inClassFieldInit }
get allowSuper() {
const {flags, inClassFieldInit} = this.currentThisScope()
return (flags & SCOPE_SUPER) > 0 || inClassFieldInit
Expand Down
73 changes: 73 additions & 0 deletions test/tests-class-features-2022.js
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,79 @@ test("class C { async\n get(){} }", {
"sourceType": "script"
}, {ecmaVersion: 13, loose: true})

// `await` is reference
test("async function f() { class C { aaa = await } }", {
"type": "Program",
"start": 0,
"end": 46,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 46,
"id": {
"type": "Identifier",
"start": 15,
"end": 16,
"name": "f"
},
"params": [],
"generator": false,
"expression": false,
"async": true,
"body": {
"type": "BlockStatement",
"start": 19,
"end": 46,
"body": [
{
"type": "ClassDeclaration",
"start": 21,
"end": 44,
"id": {
"type": "Identifier",
"start": 27,
"end": 28,
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 29,
"end": 44,
"body": [
{
"type": "PropertyDefinition",
"start": 31,
"end": 42,
"static": false,
"computed": false,
"key": {
"type": "Identifier",
"start": 31,
"end": 34,
"name": "aaa"
},
"value": {
"type": "Identifier",
"start": 37,
"end": 42,
"name": "await"
}
}
]
}
}
]
}
}
],
"sourceType": "script"
}, {ecmaVersion: 13})

// `yield` is keyword in strict mode
testFail("function* f() { class C { aaa = yield } }", "The keyword 'yield' is reserved (1:32)", {ecmaVersion: 13})

// old ecma version
testFail("class C { aaa }", "Unexpected token (1:14)", {ecmaVersion: 12})

Expand Down
3 changes: 0 additions & 3 deletions test/tests-harmony.js
Original file line number Diff line number Diff line change
Expand Up @@ -13217,7 +13217,6 @@ test("yield* 10", {
}
}, {
ecmaVersion: 6,
loose: false,
ranges: true,
locations: true
});
Expand Down Expand Up @@ -13280,7 +13279,6 @@ test("e => yield* 10", {
}
}, {
ecmaVersion: 6,
loose: false,
ranges: true,
locations: true
});
Expand Down Expand Up @@ -13352,7 +13350,6 @@ test("(function () { yield* 10 })", {
}
}, {
ecmaVersion: 6,
loose: false,
ranges: true,
locations: true
});
Expand Down

0 comments on commit 44ed579

Please sign in to comment.