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