Merge branch 'upstream' into jsx2

This commit is contained in:
Ingvar Stepanyan 2015-01-22 16:11:28 +02:00
commit 252bb46f70
3 changed files with 109 additions and 75 deletions

158
acorn.js
View File

@ -315,11 +315,6 @@
var inFunction, inGenerator, labels, strict; var inFunction, inGenerator, labels, strict;
// This counter is used for checking that arrow expressions did
// not contain nested parentheses in argument list.
var metParenL;
function initParserState() { function initParserState() {
lastStart = lastEnd = tokPos; lastStart = lastEnd = tokPos;
if (options.locations) lastEndLoc = curPosition(); if (options.locations) lastEndLoc = curPosition();
@ -423,7 +418,7 @@
var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true}; var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true};
var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true}; var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true};
var _arrow = {type: "=>", beforeExpr: true}, _template = {type: "template"}; var _arrow = {type: "=>", beforeExpr: true}, _template = {type: "template"};
var _ellipsis = {type: "...", prefix: true, beforeExpr: true}; var _ellipsis = {type: "...", beforeExpr: true};
var _backQuote = {type: "`"}, _dollarBraceL = {type: "${", beforeExpr: true}; var _backQuote = {type: "`"}, _dollarBraceL = {type: "${", beforeExpr: true};
var _jsxText = {type: "jsxText"}; var _jsxText = {type: "jsxText"};
@ -632,7 +627,6 @@
tokType = _eof; tokType = _eof;
tokContext = []; tokContext = [];
tokExprAllowed = true; tokExprAllowed = true;
metParenL = 0;
if (tokPos === 0 && options.allowHashBang && input.slice(0, 2) === '#!') { if (tokPos === 0 && options.allowHashBang && input.slice(0, 2) === '#!') {
skipLineComment(2); skipLineComment(2);
} }
@ -1782,6 +1776,17 @@
return node; return node;
} }
// Finish node at given position
function finishNodeAt(node, type, pos) {
if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; }
node.type = type;
node.end = pos;
if (options.ranges)
node.range[1] = pos;
return node;
}
// Test whether a statement node is the string literal `"use strict"`. // Test whether a statement node is the string literal `"use strict"`.
function isUseStrict(stmt) { function isUseStrict(stmt) {
@ -1842,6 +1847,9 @@
switch (node.type) { switch (node.type) {
case "Identifier": case "Identifier":
case "MemberExpression": case "MemberExpression":
case "ObjectPattern":
case "ArrayPattern":
case "AssignmentPattern":
break; break;
case "ObjectExpression": case "ObjectExpression":
@ -1884,6 +1892,21 @@
return node; return node;
} }
// Parses spread element.
function parseSpread(isBinding) {
var spread = startNode();
next();
if (isBinding) {
var arg = parseAssignableAtom();
checkSpreadAssign(arg);
spread.argument = arg;
} else {
spread.argument = parseMaybeAssign();
}
return finishNode(spread, "SpreadElement");
}
// Parses lvalue (assignable) atom. // Parses lvalue (assignable) atom.
function parseAssignableAtom() { function parseAssignableAtom() {
@ -1899,11 +1922,7 @@
while (!eat(_bracketR)) { while (!eat(_bracketR)) {
first ? first = false : expect(_comma); first ? first = false : expect(_comma);
if (tokType === _ellipsis) { if (tokType === _ellipsis) {
var spread = startNode(); elts.push(parseSpread(true));
next();
spread.argument = parseAssignableAtom();
checkSpreadAssign(spread.argument);
elts.push(finishNode(spread, "SpreadElement"));
expect(_bracketR); expect(_bracketR);
break; break;
} }
@ -2490,21 +2509,16 @@
function parseMaybeUnary() { function parseMaybeUnary() {
if (tokType.prefix) { if (tokType.prefix) {
var node = startNode(), update = tokType.isUpdate, nodeType; var node = startNode(), update = tokType.isUpdate;
if (tokType === _ellipsis) { node.operator = tokVal;
nodeType = "SpreadElement"; node.prefix = true;
} else {
nodeType = update ? "UpdateExpression" : "UnaryExpression";
node.operator = tokVal;
node.prefix = true;
}
next(); next();
node.argument = parseMaybeUnary(); node.argument = parseMaybeUnary();
if (update) checkLVal(node.argument); if (update) checkLVal(node.argument);
else if (strict && node.operator === "delete" && else if (strict && node.operator === "delete" &&
node.argument.type === "Identifier") node.argument.type === "Identifier")
raise(node.start, "Deleting local variable in strict mode"); raise(node.start, "Deleting local variable in strict mode");
return finishNode(node, nodeType); return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
} }
var start = storeCurrentPos(); var start = storeCurrentPos();
var expr = parseExprSubscripts(); var expr = parseExprSubscripts();
@ -2600,42 +2614,7 @@
return finishNode(node, "Literal"); return finishNode(node, "Literal");
case _parenL: case _parenL:
var start = storeCurrentPos(); return parseParenAndDistinguishExpression();
var val, exprList;
next();
// check whether this is generator comprehension or regular expression
if (options.ecmaVersion >= 7 && tokType === _for) {
val = parseComprehension(startNodeAt(start), true);
} else {
var oldParenL = ++metParenL;
if (tokType !== _parenR) {
val = parseExpression();
exprList = val.type === "SequenceExpression" ? val.expressions : [val];
} else {
exprList = [];
}
expect(_parenR);
// if '=>' follows '(...)', convert contents to arguments
if (metParenL === oldParenL && eat(_arrow)) {
val = parseArrowExpression(startNodeAt(start), exprList);
} else {
// forbid '()' before everything but '=>'
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();
}
}
if (options.preserveParens) {
var par = startNodeAt(start);
par.expression = val;
val = finishNode(par, "ParenthesizedExpression");
}
}
}
return val;
case _bracketL: case _bracketL:
var node = startNode(); var node = startNode();
@ -2672,6 +2651,60 @@
} }
} }
function parseParenAndDistinguishExpression() {
var start = storeCurrentPos(), val;
if (options.ecmaVersion >= 6) {
next();
if (options.ecmaVersion >= 7 && tokType === _for) {
return parseComprehension(startNodeAt(start), true);
}
var innerStart = storeCurrentPos(), exprList = [], first = true, spreadStart, innerParenStart;
while (tokType !== _parenR) {
first ? first = false : expect(_comma);
if (tokType === _ellipsis) {
spreadStart = tokStart;
exprList.push(parseSpread(true));
break;
} else {
if (tokType === _parenL && !innerParenStart) {
innerParenStart = tokStart;
}
exprList.push(parseMaybeAssign());
}
}
var innerEnd = storeCurrentPos();
expect(_parenR);
if (eat(_arrow)) {
if (innerParenStart) unexpected(innerParenStart);
return parseArrowExpression(startNodeAt(start), exprList);
}
if (!exprList.length) unexpected(lastStart);
if (spreadStart) unexpected(spreadStart);
if (exprList.length > 1) {
val = startNodeAt(innerStart);
val.expressions = exprList;
finishNodeAt(val, "SequenceExpression", innerEnd);
} else {
val = exprList[0];
}
} else {
val = parseParenExpression();
}
if (options.preserveParens) {
var par = startNodeAt(start);
par.expression = val;
return finishNode(par, "ParenthesizedExpression");
} else {
return val;
}
}
// New's precedence is slightly tricky. It must allow its argument // New's precedence is slightly tricky. It must allow its argument
// to be a `[]` or dot subscript expression, but not a call — at // to be a `[]` or dot subscript expression, but not a call — at
// least, not without wrapping it in parentheses. Thus, it uses the // least, not without wrapping it in parentheses. Thus, it uses the
@ -2715,7 +2748,7 @@
return finishNode(node, "TemplateLiteral"); return finishNode(node, "TemplateLiteral");
} }
// Parse an object literal. // Parse an object literal or binding pattern.
function parseObj(isPattern) { function parseObj(isPattern) {
var node = startNode(), first = true, propHash = {}; var node = startNode(), first = true, propHash = {};
@ -2865,7 +2898,7 @@
for (;;) { for (;;) {
if (eat(_parenR)) { if (eat(_parenR)) {
break; break;
} else if (options.ecmaVersion >= 6 && eat(_ellipsis)) { } else if (eat(_ellipsis)) {
node.rest = parseAssignableAtom(); node.rest = parseAssignableAtom();
checkSpreadAssign(node.rest); checkSpreadAssign(node.rest);
expect(_parenR); expect(_parenR);
@ -2976,8 +3009,11 @@
if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break; if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break;
} else first = false; } else first = false;
if (allowEmpty && tokType === _comma) elts.push(null); if (allowEmpty && tokType === _comma) {
else elts.push(parseExpression(true)); elts.push(null);
} else {
elts.push(tokType === _ellipsis ? parseSpread() : parseMaybeAssign());
}
} }
return elts; return elts;
} }

View File

@ -622,20 +622,18 @@
function parseMaybeUnary(noIn) { function parseMaybeUnary(noIn) {
if (token.type.prefix) { if (token.type.prefix) {
var node = startNode(), update = token.type.isUpdate, nodeType; var node = startNode(), update = token.type.isUpdate;
if (token.type === tt.ellipsis) {
nodeType = "SpreadElement";
} else {
nodeType = update ? "UpdateExpression" : "UnaryExpression";
node.operator = token.value;
node.prefix = true;
}
node.operator = token.value; node.operator = token.value;
node.prefix = true; node.prefix = true;
next(); next();
node.argument = parseMaybeUnary(noIn); node.argument = parseMaybeUnary(noIn);
if (update) node.argument = checkLVal(node.argument); if (update) node.argument = checkLVal(node.argument);
return finishNode(node, nodeType); return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
} else if (token.type === tt.ellipsis) {
var node = startNode();
next();
node.argument = parseMaybeUnary(noIn);
return finishNode(node, "SpreadElement");
} }
var start = storeCurrentPos(); var start = storeCurrentPos();
var expr = parseExprSubscripts(); var expr = parseExprSubscripts();

View File

@ -13891,9 +13891,9 @@ testFail("import { foo, bar }", "Unexpected token (1:19)", {ecmaVersion: 6});
testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6}); testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6});
testFail("((a)) => 42", "Unexpected token (1:6)", {ecmaVersion: 6}); testFail("((a)) => 42", "Unexpected token (1:1)", {ecmaVersion: 6});
testFail("(a, (b)) => 42", "Unexpected token (1:9)", {ecmaVersion: 6}); testFail("(a, (b)) => 42", "Unexpected token (1:4)", {ecmaVersion: 6});
testFail("\"use strict\"; (eval = 10) => 42", "Assigning to eval in strict mode (1:15)", {ecmaVersion: 6}); testFail("\"use strict\"; (eval = 10) => 42", "Assigning to eval in strict mode (1:15)", {ecmaVersion: 6});
@ -14151,7 +14151,7 @@ testFail("\"use strict\"; function x({ b: { a } }, [{ b: { a } }]){}", "Argument
testFail("\"use strict\"; function x(a, ...[a]){}", "Argument name clash in strict mode (1:32)", {ecmaVersion: 6}); testFail("\"use strict\"; function x(a, ...[a]){}", "Argument name clash in strict mode (1:32)", {ecmaVersion: 6});
testFail("(...a, b) => {}", "Unexpected token (1:1)", {ecmaVersion: 6}); testFail("(...a, b) => {}", "Unexpected token (1:5)", {ecmaVersion: 6});
testFail("([ 5 ]) => {}", "Unexpected token (1:3)", {ecmaVersion: 6}); testFail("([ 5 ]) => {}", "Unexpected token (1:3)", {ecmaVersion: 6});
@ -14226,9 +14226,9 @@ test("[...a, ] = b", {
locations: true locations: true
}); });
testFail("if (b,...a, );", "Unexpected token (1:12)", {ecmaVersion: 6}); testFail("if (b,...a, );", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("(b, ...a)", "Unexpected token (1:9)", {ecmaVersion: 6}); testFail("(b, ...a)", "Unexpected token (1:4)", {ecmaVersion: 6});
testFail("switch (cond) { case 10: let a = 20; ", "Unexpected token (1:37)", {ecmaVersion: 6}); testFail("switch (cond) { case 10: let a = 20; ", "Unexpected token (1:37)", {ecmaVersion: 6});