• 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(Block * block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZoneList<const AstRawString * > * names,bool * ok)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 
RewriteDestructuringAssignment(Parser * parser,RewritableExpression * to_rewrite,Scope * scope)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 
RewriteDestructuringAssignment(Parser * parser,Assignment * assignment,Scope * scope)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 
IsAssignmentContext(PatternContext c) const69 bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const {
70   return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER;
71 }
72 
73 
IsBindingContext(PatternContext c) const74 bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const {
75   return c == BINDING || c == INITIALIZER;
76 }
77 
78 
79 Parser::PatternRewriter::PatternContext
SetAssignmentContextIfNeeded(Expression * node)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
SetInitializerContextIfNeeded(Expression * node)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 
VisitVariableProxy(VariableProxy * pattern)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 
CreateTempVar(Expression * value)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 
VisitRewritableExpression(RewritableExpression * node)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
RewriteParameterScopes(Expression * expr)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 
VisitObjectLiteral(ObjectLiteral * pattern,Variable ** temp_var)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 
VisitObjectLiteral(ObjectLiteral * node)438 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
439   Variable* temp_var = nullptr;
440   VisitObjectLiteral(node, &temp_var);
441 }
442 
443 
VisitArrayLiteral(ArrayLiteral * node,Variable ** temp_var)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 
VisitArrayLiteral(ArrayLiteral * node)685 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
686   Variable* temp_var = nullptr;
687   VisitArrayLiteral(node, &temp_var);
688 }
689 
690 
VisitAssignment(Assignment * node)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 
VisitProperty(v8::internal::Property * node)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 
Visit(AstNode * node)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