Home | History | Annotate | Download | only in parsing
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/ast/ast.h"
      6 #include "src/messages.h"
      7 #include "src/parsing/parameter-initializer-rewriter.h"
      8 #include "src/parsing/parser.h"
      9 
     10 namespace v8 {
     11 
     12 namespace internal {
     13 
     14 void Parser::PatternRewriter::DeclareAndInitializeVariables(
     15     Block* block, const DeclarationDescriptor* declaration_descriptor,
     16     const DeclarationParsingResult::Declaration* declaration,
     17     ZoneList<const AstRawString*>* names, bool* ok) {
     18   PatternRewriter rewriter;
     19 
     20   DCHECK(block->ignore_completion_value());
     21 
     22   rewriter.scope_ = declaration_descriptor->scope;
     23   rewriter.parser_ = declaration_descriptor->parser;
     24   rewriter.context_ = BINDING;
     25   rewriter.pattern_ = declaration->pattern;
     26   rewriter.initializer_position_ = declaration->initializer_position;
     27   rewriter.block_ = block;
     28   rewriter.descriptor_ = declaration_descriptor;
     29   rewriter.names_ = names;
     30   rewriter.ok_ = ok;
     31   rewriter.recursion_level_ = 0;
     32 
     33   rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
     34 }
     35 
     36 
     37 void Parser::PatternRewriter::RewriteDestructuringAssignment(
     38     Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
     39   PatternRewriter rewriter;
     40 
     41   DCHECK(!to_rewrite->is_rewritten());
     42 
     43   bool ok = true;
     44   rewriter.scope_ = scope;
     45   rewriter.parser_ = parser;
     46   rewriter.context_ = ASSIGNMENT;
     47   rewriter.pattern_ = to_rewrite;
     48   rewriter.block_ = nullptr;
     49   rewriter.descriptor_ = nullptr;
     50   rewriter.names_ = nullptr;
     51   rewriter.ok_ = &ok;
     52   rewriter.recursion_level_ = 0;
     53 
     54   rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
     55   DCHECK(ok);
     56 }
     57 
     58 
     59 Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
     60     Parser* parser, Assignment* assignment, Scope* scope) {
     61   DCHECK_NOT_NULL(assignment);
     62   DCHECK_EQ(Token::ASSIGN, assignment->op());
     63   auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
     64   RewriteDestructuringAssignment(parser, to_rewrite, scope);
     65   return to_rewrite->expression();
     66 }
     67 
     68 
     69 bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const {
     70   return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER;
     71 }
     72 
     73 
     74 bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const {
     75   return c == BINDING || c == INITIALIZER;
     76 }
     77 
     78 
     79 Parser::PatternRewriter::PatternContext
     80 Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
     81   PatternContext old_context = context();
     82   // AssignmentExpressions may occur in the Initializer position of a
     83   // SingleNameBinding. Such expressions should not prompt a change in the
     84   // pattern's context.
     85   if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
     86       !IsInitializerContext()) {
     87     set_context(ASSIGNMENT);
     88   }
     89   return old_context;
     90 }
     91 
     92 
     93 Parser::PatternRewriter::PatternContext
     94 Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
     95   // Set appropriate initializer context for BindingElement and
     96   // AssignmentElement nodes
     97   PatternContext old_context = context();
     98   bool is_destructuring_assignment =
     99       node->IsRewritableExpression() &&
    100       !node->AsRewritableExpression()->is_rewritten();
    101   bool is_assignment =
    102       node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
    103   if (is_destructuring_assignment || is_assignment) {
    104     switch (old_context) {
    105       case BINDING:
    106         set_context(INITIALIZER);
    107         break;
    108       case ASSIGNMENT:
    109         set_context(ASSIGNMENT_INITIALIZER);
    110         break;
    111       default:
    112         break;
    113     }
    114   }
    115   return old_context;
    116 }
    117 
    118 
    119 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
    120   Expression* value = current_value_;
    121 
    122   if (IsAssignmentContext()) {
    123     // In an assignment context, simply perform the assignment
    124     Assignment* assignment = factory()->NewAssignment(
    125         Token::ASSIGN, pattern, value, pattern->position());
    126     block_->statements()->Add(
    127         factory()->NewExpressionStatement(assignment, pattern->position()),
    128         zone());
    129     return;
    130   }
    131 
    132   descriptor_->scope->RemoveUnresolved(pattern);
    133 
    134   // Declare variable.
    135   // Note that we *always* must treat the initial value via a separate init
    136   // assignment for variables and constants because the value must be assigned
    137   // when the variable is encountered in the source. But the variable/constant
    138   // is declared (and set to 'undefined') upon entering the function within
    139   // which the variable or constant is declared. Only function variables have
    140   // an initial value in the declaration (because they are initialized upon
    141   // entering the function).
    142   //
    143   // If we have a legacy const declaration, in an inner scope, the proxy
    144   // is always bound to the declared variable (independent of possibly
    145   // surrounding 'with' statements).
    146   // For let/const declarations in harmony mode, we can also immediately
    147   // pre-resolve the proxy because it resides in the same scope as the
    148   // declaration.
    149   const AstRawString* name = pattern->raw_name();
    150   VariableProxy* proxy = parser_->NewUnresolved(name, descriptor_->mode);
    151   Declaration* declaration = factory()->NewVariableDeclaration(
    152       proxy, descriptor_->mode, descriptor_->scope,
    153       descriptor_->declaration_pos);
    154   Variable* var =
    155       parser_->Declare(declaration, descriptor_->declaration_kind,
    156                        descriptor_->mode != VAR, ok_, descriptor_->hoist_scope);
    157   if (!*ok_) return;
    158   DCHECK_NOT_NULL(var);
    159   DCHECK(!proxy->is_resolved() || proxy->var() == var);
    160   var->set_initializer_position(initializer_position_);
    161 
    162   DCHECK(initializer_position_ != RelocInfo::kNoPosition);
    163 
    164   Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode)
    165                                  ? descriptor_->scope
    166                                  : descriptor_->scope->DeclarationScope();
    167   if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
    168     parser_->ReportMessage(MessageTemplate::kTooManyVariables);
    169     *ok_ = false;
    170     return;
    171   }
    172   if (names_) {
    173     names_->Add(name, zone());
    174   }
    175 
    176   // Initialize variables if needed. A
    177   // declaration of the form:
    178   //
    179   //    var v = x;
    180   //
    181   // is syntactic sugar for:
    182   //
    183   //    var v; v = x;
    184   //
    185   // In particular, we need to re-lookup 'v' (in scope_, not
    186   // declaration_scope) as it may be a different 'v' than the 'v' in the
    187   // declaration (e.g., if we are inside a 'with' statement or 'catch'
    188   // block).
    189   //
    190   // However, note that const declarations are different! A const
    191   // declaration of the form:
    192   //
    193   //   const c = x;
    194   //
    195   // is *not* syntactic sugar for:
    196   //
    197   //   const c; c = x;
    198   //
    199   // The "variable" c initialized to x is the same as the declared
    200   // one - there is no re-lookup (see the last parameter of the
    201   // Declare() call above).
    202   Scope* initialization_scope = IsImmutableVariableMode(descriptor_->mode)
    203                                     ? declaration_scope
    204                                     : descriptor_->scope;
    205 
    206 
    207   // Global variable declarations must be compiled in a specific
    208   // way. When the script containing the global variable declaration
    209   // is entered, the global variable must be declared, so that if it
    210   // doesn't exist (on the global object itself, see ES5 errata) it
    211   // gets created with an initial undefined value. This is handled
    212   // by the declarations part of the function representing the
    213   // top-level global code; see Runtime::DeclareGlobalVariable. If
    214   // it already exists (in the object or in a prototype), it is
    215   // *not* touched until the variable declaration statement is
    216   // executed.
    217   //
    218   // Executing the variable declaration statement will always
    219   // guarantee to give the global object an own property.
    220   // This way, global variable declarations can shadow
    221   // properties in the prototype chain, but only after the variable
    222   // declaration statement has been executed. This is important in
    223   // browsers where the global object (window) has lots of
    224   // properties defined in prototype objects.
    225   if (initialization_scope->is_script_scope() &&
    226       !IsLexicalVariableMode(descriptor_->mode)) {
    227     // Compute the arguments for the runtime
    228     // call.test-parsing/InitializedDeclarationsInStrictForOfError
    229     ZoneList<Expression*>* arguments =
    230         new (zone()) ZoneList<Expression*>(3, zone());
    231     // We have at least 1 parameter.
    232     arguments->Add(
    233         factory()->NewStringLiteral(name, descriptor_->declaration_pos),
    234         zone());
    235     CallRuntime* initialize;
    236 
    237     if (IsImmutableVariableMode(descriptor_->mode)) {
    238       arguments->Add(value, zone());
    239       // Construct the call to Runtime_InitializeConstGlobal
    240       // and add it to the initialization statement block.
    241       // Note that the function does different things depending on
    242       // the number of arguments (1 or 2).
    243       initialize = factory()->NewCallRuntime(Runtime::kInitializeConstGlobal,
    244                                              arguments, value->position());
    245       value = NULL;  // zap the value to avoid the unnecessary assignment
    246     } else {
    247       // Add language mode.
    248       // We may want to pass singleton to avoid Literal allocations.
    249       LanguageMode language_mode = initialization_scope->language_mode();
    250       arguments->Add(
    251           factory()->NewNumberLiteral(language_mode, RelocInfo::kNoPosition),
    252           zone());
    253 
    254       // Be careful not to assign a value to the global variable if
    255       // we're in a with. The initialization value should not
    256       // necessarily be stored in the global object in that case,
    257       // which is why we need to generate a separate assignment node.
    258       if (value != NULL && !descriptor_->scope->inside_with()) {
    259         arguments->Add(value, zone());
    260         // Construct the call to Runtime_InitializeVarGlobal
    261         // and add it to the initialization statement block.
    262         initialize = factory()->NewCallRuntime(Runtime::kInitializeVarGlobal,
    263                                                arguments, value->position());
    264         value = NULL;  // zap the value to avoid the unnecessary assignment
    265       } else {
    266         initialize = NULL;
    267       }
    268     }
    269 
    270     if (initialize != NULL) {
    271       block_->statements()->Add(
    272           factory()->NewExpressionStatement(initialize, initialize->position()),
    273           zone());
    274     }
    275   } else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) {
    276     // For 'let' and 'const' declared variables the initialization always
    277     // assigns to the declared variable.
    278     DCHECK_NOT_NULL(proxy);
    279     DCHECK_NOT_NULL(proxy->var());
    280     DCHECK_NOT_NULL(value);
    281     // Add break location for destructured sub-pattern.
    282     int pos = IsSubPattern() ? pattern->position() : value->position();
    283     Assignment* assignment =
    284         factory()->NewAssignment(Token::INIT, proxy, value, pos);
    285     block_->statements()->Add(
    286         factory()->NewExpressionStatement(assignment, pos), zone());
    287     value = NULL;
    288   }
    289 
    290   // Add an assignment node to the initialization statement block if we still
    291   // have a pending initialization value.
    292   if (value != NULL) {
    293     DCHECK(descriptor_->mode == VAR);
    294     // 'var' initializations are simply assignments (with all the consequences
    295     // if they are inside a 'with' statement - they may change a 'with' object
    296     // property).
    297     VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
    298     // Add break location for destructured sub-pattern.
    299     int pos = IsSubPattern() ? pattern->position() : value->position();
    300     Assignment* assignment =
    301         factory()->NewAssignment(Token::INIT, proxy, value, pos);
    302     block_->statements()->Add(
    303         factory()->NewExpressionStatement(assignment, pos), zone());
    304   }
    305 }
    306 
    307 
    308 Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
    309   auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
    310   if (value != nullptr) {
    311     auto assignment = factory()->NewAssignment(
    312         Token::ASSIGN, factory()->NewVariableProxy(temp), value,
    313         RelocInfo::kNoPosition);
    314 
    315     block_->statements()->Add(
    316         factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
    317         zone());
    318   }
    319   return temp;
    320 }
    321 
    322 
    323 void Parser::PatternRewriter::VisitRewritableExpression(
    324     RewritableExpression* node) {
    325   // If this is not a destructuring assignment...
    326   if (!IsAssignmentContext() || !node->expression()->IsAssignment()) {
    327     // Mark the node as rewritten to prevent redundant rewriting, and
    328     // perform BindingPattern rewriting
    329     DCHECK(!node->is_rewritten());
    330     node->Rewrite(node->expression());
    331     return node->expression()->Accept(this);
    332   }
    333 
    334   if (node->is_rewritten()) return;
    335   DCHECK(IsAssignmentContext());
    336   Assignment* assign = node->expression()->AsAssignment();
    337   DCHECK_NOT_NULL(assign);
    338   DCHECK_EQ(Token::ASSIGN, assign->op());
    339 
    340   auto initializer = assign->value();
    341   auto value = initializer;
    342 
    343   if (IsInitializerContext()) {
    344     // let {<pattern> = <init>} = <value>
    345     //   becomes
    346     // temp = <value>;
    347     // <pattern> = temp === undefined ? <init> : temp;
    348     auto temp_var = CreateTempVar(current_value_);
    349     Expression* is_undefined = factory()->NewCompareOperation(
    350         Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
    351         factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
    352         RelocInfo::kNoPosition);
    353     value = factory()->NewConditional(is_undefined, initializer,
    354                                       factory()->NewVariableProxy(temp_var),
    355                                       RelocInfo::kNoPosition);
    356   }
    357 
    358   PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
    359   int pos = assign->position();
    360   Block* old_block = block_;
    361   block_ = factory()->NewBlock(nullptr, 8, true, pos);
    362   Variable* temp = nullptr;
    363   Expression* pattern = assign->target();
    364   Expression* old_value = current_value_;
    365   current_value_ = value;
    366   if (pattern->IsObjectLiteral()) {
    367     VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
    368   } else {
    369     DCHECK(pattern->IsArrayLiteral());
    370     VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
    371   }
    372   DCHECK_NOT_NULL(temp);
    373   current_value_ = old_value;
    374   Expression* expr = factory()->NewDoExpression(block_, temp, pos);
    375   node->Rewrite(expr);
    376   block_ = old_block;
    377   if (block_) {
    378     block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
    379                               zone());
    380   }
    381   return set_context(old_context);
    382 }
    383 
    384 // Two cases for scope rewriting the scope of default parameters:
    385 // - Eagerly parsed arrow functions are initially parsed as having
    386 //   expressions in the enclosing scope, but when the arrow is encountered,
    387 //   need to be in the scope of the function.
    388 // - When an extra declaration scope needs to be inserted to account for
    389 //   a sloppy eval in a default parameter or function body, the expressions
    390 //   needs to be in that new inner scope which was added after initial
    391 //   parsing.
    392 // Each of these cases can be handled by rewriting the contents of the
    393 // expression to the current scope. The source scope is typically the outer
    394 // scope when one case occurs; when both cases occur, both scopes need to
    395 // be included as the outer scope. (Both rewritings still need to be done
    396 // to account for lazily parsed arrow functions which hit the second case.)
    397 // TODO(littledan): Remove the outer_scope parameter of
    398 //                  RewriteParameterInitializerScope
    399 void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
    400   if (!IsBindingContext()) return;
    401   if (descriptor_->declaration_kind != DeclarationDescriptor::PARAMETER) return;
    402   if (!scope()->is_arrow_scope() && !scope()->is_block_scope()) return;
    403 
    404   // Either this scope is an arrow scope or a declaration block scope.
    405   DCHECK(scope()->is_declaration_scope());
    406 
    407   if (scope()->outer_scope()->is_arrow_scope() && scope()->is_block_scope()) {
    408     RewriteParameterInitializerScope(parser_->stack_limit(), expr,
    409                                      scope()->outer_scope()->outer_scope(),
    410                                      scope());
    411   }
    412   RewriteParameterInitializerScope(parser_->stack_limit(), expr,
    413                                    scope()->outer_scope(), scope());
    414 }
    415 
    416 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
    417                                                  Variable** temp_var) {
    418   auto temp = *temp_var = CreateTempVar(current_value_);
    419 
    420   block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
    421 
    422   for (ObjectLiteralProperty* property : *pattern->properties()) {
    423     PatternContext context = SetInitializerContextIfNeeded(property->value());
    424 
    425     // Computed property names contain expressions which might require
    426     // scope rewriting.
    427     if (!property->key()->IsLiteral()) RewriteParameterScopes(property->key());
    428 
    429     RecurseIntoSubpattern(
    430         property->value(),
    431         factory()->NewProperty(factory()->NewVariableProxy(temp),
    432                                property->key(), RelocInfo::kNoPosition));
    433     set_context(context);
    434   }
    435 }
    436 
    437 
    438 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
    439   Variable* temp_var = nullptr;
    440   VisitObjectLiteral(node, &temp_var);
    441 }
    442 
    443 
    444 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
    445                                                 Variable** temp_var) {
    446   DCHECK(block_->ignore_completion_value());
    447 
    448   auto temp = *temp_var = CreateTempVar(current_value_);
    449   auto iterator = CreateTempVar(parser_->GetIterator(
    450       factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
    451   auto done = CreateTempVar(
    452       factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
    453   auto result = CreateTempVar();
    454   auto v = CreateTempVar();
    455   auto completion = CreateTempVar();
    456   auto nopos = RelocInfo::kNoPosition;
    457 
    458   // For the purpose of iterator finalization, we temporarily set block_ to a
    459   // new block.  In the main body of this function, we write to block_ (both
    460   // explicitly and implicitly via recursion).  At the end of the function, we
    461   // wrap this new block in a try-finally statement, restore block_ to its
    462   // original value, and add the try-finally statement to block_.
    463   auto target = block_;
    464   block_ = factory()->NewBlock(nullptr, 8, true, nopos);
    465 
    466   Spread* spread = nullptr;
    467   for (Expression* value : *node->values()) {
    468     if (value->IsSpread()) {
    469       spread = value->AsSpread();
    470       break;
    471     }
    472 
    473     PatternContext context = SetInitializerContextIfNeeded(value);
    474 
    475     // if (!done) {
    476     //   done = true;  // If .next, .done or .value throws, don't close.
    477     //   result = IteratorNext(iterator);
    478     //   if (result.done) {
    479     //     v = undefined;
    480     //   } else {
    481     //     v = result.value;
    482     //     done = false;
    483     //   }
    484     // }
    485     Statement* if_not_done;
    486     {
    487       auto result_done = factory()->NewProperty(
    488           factory()->NewVariableProxy(result),
    489           factory()->NewStringLiteral(ast_value_factory()->done_string(),
    490                                       RelocInfo::kNoPosition),
    491           RelocInfo::kNoPosition);
    492 
    493       auto assign_undefined = factory()->NewAssignment(
    494           Token::ASSIGN, factory()->NewVariableProxy(v),
    495           factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
    496           RelocInfo::kNoPosition);
    497 
    498       auto assign_value = factory()->NewAssignment(
    499           Token::ASSIGN, factory()->NewVariableProxy(v),
    500           factory()->NewProperty(
    501               factory()->NewVariableProxy(result),
    502               factory()->NewStringLiteral(ast_value_factory()->value_string(),
    503                                           RelocInfo::kNoPosition),
    504               RelocInfo::kNoPosition),
    505           RelocInfo::kNoPosition);
    506 
    507       auto unset_done = factory()->NewAssignment(
    508           Token::ASSIGN, factory()->NewVariableProxy(done),
    509           factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition),
    510           RelocInfo::kNoPosition);
    511 
    512       auto inner_else =
    513           factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
    514       inner_else->statements()->Add(
    515           factory()->NewExpressionStatement(assign_value, nopos), zone());
    516       inner_else->statements()->Add(
    517           factory()->NewExpressionStatement(unset_done, nopos), zone());
    518 
    519       auto inner_if = factory()->NewIfStatement(
    520           result_done,
    521           factory()->NewExpressionStatement(assign_undefined, nopos),
    522           inner_else, nopos);
    523 
    524       auto next_block =
    525           factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
    526       next_block->statements()->Add(
    527           factory()->NewExpressionStatement(
    528               factory()->NewAssignment(
    529                   Token::ASSIGN, factory()->NewVariableProxy(done),
    530                   factory()->NewBooleanLiteral(true, nopos), nopos),
    531               nopos),
    532           zone());
    533       next_block->statements()->Add(
    534           factory()->NewExpressionStatement(
    535               parser_->BuildIteratorNextResult(
    536                   factory()->NewVariableProxy(iterator), result,
    537                   RelocInfo::kNoPosition),
    538               RelocInfo::kNoPosition),
    539           zone());
    540       next_block->statements()->Add(inner_if, zone());
    541 
    542       if_not_done = factory()->NewIfStatement(
    543           factory()->NewUnaryOperation(Token::NOT,
    544                                        factory()->NewVariableProxy(done),
    545                                        RelocInfo::kNoPosition),
    546           next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
    547           RelocInfo::kNoPosition);
    548     }
    549     block_->statements()->Add(if_not_done, zone());
    550 
    551     if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
    552       {
    553         // completion = kAbruptCompletion;
    554         Expression* proxy = factory()->NewVariableProxy(completion);
    555         Expression* assignment = factory()->NewAssignment(
    556             Token::ASSIGN, proxy,
    557             factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
    558         block_->statements()->Add(
    559             factory()->NewExpressionStatement(assignment, nopos), zone());
    560       }
    561 
    562       RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
    563 
    564       {
    565         // completion = kNormalCompletion;
    566         Expression* proxy = factory()->NewVariableProxy(completion);
    567         Expression* assignment = factory()->NewAssignment(
    568             Token::ASSIGN, proxy,
    569             factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
    570         block_->statements()->Add(
    571             factory()->NewExpressionStatement(assignment, nopos), zone());
    572       }
    573     }
    574     set_context(context);
    575   }
    576 
    577   if (spread != nullptr) {
    578     // A spread can only occur as the last component.  It is not handled by
    579     // RecurseIntoSubpattern above.
    580 
    581     // let array = [];
    582     // while (!done) {
    583     //   done = true;  // If .next, .done or .value throws, don't close.
    584     //   result = IteratorNext(iterator);
    585     //   if (!result.done) {
    586     //     %AppendElement(array, result.value);
    587     //     done = false;
    588     //   }
    589     // }
    590 
    591     // let array = [];
    592     Variable* array;
    593     {
    594       auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
    595       array = CreateTempVar(factory()->NewArrayLiteral(
    596           empty_exprs,
    597           // Reuse pattern's literal index - it is unused since there is no
    598           // actual literal allocated.
    599           node->literal_index(), RelocInfo::kNoPosition));
    600     }
    601 
    602     // done = true;
    603     Statement* set_done = factory()->NewExpressionStatement(
    604         factory()->NewAssignment(
    605             Token::ASSIGN, factory()->NewVariableProxy(done),
    606             factory()->NewBooleanLiteral(true, nopos), nopos),
    607         nopos);
    608 
    609     // result = IteratorNext(iterator);
    610     Statement* get_next = factory()->NewExpressionStatement(
    611         parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
    612                                          result, nopos),
    613         nopos);
    614 
    615     // %AppendElement(array, result.value);
    616     Statement* append_element;
    617     {
    618       auto args = new (zone()) ZoneList<Expression*>(2, zone());
    619       args->Add(factory()->NewVariableProxy(array), zone());
    620       args->Add(factory()->NewProperty(
    621                     factory()->NewVariableProxy(result),
    622                     factory()->NewStringLiteral(
    623                         ast_value_factory()->value_string(), nopos),
    624                     nopos),
    625                 zone());
    626       append_element = factory()->NewExpressionStatement(
    627           factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
    628           nopos);
    629     }
    630 
    631     // done = false;
    632     Statement* unset_done = factory()->NewExpressionStatement(
    633         factory()->NewAssignment(
    634             Token::ASSIGN, factory()->NewVariableProxy(done),
    635             factory()->NewBooleanLiteral(false, nopos), nopos),
    636         nopos);
    637 
    638     // if (!result.done) { #append_element; #unset_done }
    639     Statement* maybe_append_and_unset_done;
    640     {
    641       Expression* result_done =
    642           factory()->NewProperty(factory()->NewVariableProxy(result),
    643                                  factory()->NewStringLiteral(
    644                                      ast_value_factory()->done_string(), nopos),
    645                                  nopos);
    646 
    647       Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
    648       then->statements()->Add(append_element, zone());
    649       then->statements()->Add(unset_done, zone());
    650 
    651       maybe_append_and_unset_done = factory()->NewIfStatement(
    652           factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
    653           factory()->NewEmptyStatement(nopos), nopos);
    654     }
    655 
    656     // while (!done) {
    657     //   #set_done;
    658     //   #get_next;
    659     //   #maybe_append_and_unset_done;
    660     // }
    661     WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
    662     {
    663       Expression* condition = factory()->NewUnaryOperation(
    664           Token::NOT, factory()->NewVariableProxy(done), nopos);
    665       Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
    666       body->statements()->Add(set_done, zone());
    667       body->statements()->Add(get_next, zone());
    668       body->statements()->Add(maybe_append_and_unset_done, zone());
    669       loop->Initialize(condition, body);
    670     }
    671 
    672     block_->statements()->Add(loop, zone());
    673     RecurseIntoSubpattern(spread->expression(),
    674                           factory()->NewVariableProxy(array));
    675   }
    676 
    677   Expression* closing_condition = factory()->NewUnaryOperation(
    678       Token::NOT, factory()->NewVariableProxy(done), nopos);
    679   parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
    680                                target);
    681   block_ = target;
    682 }
    683 
    684 
    685 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
    686   Variable* temp_var = nullptr;
    687   VisitArrayLiteral(node, &temp_var);
    688 }
    689 
    690 
    691 void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
    692   // let {<pattern> = <init>} = <value>
    693   //   becomes
    694   // temp = <value>;
    695   // <pattern> = temp === undefined ? <init> : temp;
    696   DCHECK_EQ(Token::ASSIGN, node->op());
    697 
    698   auto initializer = node->value();
    699   auto value = initializer;
    700   auto temp = CreateTempVar(current_value_);
    701 
    702   if (IsInitializerContext()) {
    703     Expression* is_undefined = factory()->NewCompareOperation(
    704         Token::EQ_STRICT, factory()->NewVariableProxy(temp),
    705         factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
    706         RelocInfo::kNoPosition);
    707     value = factory()->NewConditional(is_undefined, initializer,
    708                                       factory()->NewVariableProxy(temp),
    709                                       RelocInfo::kNoPosition);
    710   }
    711 
    712   // Initializer may have been parsed in the wrong scope.
    713   RewriteParameterScopes(initializer);
    714 
    715   PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
    716   RecurseIntoSubpattern(node->target(), value);
    717   set_context(old_context);
    718 }
    719 
    720 
    721 // =============== AssignmentPattern only ==================
    722 
    723 void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
    724   DCHECK(IsAssignmentContext());
    725   auto value = current_value_;
    726 
    727   Assignment* assignment =
    728       factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
    729 
    730   block_->statements()->Add(
    731       factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
    732       zone());
    733 }
    734 
    735 
    736 // =============== UNREACHABLE =============================
    737 
    738 void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
    739 
    740 #define NOT_A_PATTERN(Node)                                        \
    741   void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
    742     UNREACHABLE();                                                 \
    743   }
    744 
    745 NOT_A_PATTERN(BinaryOperation)
    746 NOT_A_PATTERN(Block)
    747 NOT_A_PATTERN(BreakStatement)
    748 NOT_A_PATTERN(Call)
    749 NOT_A_PATTERN(CallNew)
    750 NOT_A_PATTERN(CallRuntime)
    751 NOT_A_PATTERN(CaseClause)
    752 NOT_A_PATTERN(ClassLiteral)
    753 NOT_A_PATTERN(CompareOperation)
    754 NOT_A_PATTERN(Conditional)
    755 NOT_A_PATTERN(ContinueStatement)
    756 NOT_A_PATTERN(CountOperation)
    757 NOT_A_PATTERN(DebuggerStatement)
    758 NOT_A_PATTERN(DoExpression)
    759 NOT_A_PATTERN(DoWhileStatement)
    760 NOT_A_PATTERN(EmptyStatement)
    761 NOT_A_PATTERN(EmptyParentheses)
    762 NOT_A_PATTERN(ExportDeclaration)
    763 NOT_A_PATTERN(ExpressionStatement)
    764 NOT_A_PATTERN(ForInStatement)
    765 NOT_A_PATTERN(ForOfStatement)
    766 NOT_A_PATTERN(ForStatement)
    767 NOT_A_PATTERN(FunctionDeclaration)
    768 NOT_A_PATTERN(FunctionLiteral)
    769 NOT_A_PATTERN(IfStatement)
    770 NOT_A_PATTERN(ImportDeclaration)
    771 NOT_A_PATTERN(Literal)
    772 NOT_A_PATTERN(NativeFunctionLiteral)
    773 NOT_A_PATTERN(RegExpLiteral)
    774 NOT_A_PATTERN(ReturnStatement)
    775 NOT_A_PATTERN(SloppyBlockFunctionStatement)
    776 NOT_A_PATTERN(Spread)
    777 NOT_A_PATTERN(SuperPropertyReference)
    778 NOT_A_PATTERN(SuperCallReference)
    779 NOT_A_PATTERN(SwitchStatement)
    780 NOT_A_PATTERN(ThisFunction)
    781 NOT_A_PATTERN(Throw)
    782 NOT_A_PATTERN(TryCatchStatement)
    783 NOT_A_PATTERN(TryFinallyStatement)
    784 NOT_A_PATTERN(UnaryOperation)
    785 NOT_A_PATTERN(VariableDeclaration)
    786 NOT_A_PATTERN(WhileStatement)
    787 NOT_A_PATTERN(WithStatement)
    788 NOT_A_PATTERN(Yield)
    789 
    790 #undef NOT_A_PATTERN
    791 }  // namespace internal
    792 }  // namespace v8
    793