diff --git a/src/acorn-ext/async-generator.js b/src/acorn-ext/async-generator.js index fa5b67672..d1493b73c 100644 --- a/src/acorn-ext/async-generator.js +++ b/src/acorn-ext/async-generator.js @@ -10,6 +10,7 @@ import { types as tt } from "../vendor/acorn/src/tokentype.js" const loopLabel = { kind: "loop" } function enable(parser) { + parser.parseClass = parseClass parser.parseForIn = parseForIn parser.parseForStatement = parseForStatement parser.parseFunction = parseFunction @@ -17,6 +18,87 @@ function enable(parser) { return parser } +function parseClass(node, isStatement) { + this.next() + + this.parseClassId(node, isStatement) + this.parseClassSuper(node) + let classBody = this.startNode() + let hadConstructor = false + classBody.body = [] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (this.eat(tt.semi)) { + continue + } + let method = this.startNode() + let isGenerator = this.eat(tt.star) + let isAsync = false + let isMaybeStatic = this.type === tt.name && this.value === "static" + this.parsePropertyName(method) + method.static = isMaybeStatic && this.type !== tt.parenL + if (method.static) { + if (isGenerator) { + this.unexpected() + } + isGenerator = this.eat(tt.star) + this.parsePropertyName(method) + } + if (this.options.ecmaVersion >= 8 && !isGenerator && !method.computed && + method.key.type === "Identifier" && method.key.name === "async" && this.type !== tt.parenL && + !this.canInsertSemicolon()) { + isAsync = true + isGenerator = this.eat(tt.star) + this.parsePropertyName(method) + } + method.kind = "method" + let isGetSet = false + if (!method.computed) { + let {key} = method + if (!isGenerator && !isAsync && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) { + isGetSet = true + method.kind = key.name + key = this.parsePropertyName(method) + } + if (!method.static && (key.type === "Identifier" && key.name === "constructor" || + key.type === "Literal" && key.value === "constructor")) { + if (hadConstructor) { + this.raise(key.start, "Duplicate constructor in the same class") + } + if (isGetSet) { + this.raise(key.start, "Constructor can't have get/set modifier") + } + if (isGenerator) { + this.raise(key.start, "Constructor can't be a generator") + } + if (isAsync) { + this.raise(key.start, "Constructor can't be an async method") + } + method.kind = "constructor" + hadConstructor = true + } + } + this.parseClassMethod(classBody, method, isGenerator, isAsync) + if (isGetSet) { + let paramCount = method.kind === "get" ? 0 : 1 + if (method.value.params.length !== paramCount) { + let start = method.value.start + if (method.kind === "get") { + this.raiseRecoverable(start, "getter should have no params") + } else { + this.raiseRecoverable(start, "setter should have exactly one param") + } + } else { + if (method.kind === "set" && method.value.params[0].type === "RestElement") { + this.raiseRecoverable(method.value.params[0].start, "Setter cannot use rest params") + } + } + } + } + node.body = this.finishNode(classBody, "ClassBody") + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") +} + function parseForIn(node, init, forAwait) { const type = forAwait ? "ForAwaitStatement" diff --git a/test/fixture/export/async-generators.mjs b/test/fixture/export/async-generators.mjs index 992b6bcee..8b99228a7 100644 --- a/test/fixture/export/async-generators.mjs +++ b/test/fixture/export/async-generators.mjs @@ -4,3 +4,8 @@ const b = { async *b() { } } + +class C { + async *c() { + } +}