Array Comprehensions as per latest ES6 drafts.

This commit is contained in:
Ingvar Stepanyan 2014-07-25 18:45:04 +03:00 committed by Marijn Haverbeke
parent dd37866fdb
commit bcc97e2d52
2 changed files with 78 additions and 434 deletions

View File

@ -1174,8 +1174,10 @@
break;
case "ArrayPattern":
for (var i = 0; i < expr.elements.length; i++)
checkLVal(expr.elements[i], isBinding);
for (var i = 0; i < expr.elements.length; i++) {
var elem = expr.elements[i];
if (elem) checkLVal(elem, isBinding);
}
break;
case "SpreadElement":
@ -1731,10 +1733,11 @@
val = parseExpression();
}
expect(_parenR);
// if '=>' follows '(...)', convert contents to arguments
if (metParenL === oldParenL && eat(_arrow)) {
val = parseArrowExpression(node, !val ? [] : val.type === "SequenceExpression" ? val.expressions : [val]);
} else {
// disallow '()' before everything but error
// forbid '()' before everything but '=>'
if (!val) unexpected(lastStart);
}
val.start = tokStart1;
@ -1751,6 +1754,28 @@
case _bracketL:
var node = startNode();
next();
// check whether this is array comprehension or regular array
if (options.ecmaVersion >= 6 && tokType === _for) {
node.blocks = [];
while (tokType === _for) {
var block = startNode();
next();
expect(_parenL);
block.left = toAssignable(parseExprAtom());
checkLVal(block.left, true);
expect(_of);
// `of` property is here for compatibility with Esprima's AST
// which also supports deprecated [for (... in ...) expr]
block.of = true;
block.right = parseExpression();
expect(_parenR);
node.blocks.push(finishNode(block, "ComprehensionBlock"));
}
node.filter = eat(_if) ? parseParenExpression() : null;
node.body = parseExpression();
expect(_bracketR);
return finishNode(node, "ComprehensionExpression");
}
node.elements = parseExprList(_bracketR, true, true);
return finishNode(node, "ArrayExpression");

View File

@ -3513,225 +3513,7 @@ test("x = { set method(val) v = val }", {
// Array Comprehension
test("[[x,b,c] for (x in []) for (b in []) if (b && c)]", {
type: "Program",
body: [{
type: "ExpressionStatement",
expression: {
type: "ComprehensionExpression",
filter: {
type: "LogicalExpression",
operator: "&&",
left: {
type: "Identifier",
name: "b",
range: [41, 42],
loc: {
start: {line: 1, column: 41},
end: {line: 1, column: 42}
}
},
right: {
type: "Identifier",
name: "c",
range: [46, 47],
loc: {
start: {line: 1, column: 46},
end: {line: 1, column: 47}
}
},
range: [41, 47],
loc: {
start: {line: 1, column: 41},
end: {line: 1, column: 47}
}
},
blocks: [
{
type: "ComprehensionBlock",
left: {
type: "Identifier",
name: "x",
range: [14, 15],
loc: {
start: {line: 1, column: 14},
end: {line: 1, column: 15}
}
},
right: {
type: "ArrayExpression",
elements: [],
range: [19, 21],
loc: {
start: {line: 1, column: 19},
end: {line: 1, column: 21}
}
},
each: false,
range: [9, 22],
loc: {
start: {line: 1, column: 9},
end: {line: 1, column: 22}
},
of: false
},
{
type: "ComprehensionBlock",
left: {
type: "Identifier",
name: "b",
range: [28, 29],
loc: {
start: {line: 1, column: 28},
end: {line: 1, column: 29}
}
},
right: {
type: "ArrayExpression",
elements: [],
range: [33, 35],
loc: {
start: {line: 1, column: 33},
end: {line: 1, column: 35}
}
},
each: false,
range: [23, 36],
loc: {
start: {line: 1, column: 23},
end: {line: 1, column: 36}
},
of: false
}
],
body: {
type: "ArrayExpression",
elements: [
{
type: "Identifier",
name: "x",
range: [2, 3],
loc: {
start: {line: 1, column: 2},
end: {line: 1, column: 3}
}
},
{
type: "Identifier",
name: "b",
range: [4, 5],
loc: {
start: {line: 1, column: 4},
end: {line: 1, column: 5}
}
},
{
type: "Identifier",
name: "c",
range: [6, 7],
loc: {
start: {line: 1, column: 6},
end: {line: 1, column: 7}
}
}
],
range: [1, 8],
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 8}
}
},
range: [0, 49],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 49}
}
},
range: [0, 49],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 49}
}
}],
range: [0, 49],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 49}
}
}, {
ecmaVersion: 6,
ranges: true,
locations: true
});
test("[x for (a in [])]", {
type: "Program",
body: [{
type: "ExpressionStatement",
expression: {
type: "ComprehensionExpression",
filter: null,
blocks: [{
type: "ComprehensionBlock",
left: {
type: "Identifier",
name: "a",
range: [8, 9],
loc: {
start: {line: 1, column: 8},
end: {line: 1, column: 9}
}
},
right: {
type: "ArrayExpression",
elements: [],
range: [13, 15],
loc: {
start: {line: 1, column: 13},
end: {line: 1, column: 15}
}
},
each: false,
range: [3, 16],
loc: {
start: {line: 1, column: 3},
end: {line: 1, column: 16}
},
of: false
}],
body: {
type: "Identifier",
name: "x",
range: [1, 2],
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 2}
}
},
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
},
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
}],
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
}, {
ecmaVersion: 6,
ranges: true,
locations: true
});
test("[1 for (x in [])]", {
test("[for (x of array) x]", {
type: "Program",
body: [{
type: "ExpressionStatement",
@ -3743,190 +3525,35 @@ test("[1 for (x in [])]", {
left: {
type: "Identifier",
name: "x",
range: [8, 9],
range: [6, 7],
loc: {
start: {line: 1, column: 8},
end: {line: 1, column: 9}
}
},
right: {
type: "ArrayExpression",
elements: [],
range: [13, 15],
loc: {
start: {line: 1, column: 13},
end: {line: 1, column: 15}
}
},
each: false,
range: [3, 16],
loc: {
start: {line: 1, column: 3},
end: {line: 1, column: 16}
},
of: false
}],
body: {
type: "Literal",
value: 1,
raw: "1",
range: [1, 2],
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 2}
}
},
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
},
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
}],
range: [0, 17],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 17}
}
}, {
ecmaVersion: 6,
ranges: true,
locations: true
});
test("[(x,1) for (x in [])]", {
type: "Program",
body: [{
type: "ExpressionStatement",
expression: {
type: "ComprehensionExpression",
filter: null,
blocks: [{
type: "ComprehensionBlock",
left: {
type: "Identifier",
name: "x",
range: [12, 13],
loc: {
start: {line: 1, column: 12},
end: {line: 1, column: 13}
}
},
right: {
type: "ArrayExpression",
elements: [],
range: [17, 19],
loc: {
start: {line: 1, column: 17},
end: {line: 1, column: 19}
}
},
each: false,
range: [7, 20],
loc: {
start: {line: 1, column: 7},
end: {line: 1, column: 20}
},
of: false
}],
body: {
type: "SequenceExpression",
expressions: [
{
type: "Identifier",
name: "x",
range: [2, 3],
loc: {
start: {line: 1, column: 2},
end: {line: 1, column: 3}
}
},
{
type: "Literal",
value: 1,
raw: "1",
range: [4, 5],
loc: {
start: {line: 1, column: 4},
end: {line: 1, column: 5}
}
}
],
range: [2, 5],
loc: {
start: {line: 1, column: 2},
end: {line: 1, column: 5}
}
},
range: [0, 21],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 21}
}
},
range: [0, 21],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 21}
}
}],
range: [0, 21],
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 21}
}
}, {
ecmaVersion: 6,
ranges: true,
locations: true
});
test("[x for (x of array)]", {
type: "Program",
body: [{
type: "ExpressionStatement",
expression: {
type: "ComprehensionExpression",
filter: null,
blocks: [{
type: "ComprehensionBlock",
left: {
type: "Identifier",
name: "x",
range: [8, 9],
loc: {
start: {line: 1, column: 8},
end: {line: 1, column: 9}
start: {line: 1, column: 6},
end: {line: 1, column: 7}
}
},
right: {
type: "Identifier",
name: "array",
range: [13, 18],
range: [11, 16],
loc: {
start: {line: 1, column: 13},
end: {line: 1, column: 18}
start: {line: 1, column: 11},
end: {line: 1, column: 16}
}
},
range: [3, 19],
range: [1, 17],
loc: {
start: {line: 1, column: 3},
end: {line: 1, column: 19}
start: {line: 1, column: 1},
end: {line: 1, column: 17}
},
of: true
}],
body: {
type: "Identifier",
name: "x",
range: [1, 2],
range: [18, 19],
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 2}
start: {line: 1, column: 18},
end: {line: 1, column: 19}
}
},
range: [0, 20],
@ -3952,7 +3579,7 @@ test("[x for (x of array)]", {
locations: true
});
test("[x for (x of array) for (y of array2) if (x === test)]", {
test("[for (x of array) for (y of array2) if (x === test) x]", {
type: "Program",
body: [{
type: "ExpressionStatement",
@ -3964,25 +3591,25 @@ test("[x for (x of array) for (y of array2) if (x === test)]", {
left: {
type: "Identifier",
name: "x",
range: [42, 43],
range: [40, 41],
loc: {
start: {line: 1, column: 42},
end: {line: 1, column: 43}
start: {line: 1, column: 40},
end: {line: 1, column: 41}
}
},
right: {
type: "Identifier",
name: "test",
range: [48, 52],
range: [46, 50],
loc: {
start: {line: 1, column: 48},
end: {line: 1, column: 52}
start: {line: 1, column: 46},
end: {line: 1, column: 50}
}
},
range: [42, 52],
range: [40, 50],
loc: {
start: {line: 1, column: 42},
end: {line: 1, column: 52}
start: {line: 1, column: 40},
end: {line: 1, column: 50}
}
},
blocks: [
@ -3991,25 +3618,25 @@ test("[x for (x of array) for (y of array2) if (x === test)]", {
left: {
type: "Identifier",
name: "x",
range: [8, 9],
range: [6, 7],
loc: {
start: {line: 1, column: 8},
end: {line: 1, column: 9}
start: {line: 1, column: 6},
end: {line: 1, column: 7}
}
},
right: {
type: "Identifier",
name: "array",
range: [13, 18],
range: [11, 16],
loc: {
start: {line: 1, column: 13},
end: {line: 1, column: 18}
start: {line: 1, column: 11},
end: {line: 1, column: 16}
}
},
range: [3, 19],
range: [1, 17],
loc: {
start: {line: 1, column: 3},
end: {line: 1, column: 19}
start: {line: 1, column: 1},
end: {line: 1, column: 17}
},
of: true
},
@ -4018,25 +3645,25 @@ test("[x for (x of array) for (y of array2) if (x === test)]", {
left: {
type: "Identifier",
name: "y",
range: [25, 26],
range: [23, 24],
loc: {
start: {line: 1, column: 25},
end: {line: 1, column: 26}
start: {line: 1, column: 23},
end: {line: 1, column: 24}
}
},
right: {
type: "Identifier",
name: "array2",
range: [30, 36],
range: [28, 34],
loc: {
start: {line: 1, column: 30},
end: {line: 1, column: 36}
start: {line: 1, column: 28},
end: {line: 1, column: 34}
}
},
range: [20, 37],
range: [18, 35],
loc: {
start: {line: 1, column: 20},
end: {line: 1, column: 37}
start: {line: 1, column: 18},
end: {line: 1, column: 35}
},
of: true
}
@ -4044,10 +3671,10 @@ test("[x for (x of array) for (y of array2) if (x === test)]", {
body: {
type: "Identifier",
name: "x",
range: [1, 2],
range: [52, 53],
loc: {
start: {line: 1, column: 1},
end: {line: 1, column: 2}
start: {line: 1, column: 52},
end: {line: 1, column: 53}
}
},
range: [0, 54],
@ -15921,8 +15548,6 @@ testFail("\"use strict\"; ({ v: eval }) = obj", "Assigning to eval in strict mod
testFail("\"use strict\"; ({ v: arguments }) = obj", "Assigning to arguments in strict mode (1:20)", {ecmaVersion: 6});
testFail("for (var i = function() { return 10 in [] } in list) process(x);", "Unexpected token (1:44)", {ecmaVersion: 6});
testFail("for (let x = 42 in list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6});
testFail("for (let x = 42 of list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6});
@ -16194,23 +15819,17 @@ testFail("`hello ${10;test`", "Unexpected token (1:12)", {ecmaVersion: 6});
testFail("function a() 1 // expression closure is not supported", "Unexpected token (1:13)", {ecmaVersion: 6});
testFail("[a,b if (a)] // (a,b)", "Unexpected token (1:5)", {ecmaVersion: 6});
testFail("[for (let x of []) x]", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("for each (let x in {}) {};", "Unexpected token (1:4)", {ecmaVersion: 6});
testFail("[for (const x of []) x]", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("[x for (let x in [])]", "Unexpected token (1:21)", {ecmaVersion: 6});
testFail("[for (var x of []) x]", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("[x for (const x in [])]", "Unexpected token (1:23)", {ecmaVersion: 6});
testFail("[for (a in []) x] // (a,b) ", "Unexpected token (1:8)", {ecmaVersion: 6});
testFail("[x for (var x in [])]", "Unexpected token (1:21)", {ecmaVersion: 6});
testFail("var a = [if (x) x]", "Unexpected token (1:9)", {ecmaVersion: 6});
testFail("[a,b for (a in [])] // (a,b) ", "Unexpected token (1:5)", {ecmaVersion: 6});
testFail("[x if (x)] // block required", "Unexpected token (1:11)", {ecmaVersion: 6});
testFail("var a = [x if (x)]", "Unexpected token (1:19)", {ecmaVersion: 6});
testFail("[for (x in [])] // no espression", "Unexpected token (1:16)", {ecmaVersion: 6});
testFail("[for (x of [])] // no expression", "Unexpected token (1:14)", {ecmaVersion: 6});
testFail("({ \"chance\" }) = obj", "Unexpected token (1:12)", {ecmaVersion: 6});