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.
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
switch (key.type) {
case "Identifier": name = key.name; break
case "Literal": name = String(key.value); break
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)) {
other = propHash[name]
let isGetSet = kind !== "init"
@ -260,8 +269,10 @@ pp.parseNoCallExpr = function() {
pp.parseExprAtom = function(refShorthandDefaultPos) {
let node, canBeArrow = this.potentialArrowAt == this.start
switch (this.type) {
case tt._this:
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"
node = this.startNode()
this.next()
@ -609,6 +620,14 @@ pp.parseObjPropValue = function (prop, start, isGenerator, isAsync, isPattern, r
prop.kind = prop.key.name
this.parsePropertyName(prop)
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") {
prop.kind = "init"
if (isPattern) {
@ -634,12 +653,12 @@ pp.parsePropertyName = function(prop) {
prop.computed = true
prop.key = this.parseMaybeAssign()
this.expect(tt.bracketR)
return
return prop.key
} else {
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.

View File

@ -35,6 +35,7 @@ pp.toAssignable = function(node, isBinding) {
case "AssignmentExpression":
if (node.operator === "=") {
node.type = "AssignmentPattern"
delete node.operator
} else {
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
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];
if (prop.type === "Property") prop = prop.value;
this.checkLVal(prop, isBinding, checkClashes)
@ -194,6 +195,10 @@ pp.checkLVal = function(expr, isBinding, checkClashes) {
this.checkLVal(expr.argument, isBinding, checkClashes)
break
case "ParenthesizedExpression":
this.checkLVal(expr.expression, isBinding, checkClashes)
break
default:
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
}

View File

@ -1,5 +1,6 @@
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) {
this.options = options

View File

@ -347,7 +347,14 @@ pp.parseLabeledStatement = function(node, maybeName, expr) {
for (let i = 0; i < this.labels.length; ++i)
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
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)
this.labels.pop()
node.label = expr
@ -466,6 +473,7 @@ pp.parseClass = function(node, isStatement) {
this.parseClassId(node, isStatement)
this.parseClassSuper(node)
var classBody = this.startNode()
let hadConstructor = false
classBody.body = []
this.expect(tt.braceL)
let decorators = []
@ -480,16 +488,14 @@ pp.parseClass = function(node, isStatement) {
method.decorators = decorators
decorators = []
}
let isMaybeStatic = this.type === tt.name && this.value === "static"
var isGenerator = this.eat(tt.star), isAsync = false
this.parsePropertyName(method)
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
method.key.name === "static") {
method.static = isMaybeStatic && this.type !== tt.parenL
if (method.static) {
if (isGenerator) this.unexpected()
method['static'] = true
isGenerator = this.eat(tt.star)
this.parsePropertyName(method)
} else {
method['static'] = false
}
if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) {
classBody.body.push(this.parseClassProperty(method))
@ -500,23 +506,39 @@ pp.parseClass = function(node, isStatement) {
isAsync = true
this.parsePropertyName(method)
}
let isGetSet = false
method.kind = "method"
if (!method.computed && !isGenerator && !isAsync) {
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") {
if (!method.computed) {
let {key} = method
if (!isAsync && !isGenerator && 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 function")
method.kind = "constructor"
hadConstructor = true
}
}
if (method.kind === "constructor" && method.decorators) {
this.raise(method.start, "You can't attach decorators to a class constructor")
}
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) {
this.raise(this.start, "You have trailing decorators with no method");

View File

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

View File

@ -5,9 +5,7 @@ export const MESSAGES = {
JSXNamespacedTags: "Namespace tags are not supported. ReactJSX is not XML.",
classesIllegalBareSuper: "Illegal use of bare super",
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
classesIllegalConstructorKind: "Illegal kind for constructor method",
scopeDuplicateDeclaration: "Duplicate declaration $1",
settersInvalidParamLength: "Setters must have exactly one parameter",
settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head",
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) {
if (node.kind === "set") {
if (node.value.params.length !== 1) {
throw file.errorWithNode(node.value, messages.get("settersInvalidParamLength"));
}
var first = node.value.params[0];
if (t.isRestElement(first)) {
throw file.errorWithNode(first, messages.get("settersNoRest"));

View File

@ -2299,7 +2299,7 @@ test("class Foo { @foo bar() {} }", {
features: { "es7.decorators": true }
});
test("class Foo { @foo set bar() {} }", {
test("class Foo { @foo set bar(f) {} }", {
"start": 0,
"body": [
{
@ -2343,29 +2343,32 @@ test("class Foo { @foo set bar() {} }", {
"id": null,
"generator": false,
"expression": false,
"params": [],
"params": [{
"type": "Identifier",
"name": "f"
}],
"body": {
"start": 27,
"start": 28,
"body": [],
"type": "BlockStatement",
"end": 29
"end": 30
},
"type": "FunctionExpression",
"end": 29
"end": 30
},
"type": "MethodDefinition",
"end": 29
"end": 30
}
],
"type": "ClassBody",
"end": 31
"end": 32
},
"type": "ClassDeclaration",
"end": 31
"end": 32
}
],
"type": "Program",
"end": 31
"end": 32
}, {
ecmaVersion: 6,
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 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
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 Yusuke Suzuki <utatane.tea@gmail.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
modification, are permitted provided that the following conditions are met:
@ -877,7 +877,7 @@ test("`\n\r\n\r`", {
locations: true
});
test("`\\u{000042}\\u0042\\x42u0\\102\\A`", {
test("`\\u{000042}\\u0042\\x42u0\\A`", {
type: "Program",
body: [{
type: "ExpressionStatement",
@ -885,27 +885,27 @@ test("`\\u{000042}\\u0042\\x42u0\\102\\A`", {
type: "TemplateLiteral",
quasis: [{
type: "TemplateElement",
value: {raw: "\\u{000042}\\u0042\\x42u0\\102\\A", cooked: "BBBu0BA"},
value: {raw: "\\u{000042}\\u0042\\x42u0\\A", cooked: "BBBu0A"},
tail: true,
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 29}
end: {line: 1, column: 25}
}
}],
expressions: [],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 30}
end: {line: 1, column: 26}
}
},
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 30}
end: {line: 1, column: 26}
}
}],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 30}
end: {line: 1, column: 26}
}
}, {
ecmaVersion: 6,
@ -1714,7 +1714,7 @@ test("([a, , b]) => 42", {
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", {
type: "Program",
@ -7223,6 +7223,12 @@ test("class A {'constructor'() {}}", {
}]
}, {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() {}}", {
type: "Program",
body: [{
@ -13641,21 +13647,21 @@ testFail("0B18", "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("[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});
@ -13675,9 +13681,9 @@ testFail("let default", "Unexpected token (1:4)", {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});
@ -14288,7 +14294,6 @@ test("var {propName: localVar = defaultValue} = obj", {
value: {
type: "AssignmentPattern",
range: [15, 38],
operator: "=",
left: {
type: "Identifier",
range: [15, 23],
@ -14344,7 +14349,6 @@ test("var {propName = defaultValue} = obj", {
value: {
type: "AssignmentPattern",
range: [5, 28],
operator: "=",
left: {
type: "Identifier",
range: [5, 13],
@ -14387,7 +14391,6 @@ test("var [localVar = defaultValue] = obj", {
elements: [{
type: "AssignmentPattern",
range: [5, 28],
operator: "=",
left: {
type: "Identifier",
range: [5, 13],
@ -14442,7 +14445,6 @@ test("({x = 0} = obj)", {
value: {
type: "AssignmentPattern",
range: [2, 7],
operator: "=",
left: {
type: "Identifier",
range: [2, 3],
@ -14498,7 +14500,6 @@ test("({x = 0}) => x", {
value: {
type: "AssignmentPattern",
range: [2, 7],
operator: "=",
left: {
type: "Identifier",
range: [2, 3],
@ -14575,7 +14576,6 @@ test("[a, {b: {c = 1}}] = arr", {
value: {
type: "AssignmentPattern",
range: [9, 14],
operator: "=",
left: {
type: "Identifier",
range: [9, 10],
@ -14630,7 +14630,6 @@ test("for ({x = 0} in arr);", {
value: {
type: "AssignmentPattern",
range: [6, 11],
operator: "=",
left: {
type: "Identifier",
range: [6, 7],
@ -15262,3 +15261,70 @@ test("new.target", {
}, {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
});
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 = []", {
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 })", {
type: "Program",
body: [
@ -26881,7 +26907,7 @@ testFail("/test",
"Unterminated regular expression (1:1)");
testFail("var x = /[a-z]/\\ux",
"Bad character escape sequence (1:8)");
"Bad character escape sequence (1:17)");
testFail("3 = 4",
"Assigning to rvalue (1:0)");
@ -27168,7 +27194,7 @@ testFail("\"\\",
"Unterminated string constant (1:0)");
testFail("\"\\u",
"Bad character escape sequence (1:0)");
"Bad character escape sequence (1:3)");
testFail("return",
"'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)");
// 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;", {
type: "Program",
body: [{
@ -28932,3 +28991,9 @@ testAssert("[1,2,] + {foo: 1,}", function() {
return "Unexpected result for onTrailingComma: " + result;
}, {onTrailingComma: function(pos) { trailingCommas.push(pos); },
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"]
}