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