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