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

[destructuring] Implement BindingArrayPattern

(everything except Spread is implemeneted)

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

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

Cr-Commit-Position: refs/heads/master@{#28500}
parent 9a1490ad
......@@ -169,6 +169,8 @@ class AstValue : public ZoneObject {
bool BooleanValue() const;
bool IsTheHole() const { return type_ == THE_HOLE; }
void Internalize(Isolate* isolate);
// Can be called after Internalize has been called.
......
......@@ -3060,6 +3060,48 @@ WhileStatement* Parser::ParseWhileStatement(
}
// !%_IsSpecObject(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
Expression* Parser::BuildIteratorNextResult(Expression* iterator,
Variable* result, int pos) {
Expression* next_literal = factory()->NewStringLiteral(
ast_value_factory()->next_string(), RelocInfo::kNoPosition);
Expression* next_property =
factory()->NewProperty(iterator, next_literal, RelocInfo::kNoPosition);
ZoneList<Expression*>* next_arguments =
new (zone()) ZoneList<Expression*>(0, zone());
Expression* next_call =
factory()->NewCall(next_property, next_arguments, pos);
Expression* result_proxy = factory()->NewVariableProxy(result);
Expression* left =
factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos);
// %_IsSpecObject(...)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
is_spec_object_args->Add(left, zone());
Expression* is_spec_object_call = factory()->NewCallRuntime(
ast_value_factory()->is_spec_object_string(),
Runtime::FunctionForId(Runtime::kInlineIsSpecObject), is_spec_object_args,
pos);
// %ThrowIteratorResultNotAnObject(result)
Expression* result_proxy_again = factory()->NewVariableProxy(result);
ZoneList<Expression*>* throw_arguments =
new (zone()) ZoneList<Expression*>(1, zone());
throw_arguments->Add(result_proxy_again, zone());
Expression* throw_call = factory()->NewCallRuntime(
ast_value_factory()->throw_iterator_result_not_an_object_string(),
Runtime::FunctionForId(Runtime::kThrowIteratorResultNotAnObject),
throw_arguments, pos);
return factory()->NewBinaryOperation(
Token::AND,
factory()->NewUnaryOperation(Token::NOT, is_spec_object_call, pos),
throw_call, pos);
}
void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* each,
Expression* subject,
......@@ -3087,41 +3129,8 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
{
// result = iterator.next()
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
Expression* next_literal = factory()->NewStringLiteral(
ast_value_factory()->next_string(), RelocInfo::kNoPosition);
Expression* next_property = factory()->NewProperty(
iterator_proxy, next_literal, RelocInfo::kNoPosition);
ZoneList<Expression*>* next_arguments =
new (zone()) ZoneList<Expression*>(0, zone());
Expression* next_call = factory()->NewCall(next_property, next_arguments,
subject->position());
Expression* result_proxy = factory()->NewVariableProxy(result);
next_result = factory()->NewAssignment(Token::ASSIGN, result_proxy,
next_call, subject->position());
// %_IsSpecObject(...)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
is_spec_object_args->Add(next_result, zone());
Expression* is_spec_object_call = factory()->NewCallRuntime(
ast_value_factory()->is_spec_object_string(),
Runtime::FunctionForId(Runtime::kInlineIsSpecObject),
is_spec_object_args, subject->position());
// %ThrowIteratorResultNotAnObject(result)
Expression* result_proxy_again = factory()->NewVariableProxy(result);
ZoneList<Expression*>* throw_arguments =
new (zone()) ZoneList<Expression*>(1, zone());
throw_arguments->Add(result_proxy_again, zone());
Expression* throw_call = factory()->NewCallRuntime(
ast_value_factory()->throw_iterator_result_not_an_object_string(),
Runtime::FunctionForId(Runtime::kThrowIteratorResultNotAnObject),
throw_arguments, subject->position());
next_result = factory()->NewBinaryOperation(
Token::AND, factory()->NewUnaryOperation(
Token::NOT, is_spec_object_call, subject->position()),
throw_call, subject->position());
next_result =
BuildIteratorNextResult(iterator_proxy, result, subject->position());
}
// result.done
......
......@@ -1007,7 +1007,7 @@ class Parser : public ParserBase<ParserTraits> {
current_value_ = old_value;
}
Variable* CreateTempVar(Expression* value);
Variable* CreateTempVar(Expression* value = nullptr);
AstNodeFactory* factory() const { return descriptor_->parser->factory(); }
AstValueFactory* ast_value_factory() const {
......@@ -1055,6 +1055,12 @@ class Parser : public ParserBase<ParserTraits> {
// Support for hamony block scoped bindings.
Block* ParseScopedBlock(ZoneList<const AstRawString*>* labels, bool* ok);
// !%_IsSpecObject(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
Expression* BuildIteratorNextResult(Expression* iterator, Variable* result,
int pos);
// Initialize the components of a for-in / for-of statement.
void InitializeForEachStatement(ForEachStatement* stmt,
Expression* each,
......
......@@ -211,13 +211,15 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
auto temp_scope = descriptor_->parser->scope_->DeclarationScope();
auto temp = temp_scope->NewTemporary(ast_value_factory()->empty_string());
auto assignment =
factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
value, RelocInfo::kNoPosition);
if (value != nullptr) {
auto assignment = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), value,
RelocInfo::kNoPosition);
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
}
return temp;
}
......@@ -238,7 +240,62 @@ void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
// TODO(dslomov): implement.
auto iterator = CreateTempVar(
descriptor_->parser->GetIterator(current_value_, factory()));
auto done = CreateTempVar(
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
auto result = CreateTempVar();
auto v = CreateTempVar();
for (Expression* value : *node->values()) {
// if (!done) {
// result = IteratorNext(iterator);
// v = (done = result.done) ? undefined : result.value;
// }
auto next_block =
factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
next_block->AddStatement(factory()->NewExpressionStatement(
descriptor_->parser->BuildIteratorNextResult(
factory()->NewVariableProxy(iterator),
result, RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
zone());
auto assign_to_done = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->done_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto next_value = factory()->NewConditional(
assign_to_done, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->value_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
next_block->AddStatement(
factory()->NewExpressionStatement(
factory()->NewAssignment(Token::ASSIGN,
factory()->NewVariableProxy(v), next_value,
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
zone());
auto if_statement = factory()->NewIfStatement(
factory()->NewUnaryOperation(Token::NOT,
factory()->NewVariableProxy(done),
RelocInfo::kNoPosition),
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
block_->AddStatement(if_statement, zone());
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
}
}
}
......
......@@ -388,3 +388,183 @@
TypeError);
}
}());
(function TestArrayLiteral() {
var [a, b, c] = [1, 2, 3];
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
}());
(function TestIterators() {
var log = [];
function* f() {
log.push("1");
yield 1;
log.push("2");
yield 2;
log.push("3");
yield 3;
log.push("done");
};
(function() {
log = [];
var [a, b, c] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
var [a, b, c, d] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
var [a, , c] = f();
assertSame(1, a);
assertSame(3, c);
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
var [a, , c, d] = f();
assertSame(1, a);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
// last comma is not an elision.
var [a, b,] = f();
assertSame(1, a);
assertSame(2, b);
assertArrayEquals(["1", "2"], log);
}());
(function() {
log = [];
// last comma is not an elision, but the comma before the last is.
var [a, b, ,] = f();
assertSame(1, a);
assertSame(2, b);
assertArrayEquals(["1", "2", "3"], log);
}());
}());
(function TestIteratorsLexical() {
'use strict';
var log = [];
function* f() {
log.push("1");
yield 1;
log.push("2");
yield 2;
log.push("3");
yield 3;
log.push("done");
};
(function() {
log = [];
let [a, b, c] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
let [a, b, c, d] = f();
assertSame(1, a);
assertSame(2, b);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
let [a, , c] = f();
assertSame(1, a);
assertSame(3, c);
assertArrayEquals(["1", "2", "3"], log);
}());
(function() {
log = [];
let [a, , c, d] = f();
assertSame(1, a);
assertSame(3, c);
assertSame(undefined, d);
assertArrayEquals(["1", "2", "3", "done"], log);
}());
(function() {
log = [];
// last comma is not an elision.
let [a, b,] = f();
assertSame(1, a);
assertSame(2, b);
assertArrayEquals(["1", "2"], log);
}());
(function() {
log = [];
// last comma is not an elision, but the comma before the last is.
let [a, b, ,] = f();
assertSame(1, a);
assertSame(2, b);
assertArrayEquals(["1", "2", "3"], log);
}());
}());
(function TestIteratorsRecursive() {
var log = [];
function* f() {
log.push("1");
yield {x : 1, y : 2};
log.push("2");
yield [42, 27, 30];
log.push("3");
yield "abc";
log.push("done");
};
(function() {
var [{x, y}, [a, b]] = f();
assertSame(1, x);
assertSame(2, y);
assertSame(42, a);
assertSame(27, b);
assertArrayEquals(["1", "2"], log);
}());
(function() {
'use strict';
log = [];
let [{x, y}, [a, b]] = f();
assertSame(1, x);
assertSame(2, y);
assertSame(42, a);
assertSame(27, b);
assertArrayEquals(["1", "2"], log);
}());
}());
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