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
DeclareAndInitializeVariables(Parser * parser,Block * block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZoneList<const AstRawString * > * names,bool * ok)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
RewriteDestructuringAssignment(Parser * parser,RewritableExpression * to_rewrite,Scope * scope)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
RewriteDestructuringAssignment(Parser * parser,Assignment * assignment,Scope * scope)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
SetAssignmentContextIfNeeded(Expression * node)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
SetInitializerContextIfNeeded(Expression * node)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
VisitVariableProxy(VariableProxy * pattern)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
CreateTempVar(Expression * value)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
VisitRewritableExpression(RewritableExpression * node)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
DeclaresParameterContainingSloppyEval() const325 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.
RewriteParameterScopes(Expression * expr)346 void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
347 if (DeclaresParameterContainingSloppyEval()) {
348 ReparentParameterExpressionScope(parser_->stack_limit(), expr, scope());
349 }
350 }
351
VisitObjectLiteral(ObjectLiteral * pattern,Variable ** temp_var)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
VisitObjectLiteral(ObjectLiteral * node)422 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
423 Variable* temp_var = nullptr;
424 VisitObjectLiteral(node, &temp_var);
425 }
426
427
VisitArrayLiteral(ArrayLiteral * node,Variable ** temp_var)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
VisitArrayLiteral(ArrayLiteral * node)666 void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
667 Variable* temp_var = nullptr;
668 VisitArrayLiteral(node, &temp_var);
669 }
670
671
VisitAssignment(Assignment * node)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
VisitProperty(v8::internal::Property * node)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