update to latest acorn, better array shortcuts, don't add code frame to error message

This commit is contained in:
Sebastian McKenzie 2015-03-20 20:05:29 +11:00
parent f830892ab8
commit 0d143f005f
2 changed files with 165 additions and 52 deletions

110
acorn.js
View File

@ -243,6 +243,7 @@
this.label = label;
this.keyword = conf.keyword;
this.beforeExpr = !!conf.beforeExpr;
this.startsExpr = !!conf.startsExpr;
this.rightAssociative = !!conf.rightAssociative;
this.isLoop = !!conf.isLoop;
this.isAssign = !!conf.isAssign;
@ -255,21 +256,21 @@
function binop(name, prec) {
return new TokenType(name, {beforeExpr: true, binop: prec});
}
var beforeExpr = {beforeExpr: true};
var beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true};;
var tt = exports.tokTypes = {
num: new TokenType("num"),
regexp: new TokenType("regexp"),
string: new TokenType("string"),
name: new TokenType("name"),
num: new TokenType("num", startsExpr),
regexp: new TokenType("regexp", startsExpr),
string: new TokenType("string", startsExpr),
name: new TokenType("name", startsExpr),
eof: new TokenType("eof"),
// Punctuation token types.
bracketL: new TokenType("[", beforeExpr),
bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}),
bracketR: new TokenType("]"),
braceL: new TokenType("{", beforeExpr),
braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}),
braceR: new TokenType("}"),
parenL: new TokenType("(", beforeExpr),
parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}),
parenR: new TokenType(")"),
comma: new TokenType(",", beforeExpr),
semi: new TokenType(";", beforeExpr),
@ -279,8 +280,8 @@
arrow: new TokenType("=>", beforeExpr),
template: new TokenType("template"),
ellipsis: new TokenType("...", beforeExpr),
backQuote: new TokenType("`"),
dollarBraceL: new TokenType("${", beforeExpr),
backQuote: new TokenType("`", startsExpr),
dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}),
// Operators. These carry several kinds of properties to help the
// parser use them properly (the presence of these properties is
@ -298,8 +299,8 @@
eq: new TokenType("=", {beforeExpr: true, isAssign: true}),
assign: new TokenType("_=", {beforeExpr: true, isAssign: true}),
incDec: new TokenType("++/--", {prefix: true, postfix: true}),
prefix: new TokenType("prefix", {beforeExpr: true, prefix: true}),
incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}),
prefix: new TokenType("prefix", {beforeExpr: true, prefix: true, startsExpr: true}),
logicalOR: binop("||", 1),
logicalAND: binop("&&", 2),
bitwiseOR: binop("|", 3),
@ -308,7 +309,7 @@
equality: binop("==/!=", 6),
relational: binop("</>", 7),
bitShift: binop("<</>>", 8),
plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true}),
plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}),
modulo: binop("%", 10),
star: binop("*", 10),
slash: binop("/", 10),
@ -347,22 +348,22 @@
kw("const");
kw("while", {isLoop: true});
kw("with");
kw("new", beforeExpr);
kw("this");
kw("super");
kw("new", {beforeExpr: true, startsExpr: true});
kw("this", startsExpr);
kw("super", startsExpr);
kw("class");
kw("extends", beforeExpr);
kw("export");
kw("import");
kw("yield", beforeExpr);
kw("null");
kw("true");
kw("false");
kw("yield", {beforeExpr: true, startsExpr: true});
kw("null", startsExpr);
kw("true", startsExpr);
kw("false", startsExpr);
kw("in", {beforeExpr: true, binop: 7});
kw("instanceof", {beforeExpr: true, binop: 7});
kw("typeof", {beforeExpr: true, prefix: true});
kw("void", {beforeExpr: true, prefix: true});
kw("delete", {beforeExpr: true, prefix: true});
kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true});
kw("void", {beforeExpr: true, prefix: true, startsExpr: true});
kw("delete", {beforeExpr: true, prefix: true, startsExpr: true});
// This is a trick taken from Esprima. It turns out that, on
// non-Chrome browsers, to check whether a string is in a set, a
@ -1125,13 +1126,15 @@
if (this.options.ecmaVersion >= 6) validFlags = /^[gmsiyu]*$/;
if (!validFlags.test(mods)) this.raise(start, "Invalid regular expression flag");
if (mods.indexOf('u') >= 0 && !regexpUnicodeSupport) {
// Replace each astral symbol and every Unicode code point
// escape sequence that represents such a symbol with a single
// ASCII symbol to avoid throwing on regular expressions that
// Replace each astral symbol and every Unicode escape sequence that
// possibly represents an astral symbol or a paired surrogate with a
// single ASCII symbol to avoid throwing on regular expressions that
// are only valid in combination with the `/u` flag.
tmp = tmp
.replace(/\\u\{([0-9a-fA-F]+)\}/g, "x")
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x");
// Note: replacing with the ASCII symbol `x` might cause false
// 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")
}
}
// Detect invalid regular expressions.
@ -1604,24 +1607,23 @@
// Convert list of expression atoms to binding list.
pp.toAssignableList = function(exprList, isBinding) {
if (exprList.length) {
for (var i = 0; i < exprList.length - 1; i++) {
this.toAssignable(exprList[i], isBinding);
}
var last = exprList[exprList.length - 1];
switch (last.type) {
case "RestElement":
break;
case "SpreadElement":
last.type = "RestElement";
var arg = last.argument;
this.toAssignable(arg, isBinding);
if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
this.unexpected(arg.start);
break;
default:
this.toAssignable(last, isBinding);
}
var end = exprList.length;
if (end) {
var last = exprList[end - 1];
if (last && last.type == "RestElement") {
--end;
} else if (last && last.type == "SpreadElement") {
last.type = "RestElement";
var arg = last.argument;
this.toAssignable(arg, isBinding);
if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
this.unexpected(arg.start);
--end;
}
}
for (var i = 0; i < end; i++) {
var elt = exprList[i];
if (elt) this.toAssignable(elt, isBinding);
}
return exprList;
};
@ -2193,6 +2195,8 @@
decl.init = this.parseMaybeAssign(noIn);
} else if (kind === tt._const && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) {
this.unexpected();
} else if (decl.id.type != "Identifier") {
this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value");
} else {
decl.init = null;
}
@ -2634,12 +2638,10 @@
if (this.options.ecmaVersion >= 6) {
prop.method = false;
prop.shorthand = false;
if (isPattern || refShorthandDefaultPos) {
if (isPattern || refShorthandDefaultPos)
start = this.currentPos();
}
if (!isPattern) {
if (!isPattern)
isGenerator = this.eat(tt.star);
}
}
if (this.options.features["es7.asyncFunctions"] && this.isContextual("async")) {
if (isGenerator || isPattern) this.unexpected();
@ -2680,6 +2682,10 @@
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init";
if (isPattern) {
if (this.isKeyword(prop.key.name) ||
(this.strict && (isStrictBadIdWord(prop.key.name) || isStrictReservedWord(prop.key.name))) ||
(!this.options.allowReserved && this.isReservedWord(prop.key.name)))
this.raise(prop.key.start, "Binding " + prop.key.name);
prop.value = this.parseMaybeDefault(start, prop.key);
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start)
@ -3040,7 +3046,7 @@
pp.parseYield = function() {
var node = this.startNode();
this.next();
if (this.type == tt.semi || this.canInsertSemicolon()) {
if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) {
node.delegate = false;
node.argument = null;
} else {

View File

@ -5989,6 +5989,53 @@ test("var x = { *test () { yield *v } };", {
locations: true
});
test("function* foo() { console.log(yield); }", {
body: [
{
id: {
name: "foo",
type: "Identifier",
},
generator: true,
expression: false,
params: [],
body: {
body: [
{
expression: {
callee: {
object: {
name: "console",
type: "Identifier",
},
property: {
name: "log",
type: "Identifier",
},
computed: false,
type: "MemberExpression",
},
arguments: [
{
delegate: false,
argument: null,
type: "YieldExpression",
}
],
type: "CallExpression",
},
type: "ExpressionStatement",
}
],
type: "BlockStatement",
},
type: "FunctionDeclaration",
}
],
sourceType: "script",
type: "Program"
}, {ecmaVersion: 6})
test("function* t() {}", {
type: "Program",
body: [{
@ -13814,6 +13861,34 @@ test("/[a-z]/u", {
ecmaVersion: 6
});
test("/[\\uD834\\uDF06-\\uD834\\uDF08a-z]/u", {
type: "Program",
body: [
{
type: "ExpressionStatement",
expression: {
type: "Literal",
regex: {
pattern: "[\\uD834\\uDF06-\\uD834\\uDF08a-z]",
flags: "u"
},
loc: {
start: {
line: 1,
column: 0
},
end: {
line: 1,
column: 33
}
}
}
}
]
}, {
locations: true,
ecmaVersion: 6
});
test("do {} while (false) foo();", {
type: "Program",
@ -15419,6 +15494,36 @@ test("let {x} = y", {
"end": 11
}, {ecmaVersion: 6})
test("[x,,] = 1", {
type: "Program",
body: [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "ArrayPattern",
elements: [
{
type: "Identifier",
name: "x"
},
null
]
},
right: {
type: "Literal",
value: 1,
raw: "1"
}
}
}
]
}, {ecmaVersion: 6});
testFail("let [x]", "Complex binding patterns require an initialization value (1:7)", {ecmaVersion: 6})
testFail("var [x]", "Complex binding patterns require an initialization value (1:7)", {ecmaVersion: 6})
testFail("var _𖫵 = 11;", "Unexpected character '𖫵' (1:5)", {ecmaVersion: 6});
testFail("var 𫠞_ = 12;", "Unexpected character '𫠞' (1:4)", {ecmaVersion: 6});
testFail("var 𫠝_ = 10;", "Unexpected character '𫠝' (1:4)", {ecmaVersion: 5});
@ -15431,3 +15536,5 @@ testFail("'use strict'; [...eval] = arr", "Assigning to eval in strict mode (1:1
testFail("'use strict'; ({eval = defValue} = obj)", "Assigning to eval in strict mode (1:16)", {ecmaVersion: 6});
testFail("[...eval] = arr", "Assigning to eval in strict mode (1:4)", {ecmaVersion: 6, sourceType: "module"});
testFail("function* y({yield}) {}", "Binding yield (1:13)", {ecmaVersion: 6});