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
10namespace v8 {
11
12namespace internal {
13
14void 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
37void 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
59Expression* 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
69bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const {
70  return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER;
71}
72
73
74bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const {
75  return c == BINDING || c == INITIALIZER;
76}
77
78
79Parser::PatternRewriter::PatternContext
80Parser::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
93Parser::PatternRewriter::PatternContext
94Parser::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
119void 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
308Variable* 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
323void 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
399void 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
416void 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
438void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
439  Variable* temp_var = nullptr;
440  VisitObjectLiteral(node, &temp_var);
441}
442
443
444void 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
685void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
686  Variable* temp_var = nullptr;
687  VisitArrayLiteral(node, &temp_var);
688}
689
690
691void 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
723void 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
738void 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
745NOT_A_PATTERN(BinaryOperation)
746NOT_A_PATTERN(Block)
747NOT_A_PATTERN(BreakStatement)
748NOT_A_PATTERN(Call)
749NOT_A_PATTERN(CallNew)
750NOT_A_PATTERN(CallRuntime)
751NOT_A_PATTERN(CaseClause)
752NOT_A_PATTERN(ClassLiteral)
753NOT_A_PATTERN(CompareOperation)
754NOT_A_PATTERN(Conditional)
755NOT_A_PATTERN(ContinueStatement)
756NOT_A_PATTERN(CountOperation)
757NOT_A_PATTERN(DebuggerStatement)
758NOT_A_PATTERN(DoExpression)
759NOT_A_PATTERN(DoWhileStatement)
760NOT_A_PATTERN(EmptyStatement)
761NOT_A_PATTERN(EmptyParentheses)
762NOT_A_PATTERN(ExportDeclaration)
763NOT_A_PATTERN(ExpressionStatement)
764NOT_A_PATTERN(ForInStatement)
765NOT_A_PATTERN(ForOfStatement)
766NOT_A_PATTERN(ForStatement)
767NOT_A_PATTERN(FunctionDeclaration)
768NOT_A_PATTERN(FunctionLiteral)
769NOT_A_PATTERN(IfStatement)
770NOT_A_PATTERN(ImportDeclaration)
771NOT_A_PATTERN(Literal)
772NOT_A_PATTERN(NativeFunctionLiteral)
773NOT_A_PATTERN(RegExpLiteral)
774NOT_A_PATTERN(ReturnStatement)
775NOT_A_PATTERN(SloppyBlockFunctionStatement)
776NOT_A_PATTERN(Spread)
777NOT_A_PATTERN(SuperPropertyReference)
778NOT_A_PATTERN(SuperCallReference)
779NOT_A_PATTERN(SwitchStatement)
780NOT_A_PATTERN(ThisFunction)
781NOT_A_PATTERN(Throw)
782NOT_A_PATTERN(TryCatchStatement)
783NOT_A_PATTERN(TryFinallyStatement)
784NOT_A_PATTERN(UnaryOperation)
785NOT_A_PATTERN(VariableDeclaration)
786NOT_A_PATTERN(WhileStatement)
787NOT_A_PATTERN(WithStatement)
788NOT_A_PATTERN(Yield)
789
790#undef NOT_A_PATTERN
791}  // namespace internal
792}  // namespace v8
793