Forbid spread element in sequence expressions.

This commit is contained in:
Ingvar Stepanyan 2014-07-26 06:52:21 +03:00 committed by Marijn Haverbeke
parent 8f96965d36
commit 3ee9e288a2
2 changed files with 28 additions and 17 deletions

View File

@ -32,8 +32,7 @@
// The main exported interface (under `self.acorn` when in the // The main exported interface (under `self.acorn` when in the
// browser) is a `parse` function that takes a code string and // browser) is a `parse` function that takes a code string and
// returns an abstract syntax tree as specified by [Mozilla parser // returns an abstract syntax tree as specified by [Mozilla parser
// API][api], with the caveat that the SpiderMonkey-specific syntax // API][api], with the caveat that inline XML is not recognized.
// (`let`, `yield`, inline XML, etc) is not recognized.
// //
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
@ -53,7 +52,7 @@
// `ecmaVersion` indicates the ECMAScript version to parse. Must // `ecmaVersion` indicates the ECMAScript version to parse. Must
// be either 3, or 5, or 6. This influences support for strict // be either 3, or 5, or 6. This influences support for strict
// mode, the set of reserved words, support for getters and // mode, the set of reserved words, support for getters and
// setters and other features. ES6 support is only partial. // setters and other features.
ecmaVersion: 5, ecmaVersion: 5,
// Turn on `strictSemicolons` to prevent the parser from doing // Turn on `strictSemicolons` to prevent the parser from doing
// automatic semicolon insertion. // automatic semicolon insertion.
@ -1784,19 +1783,28 @@
return finishNode(node, "Literal"); return finishNode(node, "Literal");
case _parenL: case _parenL:
var node = startNode(), tokStartLoc1 = tokStartLoc, tokStart1 = tokStart, val; var node = startNode(), tokStartLoc1 = tokStartLoc, tokStart1 = tokStart, val, exprList;
next(); next();
var oldParenL = ++metParenL; var oldParenL = ++metParenL;
if (tokType !== _parenR) { if (tokType !== _parenR) {
val = parseExpression(); val = parseExpression();
exprList = val.type === "SequenceExpression" ? val.expressions : [val];
} else {
exprList = [];
} }
expect(_parenR); expect(_parenR);
// if '=>' follows '(...)', convert contents to arguments // if '=>' follows '(...)', convert contents to arguments
if (metParenL === oldParenL && eat(_arrow)) { if (metParenL === oldParenL && eat(_arrow)) {
val = parseArrowExpression(node, !val ? [] : val.type === "SequenceExpression" ? val.expressions : [val]); val = parseArrowExpression(node, exprList);
} else { } else {
// forbid '()' before everything but '=>' // forbid '()' before everything but '=>'
if (!val) unexpected(lastStart); if (!val) unexpected(lastStart);
// forbid '...' in sequence expressions
if (options.ecmaVersion >= 6) {
for (var i = 0; i < exprList.length; i++) {
if (exprList[i].type === "SpreadElement") unexpected();
}
}
} }
val.start = tokStart1; val.start = tokStart1;
val.end = lastEnd; val.end = lastEnd;
@ -2065,7 +2073,7 @@
params[i] = param.left; params[i] = param.left;
defaults.push(param.right); defaults.push(param.right);
} else { } else {
toAssignable(param, i === lastI); toAssignable(param, i === lastI, true);
defaults.push(null); defaults.push(null);
if (param.type === "SpreadElement") { if (param.type === "SpreadElement") {
params.length--; params.length--;
@ -2092,12 +2100,12 @@
if (eat(_parenR)) { if (eat(_parenR)) {
break; break;
} else if (options.ecmaVersion >= 6 && eat(_ellipsis)) { } else if (options.ecmaVersion >= 6 && eat(_ellipsis)) {
node.rest = toAssignable(parseExprAtom()); node.rest = toAssignable(parseExprAtom(), false, true);
checkSpreadAssign(node.rest); checkSpreadAssign(node.rest);
expect(_parenR); expect(_parenR);
break; break;
} else { } else {
node.params.push(options.ecmaVersion >= 6 ? toAssignable(parseExprAtom()) : parseIdent()); node.params.push(options.ecmaVersion >= 6 ? toAssignable(parseExprAtom(), false, true) : parseIdent());
if (options.ecmaVersion >= 6 && tokVal === '=') { if (options.ecmaVersion >= 6 && tokVal === '=') {
next(); next();
hasDefaults = true; hasDefaults = true;
@ -2249,7 +2257,7 @@
// Convert existing expression atom to assignable pattern // Convert existing expression atom to assignable pattern
// if possible. // if possible.
function toAssignable(node, allowSpread) { function toAssignable(node, allowSpread, checkType) {
if (options.ecmaVersion >= 6 && node) { if (options.ecmaVersion >= 6 && node) {
switch (node.type) { switch (node.type) {
case "Identifier": case "Identifier":
@ -2261,26 +2269,28 @@
for (var i = 0; i < node.properties.length; i++) { for (var i = 0; i < node.properties.length; i++) {
var prop = node.properties[i]; var prop = node.properties[i];
if (prop.kind !== "init") unexpected(prop.key.start); if (prop.kind !== "init") unexpected(prop.key.start);
toAssignable(prop.value); toAssignable(prop.value, false, checkType);
} }
break; break;
case "ArrayExpression": case "ArrayExpression":
node.type = "ArrayPattern"; node.type = "ArrayPattern";
for (var i = 0, lastI = node.elements.length - 1; i <= lastI; i++) { for (var i = 0, lastI = node.elements.length - 1; i <= lastI; i++) {
toAssignable(node.elements[i], i === lastI); toAssignable(node.elements[i], i === lastI, checkType);
} }
break; break;
case "SpreadElement": case "SpreadElement":
if (allowSpread) { if (allowSpread) {
toAssignable(node.argument); toAssignable(node.argument, false, checkType);
checkSpreadAssign(node.argument); checkSpreadAssign(node.argument);
break; } else {
unexpected(node.start);
} }
break;
default: default:
unexpected(node.start); if (checkType) unexpected(node.start);
} }
} }
return node; return node;

View File

@ -6,6 +6,7 @@
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:
@ -14465,9 +14466,9 @@ testFail("\"\\u{FFZ}\"", "Bad character escape sequence (1:0)", {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", "Unexpected token (1:1)", {ecmaVersion: 6}); testFail("[2] = 42", "Assigning to rvalue (1:1)", {ecmaVersion: 6});
testFail("({ obj:20 }) = 42", "Unexpected token (1:7)", {ecmaVersion: 6}); testFail("({ obj:20 }) = 42", "Assigning to rvalue (1:7)", {ecmaVersion: 6});
testFail("( { get x() {} } ) = 0", "Unexpected token (1:8)", {ecmaVersion: 6}); testFail("( { get x() {} } ) = 0", "Unexpected token (1:8)", {ecmaVersion: 6});
@ -14860,7 +14861,7 @@ test("[...a, ] = b", {
locations: true locations: true
}); });
testFail("if (b,...a, );", "Unexpected token (1:11)", {ecmaVersion: 6}); testFail("if (b,...a, );", "Unexpected token (1:12)", {ecmaVersion: 6});
testFail("(b, ...a)", "Unexpected token (1:9)", {ecmaVersion: 6}); testFail("(b, ...a)", "Unexpected token (1:9)", {ecmaVersion: 6});