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