Added ES6 classes support.
This commit is contained in:
parent
eadda16c42
commit
44a4f8c016
88
acorn.js
88
acorn.js
@ -281,6 +281,7 @@
|
||||
var _let = {keyword: "let"}, _const = {keyword: "const"};
|
||||
var _while = {keyword: "while", isLoop: true}, _with = {keyword: "with"}, _new = {keyword: "new", beforeExpr: true};
|
||||
var _this = {keyword: "this"};
|
||||
var _class = {keyword: "class"}, _extends = {keyword: "extends", beforeExpr: true}, _static = {keyword: "static"};
|
||||
|
||||
// The keywords that denote values.
|
||||
|
||||
@ -305,7 +306,8 @@
|
||||
"instanceof": {keyword: "instanceof", binop: 7, beforeExpr: true}, "this": _this,
|
||||
"typeof": {keyword: "typeof", prefix: true, beforeExpr: true},
|
||||
"void": {keyword: "void", prefix: true, beforeExpr: true},
|
||||
"delete": {keyword: "delete", prefix: true, beforeExpr: true}};
|
||||
"delete": {keyword: "delete", prefix: true, beforeExpr: true},
|
||||
"class": _class, "extends": _extends, "static": _static};
|
||||
|
||||
// Punctuation token types. Again, the `type` property is purely for debugging.
|
||||
|
||||
@ -424,7 +426,7 @@
|
||||
|
||||
var isEcma5AndLessKeyword = makePredicate(ecma5AndLessKeywords);
|
||||
|
||||
var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const");
|
||||
var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const class extends static");
|
||||
|
||||
var isKeyword = isEcma5AndLessKeyword;
|
||||
|
||||
@ -1217,6 +1219,7 @@
|
||||
case _do: return parseDoStatement(node);
|
||||
case _for: return parseForStatement(node);
|
||||
case _function: return parseFunctionStatement(node);
|
||||
case _class: return parseClass(node, true);
|
||||
case _if: return parseIfStatement(node);
|
||||
case _return: return parseReturnStatement(node);
|
||||
case _switch: return parseSwitchStatement(node);
|
||||
@ -1731,6 +1734,9 @@
|
||||
next();
|
||||
return parseFunction(node, false);
|
||||
|
||||
case _class:
|
||||
return parseClass(startNode(), false);
|
||||
|
||||
case _new:
|
||||
return parseNew();
|
||||
|
||||
@ -1776,7 +1782,7 @@
|
||||
if (options.allowTrailingCommas && eat(_braceR)) break;
|
||||
} else first = false;
|
||||
|
||||
var prop = startNode(), isGetSet = false, kind;
|
||||
var prop = startNode(), kind;
|
||||
prop.key = parsePropertyName();
|
||||
if (options.ecmaVersion >= 6) {
|
||||
prop.method = false;
|
||||
@ -1794,7 +1800,7 @@
|
||||
prop.value = func;
|
||||
} else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" &&
|
||||
(prop.key.name === "get" || prop.key.name === "set")) {
|
||||
isGetSet = sawGetSet = true;
|
||||
sawGetSet = true;
|
||||
kind = prop.kind = prop.key.name;
|
||||
prop.key = parsePropertyName();
|
||||
if (tokType !== _parenL) unexpected();
|
||||
@ -1805,33 +1811,38 @@
|
||||
prop.value = func;
|
||||
} else unexpected();
|
||||
|
||||
// getters and setters are not allowed to clash — either with
|
||||
// each other or with an init property — and in strict mode,
|
||||
// init properties are also not allowed to be repeated.
|
||||
|
||||
if (prop.key.type === "Identifier" && (strict || sawGetSet)) {
|
||||
for (var i = 0; i < node.properties.length; ++i) {
|
||||
var other = node.properties[i];
|
||||
if (other.key.name === prop.key.name) {
|
||||
var conflict = kind == other.kind || isGetSet && other.kind === "init" ||
|
||||
kind === "init" && (other.kind === "get" || other.kind === "set");
|
||||
if (conflict && !strict && kind === "init" && other.kind === "init") conflict = false;
|
||||
if (conflict) raise(prop.key.start, "Redefinition of property");
|
||||
}
|
||||
}
|
||||
}
|
||||
node.properties.push(finishNode(prop, "Property"));
|
||||
addProperty(node.properties, finishNode(prop, "Property"), sawGetSet, "init");
|
||||
}
|
||||
return finishNode(node, "ObjectExpression");
|
||||
}
|
||||
|
||||
// Add property to list with keeping in mind and checking that
|
||||
// object/class getters and setters are not allowed to clash —
|
||||
// either with each other or with an init property — and in
|
||||
// strict mode, init properties are also not allowed to be repeated.
|
||||
|
||||
function addProperty(props, current, sawGetSet, defaultKind) {
|
||||
if (current.key.type === "Identifier" && (strict || sawGetSet)) {
|
||||
var kind = current.kind, isGetSet = kind !== defaultKind;
|
||||
for (var i = 0; i < props.length; ++i) {
|
||||
var other = props[i];
|
||||
if (other.key.name === current.key.name && other.static === current.static) {
|
||||
var conflict = kind == other.kind || isGetSet && other.kind === defaultKind ||
|
||||
kind === defaultKind && (other.kind !== defaultKind);
|
||||
if (conflict && !strict && kind === defaultKind && other.kind === defaultKind) conflict = false;
|
||||
if (conflict) raise(current.key.start, "Redefinition of property");
|
||||
}
|
||||
}
|
||||
}
|
||||
props.push(current);
|
||||
}
|
||||
|
||||
function parsePropertyName() {
|
||||
if (tokType === _num || tokType === _string) return parseExprAtom();
|
||||
return parseIdent(true);
|
||||
}
|
||||
|
||||
// Parse a function declaration or literal (depending on the
|
||||
// `isStatement` parameter).
|
||||
// Initialize empty function node with given name.
|
||||
|
||||
function initFunction(node, id) {
|
||||
node.id = id || null;
|
||||
@ -1844,6 +1855,9 @@
|
||||
return node;
|
||||
}
|
||||
|
||||
// Parse a function declaration or literal (depending on the
|
||||
// `isStatement` parameter).
|
||||
|
||||
function parseFunction(node, isStatement, allowExpression) {
|
||||
initFunction(node, tokType === _name ? parseIdent() : isStatement ? unexpected() : null);
|
||||
parseFunctionParams(node);
|
||||
@ -1946,6 +1960,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a class declaration or literal (depending on the
|
||||
// `isStatement` parameter).
|
||||
|
||||
function parseClass(node, isStatement) {
|
||||
next();
|
||||
node.id = tokType === _name ? parseIdent() : isStatement ? unexpected() : null;
|
||||
node.superClass = eat(_extends) ? parseExpression() : null;
|
||||
var classBody = startNode(), sawGetSet = false;
|
||||
classBody.body = [];
|
||||
expect(_braceL);
|
||||
while (!eat(_braceR)) {
|
||||
var method = startNode();
|
||||
method.static = !!eat(_static);
|
||||
method.key = parseIdent(true);
|
||||
if (method.key.type === "Identifier" && (method.key.name === "get" || method.key.name === "set") && tokType === _name) {
|
||||
method.kind = method.key.name;
|
||||
method.key = parseIdent(true);
|
||||
sawGetSet = true;
|
||||
} else {
|
||||
method.kind = "";
|
||||
}
|
||||
method.value = parseFunction(startNode());
|
||||
setLoc(method.value, method.value.body);
|
||||
addProperty(classBody.body, finishNode(method, "MethodDefinition"), sawGetSet, "");
|
||||
eat(_semi);
|
||||
}
|
||||
node.body = finishNode(classBody, "ClassBody");
|
||||
return finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
|
||||
}
|
||||
|
||||
// Parses a comma-separated list of expressions, and returns them as
|
||||
// an array. `close` is the token type that ends the list, and
|
||||
// `allowEmpty` can be turned on to allow subsequent commas with
|
||||
|
||||
@ -9205,10 +9205,10 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
|
||||
end: {line: 1, column: 47}
|
||||
}
|
||||
},
|
||||
range: [40, 48],
|
||||
range: [40, 47],
|
||||
loc: {
|
||||
start: {line: 1, column: 40},
|
||||
end: {line: 1, column: 48}
|
||||
end: {line: 1, column: 47}
|
||||
}
|
||||
}],
|
||||
range: [38, 49],
|
||||
@ -9240,10 +9240,10 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
|
||||
end: {line: 1, column: 50}
|
||||
}
|
||||
},
|
||||
range: [15, 50],
|
||||
range: [14, 51],
|
||||
loc: {
|
||||
start: {line: 1, column: 15},
|
||||
end: {line: 1, column: 50}
|
||||
start: {line: 1, column: 14},
|
||||
end: {line: 1, column: 51}
|
||||
}
|
||||
},
|
||||
range: [14, 51],
|
||||
@ -9257,8 +9257,7 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
|
||||
loc: {
|
||||
start: {line: 1, column: 0},
|
||||
end: {line: 1, column: 51}
|
||||
},
|
||||
comments: []
|
||||
}
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
ranges: true,
|
||||
@ -9546,10 +9545,10 @@ test("\"use strict\"; (class A { static constructor() { super() }})", {
|
||||
end: {line: 1, column: 55}
|
||||
}
|
||||
},
|
||||
range: [48, 56],
|
||||
range: [48, 55],
|
||||
loc: {
|
||||
start: {line: 1, column: 48},
|
||||
end: {line: 1, column: 56}
|
||||
end: {line: 1, column: 55}
|
||||
}
|
||||
}],
|
||||
range: [46, 57],
|
||||
@ -9581,10 +9580,10 @@ test("\"use strict\"; (class A { static constructor() { super() }})", {
|
||||
end: {line: 1, column: 58}
|
||||
}
|
||||
},
|
||||
range: [15, 58],
|
||||
range: [14, 59],
|
||||
loc: {
|
||||
start: {line: 1, column: 15},
|
||||
end: {line: 1, column: 58}
|
||||
start: {line: 1, column: 14},
|
||||
end: {line: 1, column: 59}
|
||||
}
|
||||
},
|
||||
range: [14, 59],
|
||||
@ -9598,8 +9597,7 @@ test("\"use strict\"; (class A { static constructor() { super() }})", {
|
||||
loc: {
|
||||
start: {line: 1, column: 0},
|
||||
end: {line: 1, column: 59}
|
||||
},
|
||||
comments: []
|
||||
}
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
ranges: true,
|
||||
@ -10472,17 +10470,17 @@ test("class A { set foo(v) {} get foo() {} }", {
|
||||
locations: true
|
||||
});
|
||||
|
||||
testFail("class A { get foo() {} get foo() {} }", "Unexpected token (1:31)", {ecmaVersion: 6});
|
||||
testFail("class A { get foo() {} get foo() {} }", "Redefinition of property (1:27)", {ecmaVersion: 6});
|
||||
|
||||
testFail("class A { set foo(v) {} set foo(v) {} }", "Unexpected token (1:32)", {ecmaVersion: 6});
|
||||
testFail("class A { set foo(v) {} set foo(v) {} }", "Redefinition of property (1:28)", {ecmaVersion: 6});
|
||||
|
||||
testFail("class A { get foo() {} foo() {} }", "Unexpected token (1:27)", {ecmaVersion: 6});
|
||||
testFail("class A { get foo() {} foo() {} }", "Redefinition of property (1:23)", {ecmaVersion: 6});
|
||||
|
||||
testFail("class A { foo() {} get foo() {} }", "Unexpected token (1:27)", {ecmaVersion: 6});
|
||||
testFail("class A { foo() {} get foo() {} }", "Redefinition of property (1:23)", {ecmaVersion: 6});
|
||||
|
||||
testFail("class A { set foo(v) {} foo() {} }", "Unexpected token (1:28)", {ecmaVersion: 6});
|
||||
testFail("class A { set foo(v) {} foo() {} }", "Redefinition of property (1:24)", {ecmaVersion: 6});
|
||||
|
||||
testFail("class A { foo() {} set foo(v) {} }", "Unexpected token (1:27)", {ecmaVersion: 6});
|
||||
testFail("class A { foo() {} set foo(v) {} }", "Redefinition of property (1:23)", {ecmaVersion: 6});
|
||||
|
||||
// ES6: Computed Properties
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user