diff --git a/acorn.js b/acorn.js index f82b9753fd..5389e3dbbd 100644 --- a/acorn.js +++ b/acorn.js @@ -2661,13 +2661,18 @@ } else { method['static'] = false; } - if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" && - (method.key.name === "get" || method.key.name === "set")) { - if (isGenerator) this.unexpected(); - method.kind = method.key.name; - this.parsePropertyName(method); - } else { - method.kind = ""; + method.kind = "method"; + if (!method.computed && !isGenerator) { + if (method.key.type === "Identifier") { + if (this.type !== tt.parenL && (method.key.name === "get" || method.key.name === "set")) { + method.kind = method.key.name; + this.parsePropertyName(method); + } else if (!method['static'] && method.key.name === "constructor") { + method.kind = "constructor"; + } + } else if (!method['static'] && method.key.type === "Literal" && method.key.value === "constructor") { + method.kind = "constructor"; + } } method.value = this.parseMethod(isGenerator); classBody.body.push(this.finishNode(method, "MethodDefinition")); diff --git a/acorn_loose.js b/acorn_loose.js index c936b4f0e9..94b5919bb6 100644 --- a/acorn_loose.js +++ b/acorn_loose.js @@ -456,7 +456,7 @@ return this.finishNode(node, "EmptyStatement"); case tt._class: - return this.parseObj(true, true); + return this.parseClass(true); case tt._import: return this.parseImport(); @@ -751,7 +751,7 @@ return this.parseObj(); case tt._class: - return this.parseObj(true); + return this.parseClass(); case tt._function: var node = this.startNode(); @@ -828,58 +828,29 @@ return this.finishNode(node, "TemplateLiteral"); }; - lp.parseObj = function(isClass, isStatement) { + lp.parseObj = function() { var node = this.startNode(); - if (isClass) { - this.next(); - if (this.tok.type === tt.name) node.id = this.parseIdent(); - else if (isStatement) node.id = this.dummyIdent(); - else node.id = null; - node.superClass = this.eat(tt._extends) ? this.parseExpression() : null; - node.body = this.startNode(); - node.body.body = []; - } else { - node.properties = []; - } + node.properties = []; this.pushCx(); var indent = this.curIndent + 1, line = this.curLineStart; this.eat(tt.braceL); if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; } while (!this.closes(tt.braceR, indent, line)) { - if (isClass && this.semicolon()) continue; var prop = this.startNode(), isGenerator, start; if (this.options.ecmaVersion >= 6) { - if (isClass) { - prop['static'] = false; - } else { - start = this.storeCurrentPos(); - prop.method = false; - prop.shorthand = false; - } + start = this.storeCurrentPos(); + prop.method = false; + prop.shorthand = false; isGenerator = this.eat(tt.star); } this.parsePropertyName(prop); if (isDummy(prop.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue; } - if (isClass) { - if (prop.key.type === "Identifier" && !prop.computed && prop.key.name === "static" && - (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { - prop['static'] = true; - isGenerator = this.eat(tt.star); - this.parsePropertyName(prop); - } else { - prop['static'] = false; - } - } - if (!isClass && this.eat(tt.colon)) { + if (this.eat(tt.colon)) { prop.kind = "init"; prop.value = this.parseMaybeAssign(); } else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) { - if (isClass) { - prop.kind = ""; - } else { - prop.kind = "init"; - prop.method = true; - } + prop.kind = "init"; + prop.method = true; prop.value = this.parseMethod(isGenerator); } else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && @@ -887,9 +858,6 @@ prop.kind = prop.key.name; this.parsePropertyName(prop); prop.value = this.parseMethod(false); - } else if (isClass) { - prop.kind = ""; - prop.value = this.parseMethod(isGenerator); } else { prop.kind = "init"; if (this.options.ecmaVersion >= 6) { @@ -907,13 +875,8 @@ } prop.shorthand = true; } - - if (isClass) { - node.body.body.push(this.finishNode(prop, "MethodDefinition")); - } else { - node.properties.push(this.finishNode(prop, "Property")); - this.eat(tt.comma); - } + node.properties.push(this.finishNode(prop, "Property")); + this.eat(tt.comma); } this.popCx(); if (!this.eat(tt.braceR)) { @@ -922,13 +885,67 @@ this.last.end = this.tok.start; if (this.options.locations) this.last.loc.end = this.tok.loc.start; } - if (isClass) { - this.semicolon(); - this.finishNode(node.body, "ClassBody"); - return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); - } else { - return this.finishNode(node, "ObjectExpression"); + return this.finishNode(node, "ObjectExpression"); + }; + + lp.parseClass = function(isStatement) { + var node = this.startNode(); + this.next(); + if (this.tok.type === tt.name) node.id = this.parseIdent(); + else if (isStatement) node.id = this.dummyIdent(); + else node.id = null; + node.superClass = this.eat(tt._extends) ? this.parseExpression() : null; + node.body = this.startNode(); + node.body.body = []; + this.pushCx(); + var indent = this.curIndent + 1, line = this.curLineStart; + this.eat(tt.braceL); + if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; } + while (!this.closes(tt.braceR, indent, line)) { + if (this.semicolon()) continue; + var method = this.startNode(), isGenerator, start; + if (this.options.ecmaVersion >= 6) { + method['static'] = false; + isGenerator = this.eat(tt.star); + } + this.parsePropertyName(method); + if (isDummy(method.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue; } + if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && + (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { + method['static'] = true; + isGenerator = this.eat(tt.star); + this.parsePropertyName(method); + } else { + method['static'] = false; + } + if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && + !method.computed && (method.key.name === "get" || method.key.name === "set") && + this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) { + method.kind = method.key.name; + this.parsePropertyName(method); + method.value = this.parseMethod(false); + } else { + if (!method.computed && !method['static'] && !isGenerator && ( + method.key.type === "Identifier" && method.key.name === "constructor" || + method.key.type === "Literal" && method.key.value === "constructor")) { + method.kind = "constructor"; + } else { + method.kind = "method"; + } + method.value = this.parseMethod(isGenerator); + } + node.body.body.push(this.finishNode(method, "MethodDefinition")); } + this.popCx(); + if (!this.eat(tt.braceR)) { + // If there is no closing brace, make the node span to the start + // of the next token (this is useful for Tern) + this.last.end = this.tok.start; + if (this.options.locations) this.last.loc.end = this.tok.loc.start; + } + this.semicolon(); + this.finishNode(node.body, "ClassBody"); + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); }; lp.parsePropertyName = function(prop) { diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 3fde855cfb..d9699915fb 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -6560,7 +6560,7 @@ test("class A {get() {}}", { end: {line: 1, column: 17} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 9}, @@ -6632,7 +6632,7 @@ test("class A { static get() {}}", { end: {line: 1, column: 25} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 10}, @@ -7027,7 +7027,7 @@ test("class A {set(v) {};}", { end: {line: 1, column: 18} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 9}, @@ -7106,7 +7106,7 @@ test("class A { static set(v) {};}", { end: {line: 1, column: 26} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 10}, @@ -7207,7 +7207,7 @@ test("class A {*gen(v) { yield v; }}", { end: {line: 1, column: 29} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 9}, @@ -7308,7 +7308,7 @@ test("class A { static *gen(v) { yield v; }}", { end: {line: 1, column: 37} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 10}, @@ -7421,7 +7421,7 @@ test("\"use strict\"; (class A {constructor() { super() }})", { end: {line: 1, column: 49} } }, - kind: "", + kind: "constructor", static: false, loc: { start: {line: 1, column: 24}, @@ -7454,6 +7454,36 @@ test("\"use strict\"; (class A {constructor() { super() }})", { locations: true }); +test("class A {'constructor'() {}}", { + type: "Program", + body: [{ + type: "ClassDeclaration", + id: {type: "Identifier", name: "A"}, + superClass: null, + body: { + type: "ClassBody", + body: [{ + type: "MethodDefinition", + computed: false, + key: {type: "Literal", value: "constructor"}, + static: false, + kind: "constructor", + value: { + type: "FunctionExpression", + id: null, + generator: false, + expression: false, + params: [], + body: { + type: "BlockStatement", + body: [] + } + } + }] + } + }] +}, {ecmaVersion: 6}); + test("class A {static foo() {}}", { type: "Program", body: [{ @@ -7499,7 +7529,7 @@ test("class A {static foo() {}}", { end: {line: 1, column: 24} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 9}, @@ -7572,7 +7602,7 @@ test("class A {foo() {} static bar() {}}", { end: {line: 1, column: 17} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 9}, @@ -7609,7 +7639,7 @@ test("class A {foo() {} static bar() {}}", { end: {line: 1, column: 33} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 18}, @@ -7723,7 +7753,7 @@ test("\"use strict\"; (class A { static constructor() { super() }})", { end: {line: 1, column: 57} } }, - kind: "", + kind: "method", static: true, loc: { start: {line: 1, column: 25}, @@ -7802,7 +7832,7 @@ test("class A { foo() {} bar() {}}", { end: {line: 1, column: 18} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 10}, @@ -7839,7 +7869,7 @@ test("class A { foo() {} bar() {}}", { end: {line: 1, column: 27} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 19}, @@ -8450,7 +8480,7 @@ test("class A { static [foo]() {} }", { }, name: "foo" }, - kind: "", + kind: "method", value: { type: "FunctionExpression", loc: { @@ -8717,7 +8747,7 @@ test("class A { foo() {} get foo() {} }",{ }, name: "foo" }, - kind: "", + kind: "method", value: { type: "FunctionExpression", loc: { @@ -9582,7 +9612,7 @@ test("class A {[x]() {}}", { }, name: "x" }, - kind: "", + kind: "method", value: { type: "FunctionExpression", loc: { @@ -10324,7 +10354,7 @@ test("(class {f({x} = {x: 10}) {}})", { end: {line: 1, column: 27} } }, - kind: "", + kind: "method", static: false, loc: { start: {line: 1, column: 8}, @@ -14947,7 +14977,7 @@ test("class A { static() {} }", { name: "static" }, static: false, - kind: "", + kind: "method", value: { type: "FunctionExpression", range: [16, 21], @@ -15044,7 +15074,7 @@ test("class A { *static() {} }", { name: "static" }, static: false, - kind: "", + kind: "method", value: { type: "FunctionExpression", range: [17, 22],