From 98b1fb751878ad790e76c5b64f8ff597db4715d1 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 15 May 2019 10:34:47 -0700 Subject: [PATCH] Add support for public and private static class fields. [closes #801] --- src/acorn/parser/class-fields.js | 38 +++++++++++++++------ src/parse/lookahead.js | 37 ++++++++++++++++---- src/parser.js | 58 ++++++++++++++++++-------------- test/compiler-tests.mjs | 30 ++++++++++------- 4 files changed, 108 insertions(+), 55 deletions(-) diff --git a/src/acorn/parser/class-fields.js b/src/acorn/parser/class-fields.js index 759cac777..f1aade4e3 100644 --- a/src/acorn/parser/class-fields.js +++ b/src/acorn/parser/class-fields.js @@ -42,22 +42,38 @@ function init() { return Reflect.apply(func, this, args) } - const nextType = lookahead(this).type - - if (nextType === tt.parenL || - nextType === tt.star || - (nextType !== tt.braceR && - nextType !== tt.eq && - nextType !== tt.semi && - (this.isContextual("async") || - this.isContextual("get") || - this.isContextual("set") || - this.isContextual("static")))) { + const next = lookahead(this) + const nextType = next.type + + if (nextType === tt.parenL) { return Reflect.apply(func, this, args) } + if (nextType !== tt.braceR && + nextType !== tt.eq && + nextType !== tt.semi) { + if (this.isContextual("async") || + this.isContextual("get") || + this.isContextual("set")) { + return Reflect.apply(func, this, args) + } + + if (this.isContextual("static")) { + next.parsePropertyName(this.startNode()) + + if (next.type === tt.parenL) { + return Reflect.apply(func, this, args) + } + } + } + const node = this.startNode() + node.static = + nextType !== tt.braceR && + nextType !== tt.eq && + this.eatContextual("static") + this.parsePropertyName(node) node.value = this.eat(tt.eq) diff --git a/src/parse/lookahead.js b/src/parse/lookahead.js index ee8d446d6..07a8ce664 100644 --- a/src/parse/lookahead.js +++ b/src/parse/lookahead.js @@ -1,25 +1,50 @@ -import { Parser } from "../acorn.js" +import Parser from "../parser.js" import shared from "../shared.js" function init() { - const flyweight = new Parser({ - allowAwaitOutsideFunction: true, - allowReturnOutsideFunction: true, - ecmaVersion: 10 - }) + let flyweight function lookahead(parser) { + if (flyweight === void 0 || + flyweight === parser) { + flyweight = createFlyweight() + } + + flyweight.awaitIdentPos = parser.awaitIdentPos + flyweight.awaitPos = parser.awaitPos + flyweight.containsEsc = parser.containsEsc + flyweight.curLine = parser.curLine + flyweight.end = parser.end + flyweight.exprAllowed = parser.exprAllowed flyweight.inModule = parser.inModule flyweight.input = parser.input + flyweight.inTemplateElement = parser.inTemplateElement + flyweight.lastTokEnd = parser.lastTokEnd + flyweight.lastTokStart = parser.lastTokStart + flyweight.lineStart = parser.lineStart flyweight.pos = parser.pos + flyweight.potentialArrowAt = parser.potentialArrowAt + flyweight.sourceFile = parser.sourceFile + flyweight.start = parser.start flyweight.strict = parser.strict + flyweight.type = parser.type + flyweight.value = parser.value + flyweight.yieldPos = parser.yieldPos flyweight.next() return flyweight } + function createFlyweight() { + return Parser.create("", { + allowAwaitOutsideFunction: true, + allowReturnOutsideFunction: true, + ecmaVersion: 10 + }) + } + return lookahead } diff --git a/src/parser.js b/src/parser.js index 0ecb3c10b..cda154268 100644 --- a/src/parser.js +++ b/src/parser.js @@ -43,35 +43,11 @@ function init() { ]) const Parser = { + create, createOptions, defaultOptions, parse(code, options) { - options = Parser.createOptions(options) - - const { strict } = options - const parser = new AcornParser(options, code) - - acornParserBigInt.enable(parser) - acornParserClassFields.enable(parser) - acornParserErrorMessages.enable(parser) - acornParserFirstAwaitOutsideFunction.enable(parser) - acornParserFirstReturnOutsideFunction.enable(parser) - acornParserFunctionParamsStart.enable(parser) - acornParserHTMLComment.enable(parser) - acornParserImport.enable(parser) - acornParserNumericSeparator.enable(parser) - acornParserRaw.enable(parser) - acornParserTolerance.enable(parser) - acornParserTopLevel.enable(parser) - - if (strict !== void 0) { - parser.strict = !! strict - - if (! parser.strict) { - parser.reservedWords = reservedWordsRegExp - } - } - + const parser = Parser.create(code, options) const result = parser.parse() result.inModule = parser.inModule @@ -81,6 +57,36 @@ function init() { } } + function create(code, options) { + options = Parser.createOptions(options) + + const { strict } = options + const parser = new AcornParser(options, code) + + acornParserBigInt.enable(parser) + acornParserClassFields.enable(parser) + acornParserErrorMessages.enable(parser) + acornParserFirstAwaitOutsideFunction.enable(parser) + acornParserFirstReturnOutsideFunction.enable(parser) + acornParserFunctionParamsStart.enable(parser) + acornParserHTMLComment.enable(parser) + acornParserImport.enable(parser) + acornParserNumericSeparator.enable(parser) + acornParserRaw.enable(parser) + acornParserTolerance.enable(parser) + acornParserTopLevel.enable(parser) + + if (strict !== void 0) { + parser.strict = !! strict + + if (! parser.strict) { + parser.reservedWords = reservedWordsRegExp + } + } + + return parser + } + function createOptions(value) { const options = defaults({}, value, Parser.defaultOptions) diff --git a/test/compiler-tests.mjs b/test/compiler-tests.mjs index 9e85ec83f..09b2284d5 100644 --- a/test/compiler-tests.mjs +++ b/test/compiler-tests.mjs @@ -393,21 +393,27 @@ describe("compiler tests", () => { it("should parse class fields syntax", () => { const code = [ "export class A { a }", - 'export class B { b = "b" }', + "export class B { b = 1 }", "export class C { [c] }", - 'export class D { [d] = "d" }', - "export class E { #e }", - "export class F { async }", - "export class G { get }", - "export class H { set }", - "export class I { static }", - "export class J {", - ' #j= "j"', - " j() {", - " return this.#j", + "export class D { [d] = 1 }", + "export class E { static e }", + "export class F { static f = 1 }", + "export class G { static [g] }", + "export class H { static [h] = 1 }", + "export class I { #i }", + "export class J { static #j }", + "export class K { static #k = 1 }", + "export class L { async }", + "export class M { get }", + "export class N { set }", + "export class O { static }", + "export class P {", + ' #p = "p"', + " p() {", + " return this.#p", " }", "}", - "export class K {", + "export class Q {", " async = 1;", " get = 1", " set = 1",