pattern-rewriter.cc 27.6 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/ast/ast.h"
6
#include "src/messages.h"
7
#include "src/objects-inl.h"
8 9
#include "src/parsing/parameter-initializer-rewriter.h"
#include "src/parsing/parser.h"
10 11 12 13 14

namespace v8 {

namespace internal {

15
void Parser::PatternRewriter::DeclareAndInitializeVariables(
16 17
    Parser* parser, Block* block,
    const DeclarationDescriptor* declaration_descriptor,
18 19 20
    const DeclarationParsingResult::Declaration* declaration,
    ZoneList<const AstRawString*>* names, bool* ok) {
  PatternRewriter rewriter;
21

22 23
  DCHECK(block->ignore_completion_value());

24
  rewriter.scope_ = declaration_descriptor->scope;
25
  rewriter.parser_ = parser;
26
  rewriter.context_ = BINDING;
27 28
  rewriter.pattern_ = declaration->pattern;
  rewriter.initializer_position_ = declaration->initializer_position;
29
  rewriter.value_beg_position_ = declaration->value_beg_position;
30 31 32 33
  rewriter.block_ = block;
  rewriter.descriptor_ = declaration_descriptor;
  rewriter.names_ = names;
  rewriter.ok_ = ok;
34
  rewriter.recursion_level_ = 0;
35

36
  rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
37 38 39
}


40
void Parser::PatternRewriter::RewriteDestructuringAssignment(
41
    Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
42
  DCHECK(!scope->HasBeenRemoved());
43 44
  DCHECK(!to_rewrite->is_rewritten());

45
  bool ok = true;
46 47

  PatternRewriter rewriter;
48 49 50 51 52 53 54
  rewriter.scope_ = scope;
  rewriter.parser_ = parser;
  rewriter.context_ = ASSIGNMENT;
  rewriter.pattern_ = to_rewrite;
  rewriter.block_ = nullptr;
  rewriter.descriptor_ = nullptr;
  rewriter.names_ = nullptr;
55
  rewriter.ok_ = &ok;
56
  rewriter.recursion_level_ = 0;
57 58

  rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
59 60 61 62 63 64 65 66
  DCHECK(ok);
}


Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
    Parser* parser, Assignment* assignment, Scope* scope) {
  DCHECK_NOT_NULL(assignment);
  DCHECK_EQ(Token::ASSIGN, assignment->op());
67
  auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
68 69
  RewriteDestructuringAssignment(parser, to_rewrite, scope);
  return to_rewrite->expression();
70 71 72 73 74 75
}


Parser::PatternRewriter::PatternContext
Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
  PatternContext old_context = context();
76 77 78 79 80
  // AssignmentExpressions may occur in the Initializer position of a
  // SingleNameBinding. Such expressions should not prompt a change in the
  // pattern's context.
  if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
      !IsInitializerContext()) {
81 82 83 84 85 86 87 88 89 90 91 92
    set_context(ASSIGNMENT);
  }
  return old_context;
}


Parser::PatternRewriter::PatternContext
Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
  // Set appropriate initializer context for BindingElement and
  // AssignmentElement nodes
  PatternContext old_context = context();
  bool is_destructuring_assignment =
93 94
      node->IsRewritableExpression() &&
      !node->AsRewritableExpression()->is_rewritten();
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
  bool is_assignment =
      node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
  if (is_destructuring_assignment || is_assignment) {
    switch (old_context) {
      case BINDING:
        set_context(INITIALIZER);
        break;
      case ASSIGNMENT:
        set_context(ASSIGNMENT_INITIALIZER);
        break;
      default:
        break;
    }
  }
  return old_context;
}


113 114
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
  Expression* value = current_value_;
115 116 117 118 119 120

  if (IsAssignmentContext()) {
    // In an assignment context, simply perform the assignment
    Assignment* assignment = factory()->NewAssignment(
        Token::ASSIGN, pattern, value, pattern->position());
    block_->statements()->Add(
121
        factory()->NewExpressionStatement(assignment, pattern->position()),
122 123 124 125
        zone());
    return;
  }

126
  descriptor_->scope->RemoveUnresolved(pattern);
127 128 129 130 131 132 133 134 135 136

  // Declare variable.
  // Note that we *always* must treat the initial value via a separate init
  // assignment for variables and constants because the value must be assigned
  // when the variable is encountered in the source. But the variable/constant
  // is declared (and set to 'undefined') upon entering the function within
  // which the variable or constant is declared. Only function variables have
  // an initial value in the declaration (because they are initialized upon
  // entering the function).
  const AstRawString* name = pattern->raw_name();
137 138
  VariableProxy* proxy =
      factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
139
  Declaration* declaration = factory()->NewVariableDeclaration(
140
      proxy, descriptor_->scope, descriptor_->declaration_pos);
141 142 143 144 145 146 147 148 149

  // When an extra declaration scope needs to be inserted to account for
  // a sloppy eval in a default parameter or function body, the parameter
  // needs to be declared in the function's scope, not in the varblock
  // scope which will be used for the initializer expression.
  Scope* outer_function_scope = nullptr;
  if (DeclaresParameterContainingSloppyEval()) {
    outer_function_scope = descriptor_->scope->outer_scope();
  }
150 151 152
  Variable* var = parser_->Declare(
      declaration, descriptor_->declaration_kind, descriptor_->mode,
      Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
153
      outer_function_scope);
154 155
  if (!*ok_) return;
  DCHECK_NOT_NULL(var);
156
  DCHECK(proxy->is_resolved());
yangguo's avatar
yangguo committed
157
  DCHECK(initializer_position_ != kNoSourcePosition);
158
  var->set_initializer_position(initializer_position_);
159

160 161 162 163 164 165
  Scope* declaration_scope =
      outer_function_scope != nullptr
          ? outer_function_scope
          : (IsLexicalVariableMode(descriptor_->mode)
                 ? descriptor_->scope
                 : descriptor_->scope->GetDeclarationScope());
166
  if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
167
    parser_->ReportMessage(MessageTemplate::kTooManyVariables);
168 169 170
    *ok_ = false;
    return;
  }
171 172
  if (names_) {
    names_->Add(name, zone());
173 174
  }

175 176 177
  // If there's no initializer, we're done.
  if (value == nullptr) return;

178
  Scope* var_init_scope = descriptor_->scope;
179 180
  MarkLoopVariableAsAssigned(var_init_scope, proxy->var());

181
  // A declaration of the form:
182 183 184 185 186 187 188
  //
  //    var v = x;
  //
  // is syntactic sugar for:
  //
  //    var v; v = x;
  //
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  // In particular, we need to re-lookup 'v' as it may be a different
  // 'v' than the 'v' in the declaration (e.g., if we are inside a
  // 'with' statement or 'catch' block). Global var declarations
  // also need special treatment.

  if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) {
    // Global variable declarations must be compiled in a specific
    // way. When the script containing the global variable declaration
    // is entered, the global variable must be declared, so that if it
    // doesn't exist (on the global object itself, see ES5 errata) it
    // gets created with an initial undefined value. This is handled
    // by the declarations part of the function representing the
    // top-level global code; see Runtime::DeclareGlobalVariable. If
    // it already exists (in the object or in a prototype), it is
    // *not* touched until the variable declaration statement is
    // executed.
    //
    // Executing the variable declaration statement will always
    // guarantee to give the global object an own property.
    // This way, global variable declarations can shadow
    // properties in the prototype chain, but only after the variable
    // declaration statement has been executed. This is important in
    // browsers where the global object (window) has lots of
    // properties defined in prototype objects.

214 215
    ZoneList<Expression*>* arguments =
        new (zone()) ZoneList<Expression*>(3, zone());
216 217 218
    arguments->Add(
        factory()->NewStringLiteral(name, descriptor_->declaration_pos),
        zone());
219 220 221 222
    arguments->Add(factory()->NewNumberLiteral(var_init_scope->language_mode(),
                                               kNoSourcePosition),
                   zone());
    arguments->Add(value, zone());
223

224 225 226 227 228 229
    CallRuntime* initialize = factory()->NewCallRuntime(
        Runtime::kInitializeVarGlobal, arguments, value->position());
    block_->statements()->Add(
        factory()->NewExpressionStatement(initialize, initialize->position()),
        zone());
  } else {
230 231
    // For 'let' and 'const' declared variables the initialization always
    // assigns to the declared variable.
232 233 234 235 236 237 238
    // But for var declarations we need to do a new lookup.
    if (descriptor_->mode == VAR) {
      proxy = var_init_scope->NewUnresolved(factory(), name);
    } else {
      DCHECK_NOT_NULL(proxy);
      DCHECK_NOT_NULL(proxy->var());
    }
239
    // Add break location for destructured sub-pattern.
240 241 242 243
    int pos = value_beg_position_;
    if (pos == kNoSourcePosition) {
      pos = IsSubPattern() ? pattern->position() : value->position();
    }
244 245
    Assignment* assignment =
        factory()->NewAssignment(Token::INIT, proxy, value, pos);
neis's avatar
neis committed
246
    block_->statements()->Add(
247
        factory()->NewExpressionStatement(assignment, pos), zone());
248 249 250 251
  }
}


252
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
253
  auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
254 255 256
  if (value != nullptr) {
    auto assignment = factory()->NewAssignment(
        Token::ASSIGN, factory()->NewVariableProxy(temp), value,
yangguo's avatar
yangguo committed
257
        kNoSourcePosition);
258

neis's avatar
neis committed
259
    block_->statements()->Add(
yangguo's avatar
yangguo committed
260
        factory()->NewExpressionStatement(assignment, kNoSourcePosition),
261 262
        zone());
  }
263 264 265
  return temp;
}

266

267 268 269
void Parser::PatternRewriter::VisitRewritableExpression(
    RewritableExpression* node) {
  // If this is not a destructuring assignment...
270
  if (!IsAssignmentContext()) {
271
    // Mark the node as rewritten to prevent redundant rewriting, and
272 273 274
    // perform BindingPattern rewriting
    DCHECK(!node->is_rewritten());
    node->Rewrite(node->expression());
275
    return Visit(node->expression());
276 277
  } else if (!node->expression()->IsAssignment()) {
    return Visit(node->expression());
278
  }
279

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  if (node->is_rewritten()) return;
  DCHECK(IsAssignmentContext());
  Assignment* assign = node->expression()->AsAssignment();
  DCHECK_NOT_NULL(assign);
  DCHECK_EQ(Token::ASSIGN, assign->op());

  auto initializer = assign->value();
  auto value = initializer;

  if (IsInitializerContext()) {
    // let {<pattern> = <init>} = <value>
    //   becomes
    // temp = <value>;
    // <pattern> = temp === undefined ? <init> : temp;
    auto temp_var = CreateTempVar(current_value_);
    Expression* is_undefined = factory()->NewCompareOperation(
        Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
yangguo's avatar
yangguo committed
297
        factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
298 299
    value = factory()->NewConditional(is_undefined, initializer,
                                      factory()->NewVariableProxy(temp_var),
yangguo's avatar
yangguo committed
300
                                      kNoSourcePosition);
301 302 303 304 305
  }

  PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
  int pos = assign->position();
  Block* old_block = block_;
306
  block_ = factory()->NewBlock(nullptr, 8, true, pos);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
  Variable* temp = nullptr;
  Expression* pattern = assign->target();
  Expression* old_value = current_value_;
  current_value_ = value;
  if (pattern->IsObjectLiteral()) {
    VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
  } else {
    DCHECK(pattern->IsArrayLiteral());
    VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
  }
  DCHECK_NOT_NULL(temp);
  current_value_ = old_value;
  Expression* expr = factory()->NewDoExpression(block_, temp, pos);
  node->Rewrite(expr);
  block_ = old_block;
  if (block_) {
    block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
                              zone());
  }
326
  set_context(old_context);
327 328
}

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
bool Parser::PatternRewriter::DeclaresParameterContainingSloppyEval() const {
  // Need to check for a binding context to make sure we have a descriptor.
  if (IsBindingContext() &&
      // Only relevant for parameters.
      descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
      // And only when scope is a block scope;
      // without eval, it is a function scope.
      scope()->is_block_scope()) {
    DCHECK(scope()->calls_sloppy_eval());
    DCHECK(scope()->is_declaration_scope());
    DCHECK(scope()->outer_scope()->is_function_scope());
    return true;
  }

  return false;
}

346 347 348 349
// When an extra declaration scope needs to be inserted to account for
// a sloppy eval in a default parameter or function body, the expressions
// needs to be in that new inner scope which was added after initial
// parsing.
350
void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
351 352 353
  if (DeclaresParameterContainingSloppyEval()) {
    ReparentParameterExpressionScope(parser_->stack_limit(), expr, scope());
  }
354
}
355 356 357 358 359

void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
                                                 Variable** temp_var) {
  auto temp = *temp_var = CreateTempVar(current_value_);

360 361 362 363 364 365 366 367 368 369 370
  ZoneList<Expression*>* rest_runtime_callargs = nullptr;
  if (pattern->has_rest_property()) {
    // non_rest_properties_count = pattern->properties()->length - 1;
    // args_length = 1 + non_rest_properties_count because we need to
    // pass temp as well to the runtime function.
    int args_length = pattern->properties()->length();
    rest_runtime_callargs =
        new (zone()) ZoneList<Expression*>(args_length, zone());
    rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
  }

371 372
  block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
                            zone());
373

374
  for (ObjectLiteralProperty* property : *pattern->properties()) {
375
    PatternContext context = SetInitializerContextIfNeeded(property->value());
376 377 378 379 380
    Expression* value;

    if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
      // var { y, [x++]: a, ...c } = temp
      //     becomes
381 382 383
      // var y = temp.y;
      // var temp1 = %ToName(x++);
      // var a = temp[temp1];
384
      // var c;
385
      // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
386 387 388 389 390 391 392 393 394 395 396 397 398
      value = factory()->NewCallRuntime(
          Runtime::kCopyDataPropertiesWithExcludedProperties,
          rest_runtime_callargs, kNoSourcePosition);
    } else {
      Expression* key = property->key();

      if (!key->IsLiteral()) {
        // Computed property names contain expressions which might require
        // scope rewriting.
        RewriteParameterScopes(key);
      }

      if (pattern->has_rest_property()) {
399 400 401 402 403 404 405 406 407 408 409 410 411
        Expression* excluded_property = key;

        if (property->is_computed_name()) {
          DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
          auto args = new (zone()) ZoneList<Expression*>(1, zone());
          args->Add(key, zone());
          auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
              Runtime::kToName, args, kNoSourcePosition));
          key = factory()->NewVariableProxy(to_name_key);
          excluded_property = factory()->NewVariableProxy(to_name_key);
        } else {
          DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
        }
412 413

        DCHECK(rest_runtime_callargs != nullptr);
414
        rest_runtime_callargs->Add(excluded_property, zone());
415
      }
416

417 418 419
      value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
                                     kNoSourcePosition);
    }
420

421
    RecurseIntoSubpattern(property->value(), value);
422
    set_context(context);
423 424 425 426
  }
}


427 428 429 430 431
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
  Variable* temp_var = nullptr;
  VisitObjectLiteral(node, &temp_var);
}

432

433 434
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
                                                Variable** temp_var) {
435
  DCHECK(block_->ignore_completion_value());
436

437
  auto temp = *temp_var = CreateTempVar(current_value_);
438 439 440
  auto iterator = CreateTempVar(factory()->NewGetIterator(
      factory()->NewVariableProxy(temp), IteratorType::kNormal,
      current_value_->position()));
yangguo's avatar
yangguo committed
441 442
  auto done =
      CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
443 444
  auto result = CreateTempVar();
  auto v = CreateTempVar();
445
  auto completion = CreateTempVar();
yangguo's avatar
yangguo committed
446
  auto nopos = kNoSourcePosition;
447 448 449 450 451 452 453

  // For the purpose of iterator finalization, we temporarily set block_ to a
  // new block.  In the main body of this function, we write to block_ (both
  // explicitly and implicitly via recursion).  At the end of the function, we
  // wrap this new block in a try-finally statement, restore block_ to its
  // original value, and add the try-finally statement to block_.
  auto target = block_;
454
  block_ = factory()->NewBlock(nullptr, 8, true, nopos);
455 456

  Spread* spread = nullptr;
457
  for (Expression* value : *node->values()) {
458 459 460 461 462
    if (value->IsSpread()) {
      spread = value->AsSpread();
      break;
    }

463
    PatternContext context = SetInitializerContextIfNeeded(value);
464

465
    // if (!done) {
466
    //   done = true;  // If .next, .done or .value throws, don't close.
467
    //   result = IteratorNext(iterator);
468 469 470 471 472 473
    //   if (result.done) {
    //     v = undefined;
    //   } else {
    //     v = result.value;
    //     done = false;
    //   }
474
    // }
475
    Statement* if_not_done;
476
    {
477 478 479
      auto result_done = factory()->NewProperty(
          factory()->NewVariableProxy(result),
          factory()->NewStringLiteral(ast_value_factory()->done_string(),
yangguo's avatar
yangguo committed
480 481
                                      kNoSourcePosition),
          kNoSourcePosition);
482 483 484

      auto assign_undefined = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(v),
yangguo's avatar
yangguo committed
485
          factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
486 487 488 489 490 491

      auto assign_value = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(v),
          factory()->NewProperty(
              factory()->NewVariableProxy(result),
              factory()->NewStringLiteral(ast_value_factory()->value_string(),
yangguo's avatar
yangguo committed
492 493 494
                                          kNoSourcePosition),
              kNoSourcePosition),
          kNoSourcePosition);
495 496 497

      auto unset_done = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(done),
yangguo's avatar
yangguo committed
498 499
          factory()->NewBooleanLiteral(false, kNoSourcePosition),
          kNoSourcePosition);
500 501

      auto inner_else =
yangguo's avatar
yangguo committed
502
          factory()->NewBlock(nullptr, 2, true, kNoSourcePosition);
503 504 505 506 507 508 509 510 511 512
      inner_else->statements()->Add(
          factory()->NewExpressionStatement(assign_value, nopos), zone());
      inner_else->statements()->Add(
          factory()->NewExpressionStatement(unset_done, nopos), zone());

      auto inner_if = factory()->NewIfStatement(
          result_done,
          factory()->NewExpressionStatement(assign_undefined, nopos),
          inner_else, nopos);

513
      auto next_block =
yangguo's avatar
yangguo committed
514
          factory()->NewBlock(nullptr, 3, true, kNoSourcePosition);
515 516 517 518 519 520 521 522 523 524 525
      next_block->statements()->Add(
          factory()->NewExpressionStatement(
              factory()->NewAssignment(
                  Token::ASSIGN, factory()->NewVariableProxy(done),
                  factory()->NewBooleanLiteral(true, nopos), nopos),
              nopos),
          zone());
      next_block->statements()->Add(
          factory()->NewExpressionStatement(
              parser_->BuildIteratorNextResult(
                  factory()->NewVariableProxy(iterator), result,
526
                  IteratorType::kNormal, kNoSourcePosition),
yangguo's avatar
yangguo committed
527
              kNoSourcePosition),
528
          zone());
529
      next_block->statements()->Add(inner_if, zone());
530

531
      if_not_done = factory()->NewIfStatement(
yangguo's avatar
yangguo committed
532 533 534 535
          factory()->NewUnaryOperation(
              Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
          next_block, factory()->NewEmptyStatement(kNoSourcePosition),
          kNoSourcePosition);
536
    }
537
    block_->statements()->Add(if_not_done, zone());
538 539

    if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
540
      {
541 542 543 544 545 546 547 548 549
        // completion = kAbruptCompletion;
        Expression* proxy = factory()->NewVariableProxy(completion);
        Expression* assignment = factory()->NewAssignment(
            Token::ASSIGN, proxy,
            factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
        block_->statements()->Add(
            factory()->NewExpressionStatement(assignment, nopos), zone());
      }

550
      RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
551

552
      {
553 554 555 556 557 558 559 560
        // completion = kNormalCompletion;
        Expression* proxy = factory()->NewVariableProxy(completion);
        Expression* assignment = factory()->NewAssignment(
            Token::ASSIGN, proxy,
            factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
        block_->statements()->Add(
            factory()->NewExpressionStatement(assignment, nopos), zone());
      }
561
    }
562
    set_context(context);
563
  }
564 565

  if (spread != nullptr) {
566 567 568 569
    // A spread can only occur as the last component.  It is not handled by
    // RecurseIntoSubpattern above.

    // let array = [];
570
    // while (!done) {
571
    //   done = true;  // If .next, .done or .value throws, don't close.
572
    //   result = IteratorNext(iterator);
573
    //   if (!result.done) {
574
    //     %AppendElement(array, result.value);
575
    //     done = false;
576 577 578 579 580 581 582
    //   }
    // }

    // let array = [];
    Variable* array;
    {
      auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
583 584
      array = CreateTempVar(
          factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
585 586
    }

587
    // done = true;
588 589 590 591 592 593
    Statement* set_done = factory()->NewExpressionStatement(
        factory()->NewAssignment(
            Token::ASSIGN, factory()->NewVariableProxy(done),
            factory()->NewBooleanLiteral(true, nopos), nopos),
        nopos);

594 595 596
    // result = IteratorNext(iterator);
    Statement* get_next = factory()->NewExpressionStatement(
        parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
597
                                         result, IteratorType::kNormal, nopos),
598 599
        nopos);

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
    // %AppendElement(array, result.value);
    Statement* append_element;
    {
      auto args = new (zone()) ZoneList<Expression*>(2, zone());
      args->Add(factory()->NewVariableProxy(array), zone());
      args->Add(factory()->NewProperty(
                    factory()->NewVariableProxy(result),
                    factory()->NewStringLiteral(
                        ast_value_factory()->value_string(), nopos),
                    nopos),
                zone());
      append_element = factory()->NewExpressionStatement(
          factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
          nopos);
    }
615

616 617 618 619 620 621 622 623 624
    // done = false;
    Statement* unset_done = factory()->NewExpressionStatement(
        factory()->NewAssignment(
            Token::ASSIGN, factory()->NewVariableProxy(done),
            factory()->NewBooleanLiteral(false, nopos), nopos),
        nopos);

    // if (!result.done) { #append_element; #unset_done }
    Statement* maybe_append_and_unset_done;
625 626 627 628 629 630
    {
      Expression* result_done =
          factory()->NewProperty(factory()->NewVariableProxy(result),
                                 factory()->NewStringLiteral(
                                     ast_value_factory()->done_string(), nopos),
                                 nopos);
631 632 633 634 635 636 637 638

      Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
      then->statements()->Add(append_element, zone());
      then->statements()->Add(unset_done, zone());

      maybe_append_and_unset_done = factory()->NewIfStatement(
          factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
          factory()->NewEmptyStatement(nopos), nopos);
639
    }
640

641
    // while (!done) {
642
    //   #set_done;
643
    //   #get_next;
644
    //   #maybe_append_and_unset_done;
645 646 647 648 649
    // }
    WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
    {
      Expression* condition = factory()->NewUnaryOperation(
          Token::NOT, factory()->NewVariableProxy(done), nopos);
650 651
      Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
      body->statements()->Add(set_done, zone());
652
      body->statements()->Add(get_next, zone());
653
      body->statements()->Add(maybe_append_and_unset_done, zone());
654 655
      loop->Initialize(condition, body);
    }
656

657
    block_->statements()->Add(loop, zone());
658 659 660
    RecurseIntoSubpattern(spread->expression(),
                          factory()->NewVariableProxy(array));
  }
661

662 663
  Expression* closing_condition = factory()->NewUnaryOperation(
      Token::NOT, factory()->NewVariableProxy(done), nopos);
664 665

  parser_->FinalizeIteratorUse(scope(), completion, closing_condition, iterator,
666
                               block_, target, IteratorType::kNormal);
667
  block_ = target;
668 669 670
}


671 672 673 674 675 676
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
  Variable* temp_var = nullptr;
  VisitArrayLiteral(node, &temp_var);
}


677
void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
678 679 680 681
  // let {<pattern> = <init>} = <value>
  //   becomes
  // temp = <value>;
  // <pattern> = temp === undefined ? <init> : temp;
682 683 684 685
  DCHECK_EQ(Token::ASSIGN, node->op());

  auto initializer = node->value();
  auto value = initializer;
686
  auto temp = CreateTempVar(current_value_);
687 688 689 690

  if (IsInitializerContext()) {
    Expression* is_undefined = factory()->NewCompareOperation(
        Token::EQ_STRICT, factory()->NewVariableProxy(temp),
yangguo's avatar
yangguo committed
691
        factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
692 693
    value = factory()->NewConditional(is_undefined, initializer,
                                      factory()->NewVariableProxy(temp),
yangguo's avatar
yangguo committed
694
                                      kNoSourcePosition);
695
  }
696

697 698
  // Initializer may have been parsed in the wrong scope.
  RewriteParameterScopes(initializer);
699 700

  PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
701
  RecurseIntoSubpattern(node->target(), value);
702 703 704 705 706 707 708 709 710 711 712 713 714 715
  set_context(old_context);
}


// =============== AssignmentPattern only ==================

void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
  DCHECK(IsAssignmentContext());
  auto value = current_value_;

  Assignment* assignment =
      factory()->NewAssignment(Token::ASSIGN, node, value, node->position());

  block_->statements()->Add(
yangguo's avatar
yangguo committed
716
      factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
}


// =============== UNREACHABLE =============================

#define NOT_A_PATTERN(Node)                                        \
  void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
    UNREACHABLE();                                                 \
  }

NOT_A_PATTERN(BinaryOperation)
NOT_A_PATTERN(Block)
NOT_A_PATTERN(BreakStatement)
NOT_A_PATTERN(Call)
NOT_A_PATTERN(CallNew)
NOT_A_PATTERN(CallRuntime)
NOT_A_PATTERN(CaseClause)
NOT_A_PATTERN(ClassLiteral)
NOT_A_PATTERN(CompareOperation)
NOT_A_PATTERN(Conditional)
NOT_A_PATTERN(ContinueStatement)
NOT_A_PATTERN(CountOperation)
NOT_A_PATTERN(DebuggerStatement)
740
NOT_A_PATTERN(DoExpression)
741 742
NOT_A_PATTERN(DoWhileStatement)
NOT_A_PATTERN(EmptyStatement)
743
NOT_A_PATTERN(EmptyParentheses)
744 745 746 747 748 749
NOT_A_PATTERN(ExpressionStatement)
NOT_A_PATTERN(ForInStatement)
NOT_A_PATTERN(ForOfStatement)
NOT_A_PATTERN(ForStatement)
NOT_A_PATTERN(FunctionDeclaration)
NOT_A_PATTERN(FunctionLiteral)
750
NOT_A_PATTERN(GetIterator)
751
NOT_A_PATTERN(IfStatement)
752
NOT_A_PATTERN(ImportCallExpression)
753 754 755 756
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
NOT_A_PATTERN(RegExpLiteral)
NOT_A_PATTERN(ReturnStatement)
757 758
NOT_A_PATTERN(SloppyBlockFunctionStatement)
NOT_A_PATTERN(Spread)
759 760
NOT_A_PATTERN(SuperPropertyReference)
NOT_A_PATTERN(SuperCallReference)
761 762 763 764 765 766 767 768 769
NOT_A_PATTERN(SwitchStatement)
NOT_A_PATTERN(ThisFunction)
NOT_A_PATTERN(Throw)
NOT_A_PATTERN(TryCatchStatement)
NOT_A_PATTERN(TryFinallyStatement)
NOT_A_PATTERN(UnaryOperation)
NOT_A_PATTERN(VariableDeclaration)
NOT_A_PATTERN(WhileStatement)
NOT_A_PATTERN(WithStatement)
770
NOT_A_PATTERN(Suspend)
771
NOT_A_PATTERN(YieldStar)
772 773

#undef NOT_A_PATTERN
774 775
}  // namespace internal
}  // namespace v8