blob: e699255cdb38b8932fdd2dbf10b718f8d21bfd80 [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 }
275 } else if (value != nullptr && (descriptor_->mode == CONST_LEGACY ||
276 IsLexicalVariableMode(descriptor_->mode))) {
277 // Constant initializations always assign to the declared constant which
278 // is always at the function scope level. This is only relevant for
279 // dynamically looked-up variables and constants (the
280 // start context for constant lookups is always the function context,
281 // while it is the top context for var declared variables). Sigh...
282 // For 'let' and 'const' declared variables in harmony mode the
283 // initialization also always assigns to the declared variable.
284 DCHECK_NOT_NULL(proxy);
285 DCHECK_NOT_NULL(proxy->var());
286 DCHECK_NOT_NULL(value);
287 // Add break location for destructured sub-pattern.
Ben Murdochda12d292016-06-02 14:46:10 +0100288 int pos = IsSubPattern() ? pattern->position() : value->position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 Assignment* assignment =
290 factory()->NewAssignment(Token::INIT, proxy, value, pos);
291 block_->statements()->Add(
292 factory()->NewExpressionStatement(assignment, pos), zone());
293 value = NULL;
294 }
295
296 // Add an assignment node to the initialization statement block if we still
297 // have a pending initialization value.
298 if (value != NULL) {
299 DCHECK(descriptor_->mode == VAR);
300 // 'var' initializations are simply assignments (with all the consequences
301 // if they are inside a 'with' statement - they may change a 'with' object
302 // property).
303 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
304 // Add break location for destructured sub-pattern.
Ben Murdochda12d292016-06-02 14:46:10 +0100305 int pos = IsSubPattern() ? pattern->position() : value->position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 Assignment* assignment =
307 factory()->NewAssignment(Token::INIT, proxy, value, pos);
308 block_->statements()->Add(
309 factory()->NewExpressionStatement(assignment, pos), zone());
310 }
311}
312
313
314Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
315 auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
316 if (value != nullptr) {
317 auto assignment = factory()->NewAssignment(
318 Token::ASSIGN, factory()->NewVariableProxy(temp), value,
319 RelocInfo::kNoPosition);
320
321 block_->statements()->Add(
322 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
323 zone());
324 }
325 return temp;
326}
327
328
Ben Murdoch097c5b22016-05-18 11:27:45 +0100329void Parser::PatternRewriter::VisitRewritableExpression(
330 RewritableExpression* node) {
331 // If this is not a destructuring assignment...
332 if (!IsAssignmentContext() || !node->expression()->IsAssignment()) {
333 // Mark the node as rewritten to prevent redundant rewriting, and
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 // perform BindingPattern rewriting
335 DCHECK(!node->is_rewritten());
336 node->Rewrite(node->expression());
337 return node->expression()->Accept(this);
338 }
339
340 if (node->is_rewritten()) return;
341 DCHECK(IsAssignmentContext());
342 Assignment* assign = node->expression()->AsAssignment();
343 DCHECK_NOT_NULL(assign);
344 DCHECK_EQ(Token::ASSIGN, assign->op());
345
346 auto initializer = assign->value();
347 auto value = initializer;
348
349 if (IsInitializerContext()) {
350 // let {<pattern> = <init>} = <value>
351 // becomes
352 // temp = <value>;
353 // <pattern> = temp === undefined ? <init> : temp;
354 auto temp_var = CreateTempVar(current_value_);
355 Expression* is_undefined = factory()->NewCompareOperation(
356 Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
357 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
358 RelocInfo::kNoPosition);
359 value = factory()->NewConditional(is_undefined, initializer,
360 factory()->NewVariableProxy(temp_var),
361 RelocInfo::kNoPosition);
362 }
363
364 PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
365 int pos = assign->position();
366 Block* old_block = block_;
Ben Murdochda12d292016-06-02 14:46:10 +0100367 block_ = factory()->NewBlock(nullptr, 8, true, pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 Variable* temp = nullptr;
369 Expression* pattern = assign->target();
370 Expression* old_value = current_value_;
371 current_value_ = value;
372 if (pattern->IsObjectLiteral()) {
373 VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
374 } else {
375 DCHECK(pattern->IsArrayLiteral());
376 VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
377 }
378 DCHECK_NOT_NULL(temp);
379 current_value_ = old_value;
380 Expression* expr = factory()->NewDoExpression(block_, temp, pos);
381 node->Rewrite(expr);
382 block_ = old_block;
383 if (block_) {
384 block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
385 zone());
386 }
387 return set_context(old_context);
388}
389
390
391void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
392 Variable** temp_var) {
393 auto temp = *temp_var = CreateTempVar(current_value_);
394
395 block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
396
397 for (ObjectLiteralProperty* property : *pattern->properties()) {
398 PatternContext context = SetInitializerContextIfNeeded(property->value());
399 RecurseIntoSubpattern(
400 property->value(),
401 factory()->NewProperty(factory()->NewVariableProxy(temp),
402 property->key(), RelocInfo::kNoPosition));
403 set_context(context);
404 }
405}
406
407
408void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
409 Variable* temp_var = nullptr;
410 VisitObjectLiteral(node, &temp_var);
411}
412
413
414void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
415 Variable** temp_var) {
Ben Murdochda12d292016-06-02 14:46:10 +0100416 DCHECK(block_->ignore_completion_value());
417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 auto temp = *temp_var = CreateTempVar(current_value_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 auto iterator = CreateTempVar(parser_->GetIterator(
420 factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
421 auto done = CreateTempVar(
422 factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
423 auto result = CreateTempVar();
424 auto v = CreateTempVar();
Ben Murdochda12d292016-06-02 14:46:10 +0100425 auto completion = CreateTempVar();
426 auto nopos = RelocInfo::kNoPosition;
427
428 // For the purpose of iterator finalization, we temporarily set block_ to a
429 // new block. In the main body of this function, we write to block_ (both
430 // explicitly and implicitly via recursion). At the end of the function, we
431 // wrap this new block in a try-finally statement, restore block_ to its
432 // original value, and add the try-finally statement to block_.
433 auto target = block_;
434 if (FLAG_harmony_iterator_close) {
435 block_ = factory()->NewBlock(nullptr, 8, true, nopos);
436 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437
438 Spread* spread = nullptr;
439 for (Expression* value : *node->values()) {
440 if (value->IsSpread()) {
441 spread = value->AsSpread();
442 break;
443 }
444
445 PatternContext context = SetInitializerContextIfNeeded(value);
Ben Murdochda12d292016-06-02 14:46:10 +0100446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 // if (!done) {
Ben Murdochda12d292016-06-02 14:46:10 +0100448 // done = true; // If .next, .done or .value throws, don't close.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 // result = IteratorNext(iterator);
Ben Murdochda12d292016-06-02 14:46:10 +0100450 // if (result.done) {
451 // v = undefined;
452 // } else {
453 // v = result.value;
454 // done = false;
455 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 // }
Ben Murdochda12d292016-06-02 14:46:10 +0100457 Statement* if_not_done;
458 {
459 auto result_done = factory()->NewProperty(
460 factory()->NewVariableProxy(result),
461 factory()->NewStringLiteral(ast_value_factory()->done_string(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 RelocInfo::kNoPosition),
Ben Murdochda12d292016-06-02 14:46:10 +0100463 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464
Ben Murdochda12d292016-06-02 14:46:10 +0100465 auto assign_undefined = factory()->NewAssignment(
466 Token::ASSIGN, factory()->NewVariableProxy(v),
467 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
468 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469
Ben Murdochda12d292016-06-02 14:46:10 +0100470 auto assign_value = factory()->NewAssignment(
471 Token::ASSIGN, factory()->NewVariableProxy(v),
472 factory()->NewProperty(
473 factory()->NewVariableProxy(result),
474 factory()->NewStringLiteral(ast_value_factory()->value_string(),
475 RelocInfo::kNoPosition),
476 RelocInfo::kNoPosition),
477 RelocInfo::kNoPosition);
478
479 auto unset_done = factory()->NewAssignment(
480 Token::ASSIGN, factory()->NewVariableProxy(done),
481 factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition),
482 RelocInfo::kNoPosition);
483
484 auto inner_else =
485 factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
486 inner_else->statements()->Add(
487 factory()->NewExpressionStatement(assign_value, nopos), zone());
488 inner_else->statements()->Add(
489 factory()->NewExpressionStatement(unset_done, nopos), zone());
490
491 auto inner_if = factory()->NewIfStatement(
492 result_done,
493 factory()->NewExpressionStatement(assign_undefined, nopos),
494 inner_else, nopos);
495
496 auto next_block =
497 factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
498 next_block->statements()->Add(
499 factory()->NewExpressionStatement(
500 factory()->NewAssignment(
501 Token::ASSIGN, factory()->NewVariableProxy(done),
502 factory()->NewBooleanLiteral(true, nopos), nopos),
503 nopos),
504 zone());
505 next_block->statements()->Add(
506 factory()->NewExpressionStatement(
507 parser_->BuildIteratorNextResult(
508 factory()->NewVariableProxy(iterator), result,
509 RelocInfo::kNoPosition),
510 RelocInfo::kNoPosition),
511 zone());
512 next_block->statements()->Add(inner_if, zone());
513
514 if_not_done = factory()->NewIfStatement(
515 factory()->NewUnaryOperation(Token::NOT,
516 factory()->NewVariableProxy(done),
517 RelocInfo::kNoPosition),
518 next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
519 RelocInfo::kNoPosition);
520 }
521 block_->statements()->Add(if_not_done, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522
523 if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
Ben Murdochda12d292016-06-02 14:46:10 +0100524 if (FLAG_harmony_iterator_close) {
525 // completion = kAbruptCompletion;
526 Expression* proxy = factory()->NewVariableProxy(completion);
527 Expression* assignment = factory()->NewAssignment(
528 Token::ASSIGN, proxy,
529 factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
530 block_->statements()->Add(
531 factory()->NewExpressionStatement(assignment, nopos), zone());
532 }
533
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
Ben Murdochda12d292016-06-02 14:46:10 +0100535
536 if (FLAG_harmony_iterator_close) {
537 // completion = kNormalCompletion;
538 Expression* proxy = factory()->NewVariableProxy(completion);
539 Expression* assignment = factory()->NewAssignment(
540 Token::ASSIGN, proxy,
541 factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
542 block_->statements()->Add(
543 factory()->NewExpressionStatement(assignment, nopos), zone());
544 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 }
546 set_context(context);
547 }
548
549 if (spread != nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100550 // A spread can only occur as the last component. It is not handled by
551 // RecurseIntoSubpattern above.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552
Ben Murdochda12d292016-06-02 14:46:10 +0100553 // let array = [];
554 // while (!done) {
555 // result = IteratorNext(iterator);
556 // if (result.done) {
557 // done = true;
558 // } else {
559 // %AppendElement(array, result.value);
560 // }
561 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562
Ben Murdochda12d292016-06-02 14:46:10 +0100563 // let array = [];
564 Variable* array;
565 {
566 auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
567 array = CreateTempVar(factory()->NewArrayLiteral(
568 empty_exprs,
569 // Reuse pattern's literal index - it is unused since there is no
570 // actual literal allocated.
571 node->literal_index(), RelocInfo::kNoPosition));
572 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573
Ben Murdochda12d292016-06-02 14:46:10 +0100574 // result = IteratorNext(iterator);
575 Statement* get_next = factory()->NewExpressionStatement(
576 parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
577 result, nopos),
578 nopos);
579
580 // done = true;
581 Statement* set_done = factory()->NewExpressionStatement(
582 factory()->NewAssignment(
583 Token::ASSIGN, factory()->NewVariableProxy(done),
584 factory()->NewBooleanLiteral(true, nopos), nopos),
585 nopos);
586
587 // %AppendElement(array, result.value);
588 Statement* append_element;
589 {
590 auto args = new (zone()) ZoneList<Expression*>(2, zone());
591 args->Add(factory()->NewVariableProxy(array), zone());
592 args->Add(factory()->NewProperty(
593 factory()->NewVariableProxy(result),
594 factory()->NewStringLiteral(
595 ast_value_factory()->value_string(), nopos),
596 nopos),
597 zone());
598 append_element = factory()->NewExpressionStatement(
599 factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
600 nopos);
601 }
602
603 // if (result.done) { #set_done } else { #append_element }
604 Statement* set_done_or_append;
605 {
606 Expression* result_done =
607 factory()->NewProperty(factory()->NewVariableProxy(result),
608 factory()->NewStringLiteral(
609 ast_value_factory()->done_string(), nopos),
610 nopos);
611 set_done_or_append = factory()->NewIfStatement(result_done, set_done,
612 append_element, nopos);
613 }
614
615 // while (!done) {
616 // #get_next;
617 // #set_done_or_append;
618 // }
619 WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
620 {
621 Expression* condition = factory()->NewUnaryOperation(
622 Token::NOT, factory()->NewVariableProxy(done), nopos);
623 Block* body = factory()->NewBlock(nullptr, 2, true, nopos);
624 body->statements()->Add(get_next, zone());
625 body->statements()->Add(set_done_or_append, zone());
626 loop->Initialize(condition, body);
627 }
628
629 block_->statements()->Add(loop, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 RecurseIntoSubpattern(spread->expression(),
631 factory()->NewVariableProxy(array));
632 }
Ben Murdochda12d292016-06-02 14:46:10 +0100633
634 if (FLAG_harmony_iterator_close) {
635 Expression* closing_condition = factory()->NewUnaryOperation(
636 Token::NOT, factory()->NewVariableProxy(done), nopos);
637 parser_->FinalizeIteratorUse(completion, closing_condition, iterator,
638 block_, target);
639 block_ = target;
640 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641}
642
643
644void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
645 Variable* temp_var = nullptr;
646 VisitArrayLiteral(node, &temp_var);
647}
648
649
650void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
651 // let {<pattern> = <init>} = <value>
652 // becomes
653 // temp = <value>;
654 // <pattern> = temp === undefined ? <init> : temp;
655 DCHECK_EQ(Token::ASSIGN, node->op());
656
657 auto initializer = node->value();
658 auto value = initializer;
659 auto temp = CreateTempVar(current_value_);
660
661 if (IsInitializerContext()) {
662 Expression* is_undefined = factory()->NewCompareOperation(
663 Token::EQ_STRICT, factory()->NewVariableProxy(temp),
664 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
665 RelocInfo::kNoPosition);
666 value = factory()->NewConditional(is_undefined, initializer,
667 factory()->NewVariableProxy(temp),
668 RelocInfo::kNoPosition);
669 }
670
671 if (IsBindingContext() &&
672 descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
673 scope()->is_arrow_scope()) {
674 RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
675 scope()->outer_scope(), scope());
676 }
677
678 PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
679 RecurseIntoSubpattern(node->target(), value);
680 set_context(old_context);
681}
682
683
684// =============== AssignmentPattern only ==================
685
686void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
687 DCHECK(IsAssignmentContext());
688 auto value = current_value_;
689
690 Assignment* assignment =
691 factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
692
693 block_->statements()->Add(
694 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
695 zone());
696}
697
698
699// =============== UNREACHABLE =============================
700
701void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
702
703#define NOT_A_PATTERN(Node) \
704 void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
705 UNREACHABLE(); \
706 }
707
708NOT_A_PATTERN(BinaryOperation)
709NOT_A_PATTERN(Block)
710NOT_A_PATTERN(BreakStatement)
711NOT_A_PATTERN(Call)
712NOT_A_PATTERN(CallNew)
713NOT_A_PATTERN(CallRuntime)
714NOT_A_PATTERN(CaseClause)
715NOT_A_PATTERN(ClassLiteral)
716NOT_A_PATTERN(CompareOperation)
717NOT_A_PATTERN(Conditional)
718NOT_A_PATTERN(ContinueStatement)
719NOT_A_PATTERN(CountOperation)
720NOT_A_PATTERN(DebuggerStatement)
721NOT_A_PATTERN(DoExpression)
722NOT_A_PATTERN(DoWhileStatement)
723NOT_A_PATTERN(EmptyStatement)
724NOT_A_PATTERN(EmptyParentheses)
725NOT_A_PATTERN(ExportDeclaration)
726NOT_A_PATTERN(ExpressionStatement)
727NOT_A_PATTERN(ForInStatement)
728NOT_A_PATTERN(ForOfStatement)
729NOT_A_PATTERN(ForStatement)
730NOT_A_PATTERN(FunctionDeclaration)
731NOT_A_PATTERN(FunctionLiteral)
732NOT_A_PATTERN(IfStatement)
733NOT_A_PATTERN(ImportDeclaration)
734NOT_A_PATTERN(Literal)
735NOT_A_PATTERN(NativeFunctionLiteral)
736NOT_A_PATTERN(RegExpLiteral)
737NOT_A_PATTERN(ReturnStatement)
738NOT_A_PATTERN(SloppyBlockFunctionStatement)
739NOT_A_PATTERN(Spread)
740NOT_A_PATTERN(SuperPropertyReference)
741NOT_A_PATTERN(SuperCallReference)
742NOT_A_PATTERN(SwitchStatement)
743NOT_A_PATTERN(ThisFunction)
744NOT_A_PATTERN(Throw)
745NOT_A_PATTERN(TryCatchStatement)
746NOT_A_PATTERN(TryFinallyStatement)
747NOT_A_PATTERN(UnaryOperation)
748NOT_A_PATTERN(VariableDeclaration)
749NOT_A_PATTERN(WhileStatement)
750NOT_A_PATTERN(WithStatement)
751NOT_A_PATTERN(Yield)
752
753#undef NOT_A_PATTERN
754} // namespace internal
755} // namespace v8