resync with upstream acorn

This commit is contained in:
Sebastian McKenzie 2015-06-20 23:28:49 +01:00
parent 4ac33d62af
commit 4f08a77230
21 changed files with 296 additions and 166 deletions

View File

@ -29,14 +29,23 @@ const pp = Parser.prototype
// strict mode, init properties are also not allowed to be repeated. // strict mode, init properties are also not allowed to be repeated.
pp.checkPropClash = function(prop, propHash) { pp.checkPropClash = function(prop, propHash) {
if (this.options.ecmaVersion >= 6) return if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand))
return
let key = prop.key, name let key = prop.key, name
switch (key.type) { switch (key.type) {
case "Identifier": name = key.name; break case "Identifier": name = key.name; break
case "Literal": name = String(key.value); break case "Literal": name = String(key.value); break
default: return default: return
} }
let kind = prop.kind || "init", other let kind = prop.kind
if (this.options.ecmaVersion >= 6) {
if (name === "__proto__" && kind === "init") {
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
propHash.proto = true
}
return
}
let other
if (has(propHash, name)) { if (has(propHash, name)) {
other = propHash[name] other = propHash[name]
let isGetSet = kind !== "init" let isGetSet = kind !== "init"
@ -260,8 +269,10 @@ pp.parseNoCallExpr = function() {
pp.parseExprAtom = function(refShorthandDefaultPos) { pp.parseExprAtom = function(refShorthandDefaultPos) {
let node, canBeArrow = this.potentialArrowAt == this.start let node, canBeArrow = this.potentialArrowAt == this.start
switch (this.type) { switch (this.type) {
case tt._this:
case tt._super: case tt._super:
if (!this.inFunction)
this.raise(this.start, "'super' outside of function or class")
case tt._this:
let type = this.type === tt._this ? "ThisExpression" : "Super" let type = this.type === tt._this ? "ThisExpression" : "Super"
node = this.startNode() node = this.startNode()
this.next() this.next()
@ -609,6 +620,14 @@ pp.parseObjPropValue = function (prop, start, isGenerator, isAsync, isPattern, r
prop.kind = prop.key.name prop.kind = prop.key.name
this.parsePropertyName(prop) this.parsePropertyName(prop)
prop.value = this.parseMethod(false) prop.value = this.parseMethod(false)
let paramCount = prop.kind === "get" ? 0 : 1
if (prop.value.params.length !== paramCount) {
let start = prop.value.start
if (prop.kind === "get")
this.raise(start, "getter should have no params");
else
this.raise(start, "setter should have exactly one param")
}
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init" prop.kind = "init"
if (isPattern) { if (isPattern) {
@ -634,12 +653,12 @@ pp.parsePropertyName = function(prop) {
prop.computed = true prop.computed = true
prop.key = this.parseMaybeAssign() prop.key = this.parseMaybeAssign()
this.expect(tt.bracketR) this.expect(tt.bracketR)
return return prop.key
} else { } else {
prop.computed = false prop.computed = false
} }
} }
prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true) return prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
} }
// Initialize empty function node. // Initialize empty function node.

View File

@ -35,6 +35,7 @@ pp.toAssignable = function(node, isBinding) {
case "AssignmentExpression": case "AssignmentExpression":
if (node.operator === "=") { if (node.operator === "=") {
node.type = "AssignmentPattern" node.type = "AssignmentPattern"
delete node.operator
} else { } else {
this.raise(node.left.end, "Only '=' operator can be used for specifying default value.") this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
} }
@ -171,7 +172,7 @@ pp.checkLVal = function(expr, isBinding, checkClashes) {
break break
case "ObjectPattern": case "ObjectPattern":
for (let i = 0; i < expr.properties.length; i++) { for (let i = 0; i < expr.properties.length; i++) {
var prop = expr.properties[i]; var prop = expr.properties[i];
if (prop.type === "Property") prop = prop.value; if (prop.type === "Property") prop = prop.value;
this.checkLVal(prop, isBinding, checkClashes) this.checkLVal(prop, isBinding, checkClashes)
@ -194,6 +195,10 @@ pp.checkLVal = function(expr, isBinding, checkClashes) {
this.checkLVal(expr.argument, isBinding, checkClashes) this.checkLVal(expr.argument, isBinding, checkClashes)
break break
case "ParenthesizedExpression":
this.checkLVal(expr.expression, isBinding, checkClashes)
break
default: default:
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue") this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
} }

View File

@ -1,5 +1,6 @@
import {reservedWords, keywords} from "./identifier" import {reservedWords, keywords} from "./identifier"
import {types as tt, lineBreak} from "./tokentype" import {types as tt} from "./tokentype"
import {lineBreak} from "./whitespace"
export function Parser(options, input, startPos) { export function Parser(options, input, startPos) {
this.options = options this.options = options

View File

@ -347,7 +347,14 @@ pp.parseLabeledStatement = function(node, maybeName, expr) {
for (let i = 0; i < this.labels.length; ++i) for (let i = 0; i < this.labels.length; ++i)
if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared") if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared")
let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null
this.labels.push({name: maybeName, kind: kind}) for (let i = this.labels.length - 1; i >= 0; i--) {
let label = this.labels[i]
if (label.statementStart == node.start) {
label.statementStart = this.start;
label.kind = kind;
} else break;
}
this.labels.push({name: maybeName, kind: kind, statementStart: this.start})
node.body = this.parseStatement(true) node.body = this.parseStatement(true)
this.labels.pop() this.labels.pop()
node.label = expr node.label = expr
@ -466,6 +473,7 @@ pp.parseClass = function(node, isStatement) {
this.parseClassId(node, isStatement) this.parseClassId(node, isStatement)
this.parseClassSuper(node) this.parseClassSuper(node)
var classBody = this.startNode() var classBody = this.startNode()
let hadConstructor = false
classBody.body = [] classBody.body = []
this.expect(tt.braceL) this.expect(tt.braceL)
let decorators = [] let decorators = []
@ -480,16 +488,14 @@ pp.parseClass = function(node, isStatement) {
method.decorators = decorators method.decorators = decorators
decorators = [] decorators = []
} }
let isMaybeStatic = this.type === tt.name && this.value === "static"
var isGenerator = this.eat(tt.star), isAsync = false var isGenerator = this.eat(tt.star), isAsync = false
this.parsePropertyName(method) this.parsePropertyName(method)
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" && method.static = isMaybeStatic && this.type !== tt.parenL
method.key.name === "static") { if (method.static) {
if (isGenerator) this.unexpected() if (isGenerator) this.unexpected()
method['static'] = true
isGenerator = this.eat(tt.star) isGenerator = this.eat(tt.star)
this.parsePropertyName(method) this.parsePropertyName(method)
} else {
method['static'] = false
} }
if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) { if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) {
classBody.body.push(this.parseClassProperty(method)) classBody.body.push(this.parseClassProperty(method))
@ -500,23 +506,39 @@ pp.parseClass = function(node, isStatement) {
isAsync = true isAsync = true
this.parsePropertyName(method) this.parsePropertyName(method)
} }
let isGetSet = false
method.kind = "method" method.kind = "method"
if (!method.computed && !isGenerator && !isAsync) { if (!method.computed) {
if (method.key.type === "Identifier") { let {key} = method
if (this.type !== tt.parenL && (method.key.name === "get" || method.key.name === "set")) { if (!isAsync && !isGenerator && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) {
method.kind = method.key.name isGetSet = true
this.parsePropertyName(method) method.kind = key.name
} else if (!method['static'] && method.key.name === "constructor") { key = this.parsePropertyName(method)
method.kind = "constructor" }
} if (!method.static && (key.type === "Identifier" && key.name === "constructor" ||
} else if (!method['static'] && method.key.type === "Literal" && method.key.value === "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 function")
method.kind = "constructor" method.kind = "constructor"
hadConstructor = true
} }
} }
if (method.kind === "constructor" && method.decorators) { if (method.kind === "constructor" && method.decorators) {
this.raise(method.start, "You can't attach decorators to a class constructor") this.raise(method.start, "You can't attach decorators to a class constructor")
} }
this.parseClassMethod(classBody, method, isGenerator, isAsync) 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.raise(start, "getter should have no params");
else
this.raise(start, "setter should have exactly one param")
}
}
} }
if (decorators.length) { if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no method"); this.raise(this.start, "You have trailing decorators with no method");

View File

@ -25,6 +25,9 @@ export class Token {
const pp = Parser.prototype const pp = Parser.prototype
// Are we running under Rhino?
const isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]"
// Move to the next token // Move to the next token
pp.next = function() { pp.next = function() {
@ -430,23 +433,30 @@ pp.readRegexp = function() {
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
// perfectly valid pattern that is equivalent to `[a-b]`, but it would // perfectly valid pattern that is equivalent to `[a-b]`, but it would
// be replaced by `[x-b]` which throws an error. // be replaced by `[x-b]` which throws an error.
tmp = tmp.replace(/\\u([a-fA-F0-9]{4})|\\u\{([0-9a-fA-F]+)\}|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x") tmp = tmp.replace(/\\u\{([0-9a-fA-F]+)\}/g, (match, code, offset) => {
code = Number("0x" + code)
if (code > 0x10FFFF) this.raise(start + offset + 3, "Code point out of bounds")
return "x"
});
tmp = tmp.replace(/\\u([a-fA-F0-9]{4})|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x")
} }
} }
// Detect invalid regular expressions. // Detect invalid regular expressions.
try { let value = null
new RegExp(tmp) // Rhino's regular expression parser is flaky and throws uncatchable exceptions,
} catch (e) { // so don't do detection if we are running under Rhino
if (e instanceof SyntaxError) this.raise(start, "Error parsing regular expression: " + e.message) if (!isRhino) {
this.raise(e) try {
} new RegExp(tmp)
// Get a regular expression object for this pattern-flag pair, or `null` in } catch (e) {
// case the current environment doesn't support the flags it uses. if (e instanceof SyntaxError) this.raise(start, "Error parsing regular expression: " + e.message)
let value this.raise(e)
try { }
value = new RegExp(content, mods) // Get a regular expression object for this pattern-flag pair, or `null` in
} catch (err) { // case the current environment doesn't support the flags it uses.
value = null try {
value = new RegExp(content, mods)
} catch (err) {}
} }
return this.finishToken(tt.regexp, {pattern: content, flags: mods, value: value}) return this.finishToken(tt.regexp, {pattern: content, flags: mods, value: value})
} }
@ -514,10 +524,10 @@ pp.readCodePoint = function() {
if (ch === 123) { if (ch === 123) {
if (this.options.ecmaVersion < 6) this.unexpected() if (this.options.ecmaVersion < 6) this.unexpected()
++this.pos let codePos = ++this.pos
code = this.readHexChar(this.input.indexOf('}', this.pos) - this.pos) code = this.readHexChar(this.input.indexOf('}', this.pos) - this.pos)
++this.pos ++this.pos
if (code > 0x10FFFF) this.unexpected() if (code > 0x10FFFF) this.raise(codePos, "Code point out of bounds")
} else { } else {
code = this.readHexChar(4) code = this.readHexChar(4)
} }
@ -539,7 +549,7 @@ pp.readString = function(quote) {
if (ch === quote) break if (ch === quote) break
if (ch === 92) { // '\' if (ch === 92) { // '\'
out += this.input.slice(chunkStart, this.pos) out += this.input.slice(chunkStart, this.pos)
out += this.readEscapedChar() out += this.readEscapedChar(false)
chunkStart = this.pos chunkStart = this.pos
} else { } else {
if (isNewLine(ch)) this.raise(this.start, "Unterminated string constant") if (isNewLine(ch)) this.raise(this.start, "Unterminated string constant")
@ -572,7 +582,7 @@ pp.readTmplToken = function() {
} }
if (ch === 92) { // '\' if (ch === 92) { // '\'
out += this.input.slice(chunkStart, this.pos) out += this.input.slice(chunkStart, this.pos)
out += this.readEscapedChar() out += this.readEscapedChar(true)
chunkStart = this.pos chunkStart = this.pos
} else if (isNewLine(ch)) { } else if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.pos) out += this.input.slice(chunkStart, this.pos)
@ -600,42 +610,46 @@ pp.readTmplToken = function() {
// Used to read escaped characters // Used to read escaped characters
pp.readEscapedChar = function() { pp.readEscapedChar = function(inTemplate) {
let ch = this.input.charCodeAt(++this.pos) let ch = this.input.charCodeAt(++this.pos)
let octal = /^[0-7]+/.exec(this.input.slice(this.pos, this.pos + 3))
if (octal) octal = octal[0]
while (octal && parseInt(octal, 8) > 255) octal = octal.slice(0, -1)
if (octal === "0") octal = null
++this.pos ++this.pos
if (octal) { switch (ch) {
if (this.strict) this.raise(this.pos - 2, "Octal literal in strict mode") case 110: return "\n"; // 'n' -> '\n'
this.pos += octal.length - 1 case 114: return "\r"; // 'r' -> '\r'
return String.fromCharCode(parseInt(octal, 8)) case 120: return String.fromCharCode(this.readHexChar(2)); // 'x'
} else { case 117: return codePointToString(this.readCodePoint()); // 'u'
switch (ch) { case 116: return "\t"; // 't' -> '\t'
case 110: return "\n"; // 'n' -> '\n' case 98: return "\b"; // 'b' -> '\b'
case 114: return "\r"; // 'r' -> '\r' case 118: return "\u000b"; // 'v' -> '\u000b'
case 120: return String.fromCharCode(this.readHexChar(2)); // 'x' case 102: return "\f"; // 'f' -> '\f'
case 117: return codePointToString(this.readCodePoint()); // 'u' case 13: if (this.input.charCodeAt(this.pos) === 10) ++this.pos; // '\r\n'
case 116: return "\t"; // 't' -> '\t' case 10: // ' \n'
case 98: return "\b"; // 'b' -> '\b' if (this.options.locations) { this.lineStart = this.pos; ++this.curLine }
case 118: return "\u000b"; // 'v' -> '\u000b' return ""
case 102: return "\f"; // 'f' -> '\f' default:
case 48: return "\0"; // 0 -> '\0' if (ch >= 48 && ch <= 55) {
case 13: if (this.input.charCodeAt(this.pos) === 10) ++this.pos; // '\r\n' let octalStr = this.input.substr(this.pos - 1, 3).match(/^[0-7]+/)[0]
case 10: // ' \n' let octal = parseInt(octalStr, 8)
if (this.options.locations) { this.lineStart = this.pos; ++this.curLine } if (octal > 255) {
return "" octalStr = octalStr.slice(0, -1)
default: return String.fromCharCode(ch) octal = parseInt(octalStr, 8)
}
if (octal > 0 && (this.strict || inTemplate)) {
this.raise(this.pos - 2, "Octal literal in strict mode")
}
this.pos += octalStr.length - 1
return String.fromCharCode(octal)
} }
return String.fromCharCode(ch)
} }
} }
// Used to read character escape sequences ('\x', '\u', '\U'). // Used to read character escape sequences ('\x', '\u', '\U').
pp.readHexChar = function(len) { pp.readHexChar = function(len) {
let codePos = this.pos
let n = this.readInt(16, len) let n = this.readInt(16, len)
if (n === null) this.raise(this.start, "Bad character escape sequence") if (n === null) this.raise(codePos, "Bad character escape sequence")
return n return n
} }

View File

@ -5,9 +5,7 @@ export const MESSAGES = {
JSXNamespacedTags: "Namespace tags are not supported. ReactJSX is not XML.", JSXNamespacedTags: "Namespace tags are not supported. ReactJSX is not XML.",
classesIllegalBareSuper: "Illegal use of bare super", classesIllegalBareSuper: "Illegal use of bare super",
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead", classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
classesIllegalConstructorKind: "Illegal kind for constructor method",
scopeDuplicateDeclaration: "Duplicate declaration $1", scopeDuplicateDeclaration: "Duplicate declaration $1",
settersInvalidParamLength: "Setters must have exactly one parameter",
settersNoRest: "Setters aren't allowed to have a rest", settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head", noAssignmentsInForHead: "No assignments allowed in for-in/of head",
expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier", expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier",

View File

@ -14,28 +14,8 @@ export var visitor = {
} }
}, },
MethodDefinition(node) {
if (node.kind !== "constructor") {
// get constructor() {}
var isConstructor = !node.computed && t.isIdentifier(node.key, { name: "constructor" });
// get ["constructor"]() {}
isConstructor = isConstructor || t.isLiteral(node.key, { value: "constructor" });
if (isConstructor) {
throw this.errorWithNode(messages.get("classesIllegalConstructorKind"));
}
}
visitor.Property.apply(this, arguments);
},
Property(node, parent, scope, file) { Property(node, parent, scope, file) {
if (node.kind === "set") { if (node.kind === "set") {
if (node.value.params.length !== 1) {
throw file.errorWithNode(node.value, messages.get("settersInvalidParamLength"));
}
var first = node.value.params[0]; var first = node.value.params[0];
if (t.isRestElement(first)) { if (t.isRestElement(first)) {
throw file.errorWithNode(first, messages.get("settersNoRest")); throw file.errorWithNode(first, messages.get("settersNoRest"));

View File

@ -2299,7 +2299,7 @@ test("class Foo { @foo bar() {} }", {
features: { "es7.decorators": true } features: { "es7.decorators": true }
}); });
test("class Foo { @foo set bar() {} }", { test("class Foo { @foo set bar(f) {} }", {
"start": 0, "start": 0,
"body": [ "body": [
{ {
@ -2343,29 +2343,32 @@ test("class Foo { @foo set bar() {} }", {
"id": null, "id": null,
"generator": false, "generator": false,
"expression": false, "expression": false,
"params": [], "params": [{
"type": "Identifier",
"name": "f"
}],
"body": { "body": {
"start": 27, "start": 28,
"body": [], "body": [],
"type": "BlockStatement", "type": "BlockStatement",
"end": 29 "end": 30
}, },
"type": "FunctionExpression", "type": "FunctionExpression",
"end": 29 "end": 30
}, },
"type": "MethodDefinition", "type": "MethodDefinition",
"end": 29 "end": 30
} }
], ],
"type": "ClassBody", "type": "ClassBody",
"end": 31 "end": 32
}, },
"type": "ClassDeclaration", "type": "ClassDeclaration",
"end": 31 "end": 32
} }
], ],
"type": "Program", "type": "Program",
"end": 31 "end": 32
}, { }, {
ecmaVersion: 6, ecmaVersion: 6,
features: { "es7.decorators": true } features: { "es7.decorators": true }

View File

@ -1,4 +1,5 @@
/* /*
Copyright (C) 2015 Ingvar Stepanyan <me@rreverser.com>
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl> Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
@ -6,7 +7,6 @@
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com> Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2011 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2011 Yusuke Suzuki <utatane.tea@gmail.com>
Copyright (C) 2011 Arpad Borsos <arpad.borsos@googlemail.com> Copyright (C) 2011 Arpad Borsos <arpad.borsos@googlemail.com>
Copyright (C) 2014 Ingvar Stepanyan <me@rreverser.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -877,7 +877,7 @@ test("`\n\r\n\r`", {
locations: true locations: true
}); });
test("`\\u{000042}\\u0042\\x42u0\\102\\A`", { test("`\\u{000042}\\u0042\\x42u0\\A`", {
type: "Program", type: "Program",
body: [{ body: [{
type: "ExpressionStatement", type: "ExpressionStatement",
@ -885,27 +885,27 @@ test("`\\u{000042}\\u0042\\x42u0\\102\\A`", {
type: "TemplateLiteral", type: "TemplateLiteral",
quasis: [{ quasis: [{
type: "TemplateElement", type: "TemplateElement",
value: {raw: "\\u{000042}\\u0042\\x42u0\\102\\A", cooked: "BBBu0BA"}, value: {raw: "\\u{000042}\\u0042\\x42u0\\A", cooked: "BBBu0A"},
tail: true, tail: true,
loc: { loc: {
start: {line: 1, column: 1}, start: {line: 1, column: 1},
end: {line: 1, column: 29} end: {line: 1, column: 25}
} }
}], }],
expressions: [], expressions: [],
loc: { loc: {
start: {line: 1, column: 0}, start: {line: 1, column: 0},
end: {line: 1, column: 30} end: {line: 1, column: 26}
} }
}, },
loc: { loc: {
start: {line: 1, column: 0}, start: {line: 1, column: 0},
end: {line: 1, column: 30} end: {line: 1, column: 26}
} }
}], }],
loc: { loc: {
start: {line: 1, column: 0}, start: {line: 1, column: 0},
end: {line: 1, column: 30} end: {line: 1, column: 26}
} }
}, { }, {
ecmaVersion: 6, ecmaVersion: 6,
@ -1714,7 +1714,7 @@ test("([a, , b]) => 42", {
testFail("([a.a]) => 42", "Assigning to rvalue (1:2)", {ecmaVersion: 6}); testFail("([a.a]) => 42", "Assigning to rvalue (1:2)", {ecmaVersion: 6});
testFail("console.log(typeof () => {});", "Unexpected token (1:20)", {ecmaVersion: 6}); testFail("console.log(typeof () => {});", "Unexpected token (1:20)", {ecmaVersion: 6})
test("(x=1) => x * x", { test("(x=1) => x * x", {
type: "Program", type: "Program",
@ -7223,6 +7223,12 @@ test("class A {'constructor'() {}}", {
}] }]
}, {ecmaVersion: 6}); }, {ecmaVersion: 6});
testFail("class A { constructor() {} 'constructor'() }", "Duplicate constructor in the same class (1:27)", {ecmaVersion: 6});
testFail("class A { get constructor() {} }", "Constructor can't have get/set modifier (1:14)", {ecmaVersion: 6});
testFail("class A { *constructor() {} }", "Constructor can't be a generator (1:11)", {ecmaVersion: 6});
test("class A {static foo() {}}", { test("class A {static foo() {}}", {
type: "Program", type: "Program",
body: [{ body: [{
@ -13641,21 +13647,21 @@ testFail("0B18", "Unexpected token (1:3)", {ecmaVersion: 6});
testFail("0B12", "Unexpected token (1:3)", {ecmaVersion: 6}); testFail("0B12", "Unexpected token (1:3)", {ecmaVersion: 6});
testFail("\"\\u{110000}\"", "Unexpected token (1:0)", {ecmaVersion: 6}); testFail("\"\\u{110000}\"", "Code point out of bounds (1:4)", {ecmaVersion: 6});
testFail("\"\\u{}\"", "Bad character escape sequence (1:0)", {ecmaVersion: 6}); testFail("\"\\u{}\"", "Bad character escape sequence (1:4)", {ecmaVersion: 6});
testFail("\"\\u{FFFF\"", "Bad character escape sequence (1:0)", {ecmaVersion: 6}); testFail("\"\\u{FFFF\"", "Bad character escape sequence (1:4)", {ecmaVersion: 6});
testFail("\"\\u{FFZ}\"", "Bad character escape sequence (1:0)", {ecmaVersion: 6}); testFail("\"\\u{FFZ}\"", "Bad character escape sequence (1:4)", {ecmaVersion: 6});
testFail("[v] += ary", "Assigning to rvalue (1:0)", {ecmaVersion: 6}); testFail("[v] += ary", "Assigning to rvalue (1:0)", {ecmaVersion: 6});
testFail("[2] = 42", "Assigning to rvalue (1:1)", {ecmaVersion: 6}); testFail("[2] = 42", "Assigning to rvalue (1:1)", {ecmaVersion: 6});
testFail("({ obj:20 } = 42)", "Assigning to rvalue (1:7)", {ecmaVersion: 6}); testFail("({ obj:20 }) = 42", "Assigning to rvalue (1:7)", {ecmaVersion: 6});
testFail("( { get x() {} } = 0 )", "Object pattern can't contain getter or setter (1:8)", {ecmaVersion: 6}); testFail("( { get x() {} } ) = 0", "Object pattern can't contain getter or setter (1:8)", {ecmaVersion: 6});
testFail("x \n is y", "Unexpected token (2:4)", {ecmaVersion: 6}); testFail("x \n is y", "Unexpected token (2:4)", {ecmaVersion: 6});
@ -13675,9 +13681,9 @@ testFail("let default", "Unexpected token (1:4)", {ecmaVersion: 6});
testFail("const default", "Unexpected token (1:6)", {ecmaVersion: 6}); testFail("const default", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("\"use strict\"; ({ v: eval } = obj)", "Assigning to eval in strict mode (1:20)", {ecmaVersion: 6}); testFail("\"use strict\"; ({ v: eval }) = obj", "Assigning to eval in strict mode (1:20)", {ecmaVersion: 6});
testFail("\"use strict\"; ({ v: arguments } = obj)", "Assigning to arguments in strict mode (1:20)", {ecmaVersion: 6}); testFail("\"use strict\"; ({ v: arguments }) = obj", "Assigning to arguments in strict mode (1:20)", {ecmaVersion: 6});
testFail("for (let x = 42 in list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6}); testFail("for (let x = 42 in list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6});
@ -14288,7 +14294,6 @@ test("var {propName: localVar = defaultValue} = obj", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [15, 38], range: [15, 38],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [15, 23], range: [15, 23],
@ -14344,7 +14349,6 @@ test("var {propName = defaultValue} = obj", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [5, 28], range: [5, 28],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [5, 13], range: [5, 13],
@ -14387,7 +14391,6 @@ test("var [localVar = defaultValue] = obj", {
elements: [{ elements: [{
type: "AssignmentPattern", type: "AssignmentPattern",
range: [5, 28], range: [5, 28],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [5, 13], range: [5, 13],
@ -14442,7 +14445,6 @@ test("({x = 0} = obj)", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [2, 7], range: [2, 7],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [2, 3], range: [2, 3],
@ -14498,7 +14500,6 @@ test("({x = 0}) => x", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [2, 7], range: [2, 7],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [2, 3], range: [2, 3],
@ -14575,7 +14576,6 @@ test("[a, {b: {c = 1}}] = arr", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [9, 14], range: [9, 14],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [9, 10], range: [9, 10],
@ -14630,7 +14630,6 @@ test("for ({x = 0} in arr);", {
value: { value: {
type: "AssignmentPattern", type: "AssignmentPattern",
range: [6, 11], range: [6, 11],
operator: "=",
left: { left: {
type: "Identifier", type: "Identifier",
range: [6, 7], range: [6, 7],
@ -15262,3 +15261,70 @@ test("new.target", {
}, {ecmaVersion: 6}); }, {ecmaVersion: 6});
testFail("new.prop", "The only valid meta property for new is new.target (1:4)", {ecmaVersion: 6}); testFail("new.prop", "The only valid meta property for new is new.target (1:4)", {ecmaVersion: 6});
test("export default function foo() {} false", {
body: [
{
declaration: {
id: {
name: "foo",
type: "Identifier"
},
generator: false,
expression: false,
params: [],
body: {
body: [],
type: "BlockStatement"
},
type: "FunctionDeclaration"
},
type: "ExportDefaultDeclaration"
},
{
expression: {
value: false,
raw: "false",
type: "Literal"
},
type: "ExpressionStatement"
}
],
sourceType: "module",
type: "Program"
}, {ecmaVersion: 6, sourceType: "module"})
// https://github.com/marijnh/acorn/issues/274
testFail("`\\07`", "Octal literal in strict mode (1:1)", {ecmaVersion: 6});
// https://github.com/marijnh/acorn/issues/277
testFail("x = { method() 42 }", "Unexpected token (1:15)", {ecmaVersion: 6});
testFail("x = { get method() 42 }", "Unexpected token (1:19)", {ecmaVersion: 6});
testFail("x = { set method(val) v = val }", "Unexpected token (1:22)", {ecmaVersion: 6});
// https://github.com/marijnh/acorn/issues/278
testFail("/\\u{110000}/u", "Code point out of bounds (1:4)", {ecmaVersion: 6});
// https://github.com/marijnh/acorn/issues/279
testFail("super", "'super' outside of function or class (1:0)", {ecmaVersion: 6});
// https://github.com/marijnh/acorn/issues/275
testFail("class A { get prop(x) {} }", "getter should have no params (1:18)", {ecmaVersion: 6});
testFail("class A { set prop() {} }", "setter should have exactly one param (1:18)", {ecmaVersion: 6});
testFail("class A { set prop(x, y) {} }", "setter should have exactly one param (1:18)", {ecmaVersion: 6});
// https://github.com/marijnh/acorn/issues/276
testFail("({ __proto__: 1, __proto__: 2 })", "Redefinition of __proto__ property (1:17)", {ecmaVersion: 6});
testFail("({ '__proto__': 1, __proto__: 2 })", "Redefinition of __proto__ property (1:19)", {ecmaVersion: 6});
test("({ ['__proto__']: 1, __proto__: 2 })", {}, {ecmaVersion: 6});
test("({ __proto__() { return 1 }, __proto__: 2 })", {}, {ecmaVersion: 6});
test("({ get __proto__() { return 1 }, __proto__: 2 })", {}, {ecmaVersion: 6});
test("({ __proto__, __proto__: 2 })", {}, {ecmaVersion: 6});

View File

@ -403,7 +403,30 @@ test("(1 + 2 ) * 3", {
preserveParens: true preserveParens: true
}); });
testFail("(x) = 23", "Assigning to rvalue (1:0)", { preserveParens: true }); test("(x) = 23", {
body: [
{
expression: {
operator: "=",
left: {
expression: {
name: "x",
type: "Identifier",
},
type: "ParenthesizedExpression",
},
right: {
value: 23,
raw: "23",
type: "Literal",
},
type: "AssignmentExpression",
},
type: "ExpressionStatement",
}
],
type: "Program",
}, {preserveParens: true});
test("x = []", { test("x = []", {
type: "Program", type: "Program",
@ -20637,6 +20660,9 @@ test("done: while (true) { break done; }", {
} }
}); });
test("target1: target2: while (true) { continue target1; }", {});
test("target1: target2: target3: while (true) { continue target1; }", {});
test("(function(){ return })", { test("(function(){ return })", {
type: "Program", type: "Program",
body: [ body: [
@ -26881,7 +26907,7 @@ testFail("/test",
"Unterminated regular expression (1:1)"); "Unterminated regular expression (1:1)");
testFail("var x = /[a-z]/\\ux", testFail("var x = /[a-z]/\\ux",
"Bad character escape sequence (1:8)"); "Bad character escape sequence (1:17)");
testFail("3 = 4", testFail("3 = 4",
"Assigning to rvalue (1:0)"); "Assigning to rvalue (1:0)");
@ -27168,7 +27194,7 @@ testFail("\"\\",
"Unterminated string constant (1:0)"); "Unterminated string constant (1:0)");
testFail("\"\\u", testFail("\"\\u",
"Bad character escape sequence (1:0)"); "Bad character escape sequence (1:3)");
testFail("return", testFail("return",
"'return' outside of function (1:0)"); "'return' outside of function (1:0)");
@ -28720,6 +28746,39 @@ testFail("for(x of a);", "Unexpected token (1:6)");
testFail("for(var x of a);", "Unexpected token (1:10)"); testFail("for(var x of a);", "Unexpected token (1:10)");
// Assertion Tests
test(function TestComments() {
// Bear class
function Bear(x,y,z) {
this.position = [x||0,y||0,z||0]
}
Bear.prototype.roar = function(message) {
return 'RAWWW: ' + message; // Whatever
};
function Cat() {
/* 1
2
3*/
}
Cat.prototype.roar = function(message) {
return 'MEOOWW: ' + /*stuff*/ message;
};
}.toString().replace(/\r\n/g, '\n'), {}, {
onComment: [
{type: "Line", value: " Bear class"},
{type: "Line", value: " Whatever"},
{type: "Block", value: [
" 1",
" 2",
" 3"
].join('\n')},
{type: "Block", value: "stuff"}
]
});
test("<!--\n;", { test("<!--\n;", {
type: "Program", type: "Program",
body: [{ body: [{
@ -28932,3 +28991,9 @@ testAssert("[1,2,] + {foo: 1,}", function() {
return "Unexpected result for onTrailingComma: " + result; return "Unexpected result for onTrailingComma: " + result;
}, {onTrailingComma: function(pos) { trailingCommas.push(pos); }, }, {onTrailingComma: function(pos) { trailingCommas.push(pos); },
loose: false}) loose: false})
// https://github.com/marijnh/acorn/issues/275
testFail("({ get prop(x) {} })", "getter should have no params (1:11)");
testFail("({ set prop() {} })", "setter should have exactly one param (1:11)");
testFail("({ set prop(x, y) {} })", "setter should have exactly one param (1:11)");

View File

@ -1,4 +0,0 @@
class Test {
get constructor() {
}
}

View File

@ -1,3 +0,0 @@
{
"throws": "Illegal kind for constructor method"
}

View File

@ -1,5 +0,0 @@
class Foo {
set bar() {
}
}

View File

@ -1,5 +0,0 @@
class Foo {
set bar(foo, bar) {
}
}

View File

@ -1,5 +0,0 @@
var obj = {
set foo(...args) {
}
};

View File

@ -1,3 +0,0 @@
{
"throws": "Setters aren't allowed to have a rest"
}

View File

@ -1,5 +0,0 @@
var obj = {
set bar() {
}
};

View File

@ -1,5 +0,0 @@
var obj = {
set bar(foo, bar) {
}
};

View File

@ -1,3 +0,0 @@
{
"throws": "Setters must have exactly one parameter"
}

View File

@ -1 +0,0 @@
class X { async constructor() {} }

View File

@ -1,4 +0,0 @@
{
"throws": "Illegal kind for constructor method",
"optional": ["es7.asyncFunctions"]
}