Commit aca4735b authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Implement spread binding patterns.

R=arv@chromium.org,rossberg@chromium.org
BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1151503002

Cr-Commit-Position: refs/heads/master@{#28522}
parent e25058b0
......@@ -234,6 +234,7 @@ class AstValue : public ZoneObject {
#define STRING_CONSTANTS(F) \
F(anonymous_function, "(anonymous function)") \
F(arguments, "arguments") \
F(concat_iterable_to_array, "$concatIterableToArray") \
F(constructor, "constructor") \
F(default, "default") \
F(done, "done") \
......
......@@ -246,7 +246,14 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
auto result = CreateTempVar();
auto v = CreateTempVar();
Spread* spread = nullptr;
for (Expression* value : *node->values()) {
if (value->IsSpread()) {
spread = value->AsSpread();
break;
}
// if (!done) {
// result = IteratorNext(iterator);
// v = (done = result.done) ? undefined : result.value;
......@@ -296,6 +303,39 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
}
}
if (spread != nullptr) {
// array = [];
// if (!done) $concatIterableToArray(array, iterator);
auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
auto array = CreateTempVar(factory()->NewArrayLiteral(
empty_exprs,
// Reuse pattern's literal index - it is unused since there is no
// actual literal allocated.
node->literal_index(), is_strong(descriptor_->parser->language_mode()),
RelocInfo::kNoPosition));
auto arguments = new (zone()) ZoneList<Expression*>(2, zone());
arguments->Add(factory()->NewVariableProxy(array), zone());
arguments->Add(factory()->NewVariableProxy(iterator), zone());
auto spread_into_array_call = factory()->NewCallRuntime(
ast_value_factory()->concat_iterable_to_array_string(), nullptr,
arguments, RelocInfo::kNoPosition);
auto if_statement = factory()->NewIfStatement(
factory()->NewUnaryOperation(Token::NOT,
factory()->NewVariableProxy(done),
RelocInfo::kNoPosition),
factory()->NewExpressionStatement(spread_into_array_call,
RelocInfo::kNoPosition),
factory()->NewEmptyStatement(RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
block_->AddStatement(if_statement, zone());
RecurseIntoSubpattern(spread->expression(),
factory()->NewVariableProxy(array));
}
}
......
......@@ -2497,6 +2497,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
this->NewExpressionList(4, zone_);
Expect(Token::LBRACK, CHECK_OK);
while (peek() != Token::RBRACK) {
bool seen_spread = false;
ExpressionT elem = this->EmptyExpression();
if (peek() == Token::COMMA) {
if (is_strong(language_mode())) {
......@@ -2506,11 +2507,23 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
return this->EmptyExpression();
}
elem = this->GetLiteralTheHole(peek_position(), factory());
} else if (peek() == Token::ELLIPSIS) {
ExpressionUnexpectedToken(classifier);
int start_pos = peek_position();
Consume(Token::ELLIPSIS);
ExpressionT argument =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
elem = factory()->NewSpread(argument, start_pos);
seen_spread = true;
} else {
elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
}
values->Add(elem, zone_);
if (peek() != Token::RBRACK) {
if (seen_spread) {
BindingPatternUnexpectedToken(classifier);
}
Expect(Token::COMMA, CHECK_OK);
}
}
......
......@@ -932,6 +932,14 @@ function SameValueZero(x, y) {
return x === y;
}
function ConcatIterableToArray(target, iterable) {
var index = target.length;
for (var element of iterable) {
%AddElement(target, index++, element, NONE);
}
return target;
}
/* ---------------------------------
- - - U t i l i t i e s - - -
......@@ -1010,6 +1018,7 @@ function ToPositiveInteger(x, rangeErrorIndex) {
//----------------------------------------------------------------------------
$concatIterableToArray = ConcatIterableToArray;
$defaultNumber = DefaultNumber;
$defaultString = DefaultString;
$NaN = %GetRootNaN();
......
......@@ -6395,6 +6395,9 @@ TEST(DestructuringPositiveTests) {
"{[1+1] : z}",
"{[foo()] : z}",
"{}",
"[...rest]",
"[a,b,...rest]",
"[a,,...rest]",
NULL};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals,
......@@ -6467,6 +6470,15 @@ TEST(DestructuringNegativeTests) {
"{x : x += a}",
"{m() {} = 0}",
"{[1+1]}",
"[...rest, x]",
"[a,b,...rest, x]",
"[a,,...rest, x]",
"[...rest,]",
"[a,b,...rest,]",
"[a,,...rest,]",
"[...rest,...rest1]",
"[a,b,...rest,...rest1]",
"[a,,..rest,...rest1]",
NULL};
// clang-format on
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
......
......@@ -463,6 +463,34 @@
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
var [a, ...rest] = f();
assertSame(1, a);
assertArrayEquals([2,3], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
var [a, b, c, ...rest] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertArrayEquals([], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
var [a, b, c, d, ...rest] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals([], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
}());
......@@ -533,10 +561,37 @@
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
let [a, ...rest] = f();
assertSame(1, a);
assertArrayEquals([2,3], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
let [a, b, c, ...rest] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertArrayEquals([], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
let [a, b, c, d, ...rest] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals([], rest);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
}());
(function TestIteratorsRecursive() {
var log = [];
function* f() {
log.push("1");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment