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