[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}
This commit is contained in:
parent
e25058b0b7
commit
aca4735bec
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user