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