[destructuring] Implement BindingArrayPattern
authordslomov <dslomov@chromium.org>
Wed, 20 May 2015 08:08:26 +0000 (01:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 20 May 2015 08:08:14 +0000 (08:08 +0000)
(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}

src/ast-value-factory.h
src/parser.cc
src/parser.h
src/pattern-rewriter.cc
test/mjsunit/harmony/destructuring.js

index 9797611..19a13ce 100644 (file)
@@ -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.
index d70e386..d4607d1 100644 (file)
@@ -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
index e3154f9..22b3a5d 100644 (file)
@@ -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,
index 5871740..52ff8f6 100644 (file)
@@ -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));
+    }
+  }
 }
 
 
index 257c4a1..978c846 100644 (file)
                  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);
+  }());
+}());