blob: 970231bc751bfaed4b25b87c76d3a8063f719997 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdochda12d292016-06-02 14:46:10 +010020 DCHECK(block->ignore_completion_value());
21
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 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(
Ben Murdoch097c5b22016-05-18 11:27:45 +010038 Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039 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());
Ben Murdoch097c5b22016-05-18 11:27:45 +010063 auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064 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();
Ben Murdoch097c5b22016-05-18 11:27:45 +010082 // 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()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 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 =
Ben Murdoch097c5b22016-05-18 11:27:45 +010099 node->IsRewritableExpression() &&
100 !node->AsRewritableExpression()->is_rewritten();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 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());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 // 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).
Ben Murdochda12d292016-06-02 14:46:10 +0100243 initialize = factory()->NewCallRuntime(Runtime::kInitializeConstGlobal,
244 arguments, value->position());
245 value = NULL; // zap the value to avoid the unnecessary assignment
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 } else {
247 // Add language mode.
248 // We may want to pass singleton to avoid Literal allocations.
249 LanguageMode language_mode = initialization_scope->language_mode();
Ben Murdochda12d292016-06-02 14:46:10 +0100250 arguments->Add(
251 factory()->NewNumberLiteral(language_mode, RelocInfo::kNoPosition),
252 zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253
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());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 // Construct the call to Runtime_InitializeVarGlobal
261 // and add it to the initialization statement block.
Ben Murdochda12d292016-06-02 14:46:10 +0100262 initialize = factory()->NewCallRuntime(Runtime::kInitializeVarGlobal,
263 arguments, value->position());
264 value = NULL; // zap the value to avoid the unnecessary assignment
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 } else {
266 initialize = NULL;
267 }
268 }
269
270 if (initialize != NULL) {
271 block_->statements()->Add(
Ben Murdochda12d292016-06-02 14:46:10 +0100272 factory()->NewExpressionStatement(initialize, initialize->position()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 zone());
274 }
Ben Murdochc5610432016-08-08 18:44:38 +0100275 } else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) {
276 // For 'let' and 'const' declared variables the initialization always
277 // assigns to the declared variable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 DCHECK_NOT_NULL(proxy);
279 DCHECK_NOT_NULL(proxy->var());
280 DCHECK_NOT_NULL(value);
281 // Add break location for destructured sub-pattern.
Ben Murdochda12d292016-06-02 14:46:10 +0100282 int pos = IsSubPattern() ? pattern->position() : value->position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100299 int pos = IsSubPattern() ? pattern->position() : value->position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 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
Ben Murdoch097c5b22016-05-18 11:27:45 +0100323void 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 // 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_;
Ben Murdochda12d292016-06-02 14:46:10 +0100361 block_ = factory()->NewBlock(nullptr, 8, true, pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 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
Ben Murdochc5610432016-08-08 18:44:38 +0100384// 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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415
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());
Ben Murdochc5610432016-08-08 18:44:38 +0100424
425 // Computed property names contain expressions which might require
426 // scope rewriting.
427 if (!property->key()->IsLiteral()) RewriteParameterScopes(property->key());
428
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 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) {
Ben Murdochda12d292016-06-02 14:46:10 +0100446 DCHECK(block_->ignore_completion_value());
447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 auto temp = *temp_var = CreateTempVar(current_value_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 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();
Ben Murdochda12d292016-06-02 14:46:10 +0100455 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_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100464 block_ = factory()->NewBlock(nullptr, 8, true, nopos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465
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);
Ben Murdochda12d292016-06-02 14:46:10 +0100474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 // if (!done) {
Ben Murdochda12d292016-06-02 14:46:10 +0100476 // done = true; // If .next, .done or .value throws, don't close.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 // result = IteratorNext(iterator);
Ben Murdochda12d292016-06-02 14:46:10 +0100478 // if (result.done) {
479 // v = undefined;
480 // } else {
481 // v = result.value;
482 // done = false;
483 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 // }
Ben Murdochda12d292016-06-02 14:46:10 +0100485 Statement* if_not_done;
486 {
487 auto result_done = factory()->NewProperty(
488 factory()->NewVariableProxy(result),
489 factory()->NewStringLiteral(ast_value_factory()->done_string(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 RelocInfo::kNoPosition),
Ben Murdochda12d292016-06-02 14:46:10 +0100491 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492
Ben Murdochda12d292016-06-02 14:46:10 +0100493 auto assign_undefined = factory()->NewAssignment(
494 Token::ASSIGN, factory()->NewVariableProxy(v),
495 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
496 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497
Ben Murdochda12d292016-06-02 14:46:10 +0100498 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());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550
551 if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100552 {
Ben Murdochda12d292016-06-02 14:46:10 +0100553 // 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
Ben Murdochda12d292016-06-02 14:46:10 +0100563
Ben Murdoch61f157c2016-09-16 13:49:30 +0100564 {
Ben Murdochda12d292016-06-02 14:46:10 +0100565 // 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 }
574 set_context(context);
575 }
576
577 if (spread != nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100578 // A spread can only occur as the last component. It is not handled by
579 // RecurseIntoSubpattern above.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580
Ben Murdochda12d292016-06-02 14:46:10 +0100581 // let array = [];
582 // while (!done) {
Ben Murdochc5610432016-08-08 18:44:38 +0100583 // done = true; // If .next, .done or .value throws, don't close.
Ben Murdochda12d292016-06-02 14:46:10 +0100584 // result = IteratorNext(iterator);
Ben Murdochc5610432016-08-08 18:44:38 +0100585 // if (!result.done) {
Ben Murdochda12d292016-06-02 14:46:10 +0100586 // %AppendElement(array, result.value);
Ben Murdochc5610432016-08-08 18:44:38 +0100587 // done = false;
Ben Murdochda12d292016-06-02 14:46:10 +0100588 // }
589 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590
Ben Murdochda12d292016-06-02 14:46:10 +0100591 // 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601
Ben Murdochda12d292016-06-02 14:46:10 +0100602 // 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
Ben Murdochc5610432016-08-08 18:44:38 +0100609 // result = IteratorNext(iterator);
610 Statement* get_next = factory()->NewExpressionStatement(
611 parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
612 result, nopos),
613 nopos);
614
Ben Murdochda12d292016-06-02 14:46:10 +0100615 // %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
Ben Murdochc5610432016-08-08 18:44:38 +0100631 // 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;
Ben Murdochda12d292016-06-02 14:46:10 +0100640 {
641 Expression* result_done =
642 factory()->NewProperty(factory()->NewVariableProxy(result),
643 factory()->NewStringLiteral(
644 ast_value_factory()->done_string(), nopos),
645 nopos);
Ben Murdochc5610432016-08-08 18:44:38 +0100646
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);
Ben Murdochda12d292016-06-02 14:46:10 +0100654 }
655
656 // while (!done) {
Ben Murdochc5610432016-08-08 18:44:38 +0100657 // #set_done;
Ben Murdochda12d292016-06-02 14:46:10 +0100658 // #get_next;
Ben Murdochc5610432016-08-08 18:44:38 +0100659 // #maybe_append_and_unset_done;
Ben Murdochda12d292016-06-02 14:46:10 +0100660 // }
661 WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
662 {
663 Expression* condition = factory()->NewUnaryOperation(
664 Token::NOT, factory()->NewVariableProxy(done), nopos);
Ben Murdochc5610432016-08-08 18:44:38 +0100665 Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
666 body->statements()->Add(set_done, zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100667 body->statements()->Add(get_next, zone());
Ben Murdochc5610432016-08-08 18:44:38 +0100668 body->statements()->Add(maybe_append_and_unset_done, zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100669 loop->Initialize(condition, body);
670 }
671
672 block_->statements()->Add(loop, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000673 RecurseIntoSubpattern(spread->expression(),
674 factory()->NewVariableProxy(array));
675 }
Ben Murdochda12d292016-06-02 14:46:10 +0100676
Ben Murdoch61f157c2016-09-16 13:49:30 +0100677 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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682}
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
Ben Murdochc5610432016-08-08 18:44:38 +0100712 // Initializer may have been parsed in the wrong scope.
713 RewriteParameterScopes(initializer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714
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