blob: 3dcff983c4ff0d93f85e454090269d79a8939bcd [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_;
464 if (FLAG_harmony_iterator_close) {
465 block_ = factory()->NewBlock(nullptr, 8, true, nopos);
466 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467
468 Spread* spread = nullptr;
469 for (Expression* value : *node->values()) {
470 if (value->IsSpread()) {
471 spread = value->AsSpread();
472 break;
473 }
474
475 PatternContext context = SetInitializerContextIfNeeded(value);
Ben Murdochda12d292016-06-02 14:46:10 +0100476
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 // if (!done) {
Ben Murdochda12d292016-06-02 14:46:10 +0100478 // done = true; // If .next, .done or .value throws, don't close.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 // result = IteratorNext(iterator);
Ben Murdochda12d292016-06-02 14:46:10 +0100480 // if (result.done) {
481 // v = undefined;
482 // } else {
483 // v = result.value;
484 // done = false;
485 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 // }
Ben Murdochda12d292016-06-02 14:46:10 +0100487 Statement* if_not_done;
488 {
489 auto result_done = factory()->NewProperty(
490 factory()->NewVariableProxy(result),
491 factory()->NewStringLiteral(ast_value_factory()->done_string(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 RelocInfo::kNoPosition),
Ben Murdochda12d292016-06-02 14:46:10 +0100493 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494
Ben Murdochda12d292016-06-02 14:46:10 +0100495 auto assign_undefined = factory()->NewAssignment(
496 Token::ASSIGN, factory()->NewVariableProxy(v),
497 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
498 RelocInfo::kNoPosition);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499
Ben Murdochda12d292016-06-02 14:46:10 +0100500 auto assign_value = factory()->NewAssignment(
501 Token::ASSIGN, factory()->NewVariableProxy(v),
502 factory()->NewProperty(
503 factory()->NewVariableProxy(result),
504 factory()->NewStringLiteral(ast_value_factory()->value_string(),
505 RelocInfo::kNoPosition),
506 RelocInfo::kNoPosition),
507 RelocInfo::kNoPosition);
508
509 auto unset_done = factory()->NewAssignment(
510 Token::ASSIGN, factory()->NewVariableProxy(done),
511 factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition),
512 RelocInfo::kNoPosition);
513
514 auto inner_else =
515 factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
516 inner_else->statements()->Add(
517 factory()->NewExpressionStatement(assign_value, nopos), zone());
518 inner_else->statements()->Add(
519 factory()->NewExpressionStatement(unset_done, nopos), zone());
520
521 auto inner_if = factory()->NewIfStatement(
522 result_done,
523 factory()->NewExpressionStatement(assign_undefined, nopos),
524 inner_else, nopos);
525
526 auto next_block =
527 factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
528 next_block->statements()->Add(
529 factory()->NewExpressionStatement(
530 factory()->NewAssignment(
531 Token::ASSIGN, factory()->NewVariableProxy(done),
532 factory()->NewBooleanLiteral(true, nopos), nopos),
533 nopos),
534 zone());
535 next_block->statements()->Add(
536 factory()->NewExpressionStatement(
537 parser_->BuildIteratorNextResult(
538 factory()->NewVariableProxy(iterator), result,
539 RelocInfo::kNoPosition),
540 RelocInfo::kNoPosition),
541 zone());
542 next_block->statements()->Add(inner_if, zone());
543
544 if_not_done = factory()->NewIfStatement(
545 factory()->NewUnaryOperation(Token::NOT,
546 factory()->NewVariableProxy(done),
547 RelocInfo::kNoPosition),
548 next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
549 RelocInfo::kNoPosition);
550 }
551 block_->statements()->Add(if_not_done, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552
553 if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
Ben Murdochda12d292016-06-02 14:46:10 +0100554 if (FLAG_harmony_iterator_close) {
555 // completion = kAbruptCompletion;
556 Expression* proxy = factory()->NewVariableProxy(completion);
557 Expression* assignment = factory()->NewAssignment(
558 Token::ASSIGN, proxy,
559 factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
560 block_->statements()->Add(
561 factory()->NewExpressionStatement(assignment, nopos), zone());
562 }
563
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
Ben Murdochda12d292016-06-02 14:46:10 +0100565
566 if (FLAG_harmony_iterator_close) {
567 // completion = kNormalCompletion;
568 Expression* proxy = factory()->NewVariableProxy(completion);
569 Expression* assignment = factory()->NewAssignment(
570 Token::ASSIGN, proxy,
571 factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
572 block_->statements()->Add(
573 factory()->NewExpressionStatement(assignment, nopos), zone());
574 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000575 }
576 set_context(context);
577 }
578
579 if (spread != nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100580 // A spread can only occur as the last component. It is not handled by
581 // RecurseIntoSubpattern above.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000582
Ben Murdochda12d292016-06-02 14:46:10 +0100583 // let array = [];
584 // while (!done) {
Ben Murdochc5610432016-08-08 18:44:38 +0100585 // done = true; // If .next, .done or .value throws, don't close.
Ben Murdochda12d292016-06-02 14:46:10 +0100586 // result = IteratorNext(iterator);
Ben Murdochc5610432016-08-08 18:44:38 +0100587 // if (!result.done) {
Ben Murdochda12d292016-06-02 14:46:10 +0100588 // %AppendElement(array, result.value);
Ben Murdochc5610432016-08-08 18:44:38 +0100589 // done = false;
Ben Murdochda12d292016-06-02 14:46:10 +0100590 // }
591 // }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592
Ben Murdochda12d292016-06-02 14:46:10 +0100593 // let array = [];
594 Variable* array;
595 {
596 auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
597 array = CreateTempVar(factory()->NewArrayLiteral(
598 empty_exprs,
599 // Reuse pattern's literal index - it is unused since there is no
600 // actual literal allocated.
601 node->literal_index(), RelocInfo::kNoPosition));
602 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603
Ben Murdochda12d292016-06-02 14:46:10 +0100604 // done = true;
605 Statement* set_done = factory()->NewExpressionStatement(
606 factory()->NewAssignment(
607 Token::ASSIGN, factory()->NewVariableProxy(done),
608 factory()->NewBooleanLiteral(true, nopos), nopos),
609 nopos);
610
Ben Murdochc5610432016-08-08 18:44:38 +0100611 // result = IteratorNext(iterator);
612 Statement* get_next = factory()->NewExpressionStatement(
613 parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
614 result, nopos),
615 nopos);
616
Ben Murdochda12d292016-06-02 14:46:10 +0100617 // %AppendElement(array, result.value);
618 Statement* append_element;
619 {
620 auto args = new (zone()) ZoneList<Expression*>(2, zone());
621 args->Add(factory()->NewVariableProxy(array), zone());
622 args->Add(factory()->NewProperty(
623 factory()->NewVariableProxy(result),
624 factory()->NewStringLiteral(
625 ast_value_factory()->value_string(), nopos),
626 nopos),
627 zone());
628 append_element = factory()->NewExpressionStatement(
629 factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
630 nopos);
631 }
632
Ben Murdochc5610432016-08-08 18:44:38 +0100633 // done = false;
634 Statement* unset_done = factory()->NewExpressionStatement(
635 factory()->NewAssignment(
636 Token::ASSIGN, factory()->NewVariableProxy(done),
637 factory()->NewBooleanLiteral(false, nopos), nopos),
638 nopos);
639
640 // if (!result.done) { #append_element; #unset_done }
641 Statement* maybe_append_and_unset_done;
Ben Murdochda12d292016-06-02 14:46:10 +0100642 {
643 Expression* result_done =
644 factory()->NewProperty(factory()->NewVariableProxy(result),
645 factory()->NewStringLiteral(
646 ast_value_factory()->done_string(), nopos),
647 nopos);
Ben Murdochc5610432016-08-08 18:44:38 +0100648
649 Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
650 then->statements()->Add(append_element, zone());
651 then->statements()->Add(unset_done, zone());
652
653 maybe_append_and_unset_done = factory()->NewIfStatement(
654 factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
655 factory()->NewEmptyStatement(nopos), nopos);
Ben Murdochda12d292016-06-02 14:46:10 +0100656 }
657
658 // while (!done) {
Ben Murdochc5610432016-08-08 18:44:38 +0100659 // #set_done;
Ben Murdochda12d292016-06-02 14:46:10 +0100660 // #get_next;
Ben Murdochc5610432016-08-08 18:44:38 +0100661 // #maybe_append_and_unset_done;
Ben Murdochda12d292016-06-02 14:46:10 +0100662 // }
663 WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
664 {
665 Expression* condition = factory()->NewUnaryOperation(
666 Token::NOT, factory()->NewVariableProxy(done), nopos);
Ben Murdochc5610432016-08-08 18:44:38 +0100667 Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
668 body->statements()->Add(set_done, zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100669 body->statements()->Add(get_next, zone());
Ben Murdochc5610432016-08-08 18:44:38 +0100670 body->statements()->Add(maybe_append_and_unset_done, zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100671 loop->Initialize(condition, body);
672 }
673
674 block_->statements()->Add(loop, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 RecurseIntoSubpattern(spread->expression(),
676 factory()->NewVariableProxy(array));
677 }
Ben Murdochda12d292016-06-02 14:46:10 +0100678
679 if (FLAG_harmony_iterator_close) {
680 Expression* closing_condition = factory()->NewUnaryOperation(
681 Token::NOT, factory()->NewVariableProxy(done), nopos);
682 parser_->FinalizeIteratorUse(completion, closing_condition, iterator,
683 block_, target);
684 block_ = target;
685 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686}
687
688
689void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
690 Variable* temp_var = nullptr;
691 VisitArrayLiteral(node, &temp_var);
692}
693
694
695void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
696 // let {<pattern> = <init>} = <value>
697 // becomes
698 // temp = <value>;
699 // <pattern> = temp === undefined ? <init> : temp;
700 DCHECK_EQ(Token::ASSIGN, node->op());
701
702 auto initializer = node->value();
703 auto value = initializer;
704 auto temp = CreateTempVar(current_value_);
705
706 if (IsInitializerContext()) {
707 Expression* is_undefined = factory()->NewCompareOperation(
708 Token::EQ_STRICT, factory()->NewVariableProxy(temp),
709 factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
710 RelocInfo::kNoPosition);
711 value = factory()->NewConditional(is_undefined, initializer,
712 factory()->NewVariableProxy(temp),
713 RelocInfo::kNoPosition);
714 }
715
Ben Murdochc5610432016-08-08 18:44:38 +0100716 // Initializer may have been parsed in the wrong scope.
717 RewriteParameterScopes(initializer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000718
719 PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
720 RecurseIntoSubpattern(node->target(), value);
721 set_context(old_context);
722}
723
724
725// =============== AssignmentPattern only ==================
726
727void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
728 DCHECK(IsAssignmentContext());
729 auto value = current_value_;
730
731 Assignment* assignment =
732 factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
733
734 block_->statements()->Add(
735 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
736 zone());
737}
738
739
740// =============== UNREACHABLE =============================
741
742void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
743
744#define NOT_A_PATTERN(Node) \
745 void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
746 UNREACHABLE(); \
747 }
748
749NOT_A_PATTERN(BinaryOperation)
750NOT_A_PATTERN(Block)
751NOT_A_PATTERN(BreakStatement)
752NOT_A_PATTERN(Call)
753NOT_A_PATTERN(CallNew)
754NOT_A_PATTERN(CallRuntime)
755NOT_A_PATTERN(CaseClause)
756NOT_A_PATTERN(ClassLiteral)
757NOT_A_PATTERN(CompareOperation)
758NOT_A_PATTERN(Conditional)
759NOT_A_PATTERN(ContinueStatement)
760NOT_A_PATTERN(CountOperation)
761NOT_A_PATTERN(DebuggerStatement)
762NOT_A_PATTERN(DoExpression)
763NOT_A_PATTERN(DoWhileStatement)
764NOT_A_PATTERN(EmptyStatement)
765NOT_A_PATTERN(EmptyParentheses)
766NOT_A_PATTERN(ExportDeclaration)
767NOT_A_PATTERN(ExpressionStatement)
768NOT_A_PATTERN(ForInStatement)
769NOT_A_PATTERN(ForOfStatement)
770NOT_A_PATTERN(ForStatement)
771NOT_A_PATTERN(FunctionDeclaration)
772NOT_A_PATTERN(FunctionLiteral)
773NOT_A_PATTERN(IfStatement)
774NOT_A_PATTERN(ImportDeclaration)
775NOT_A_PATTERN(Literal)
776NOT_A_PATTERN(NativeFunctionLiteral)
777NOT_A_PATTERN(RegExpLiteral)
778NOT_A_PATTERN(ReturnStatement)
779NOT_A_PATTERN(SloppyBlockFunctionStatement)
780NOT_A_PATTERN(Spread)
781NOT_A_PATTERN(SuperPropertyReference)
782NOT_A_PATTERN(SuperCallReference)
783NOT_A_PATTERN(SwitchStatement)
784NOT_A_PATTERN(ThisFunction)
785NOT_A_PATTERN(Throw)
786NOT_A_PATTERN(TryCatchStatement)
787NOT_A_PATTERN(TryFinallyStatement)
788NOT_A_PATTERN(UnaryOperation)
789NOT_A_PATTERN(VariableDeclaration)
790NOT_A_PATTERN(WhileStatement)
791NOT_A_PATTERN(WithStatement)
792NOT_A_PATTERN(Yield)
793
794#undef NOT_A_PATTERN
795} // namespace internal
796} // namespace v8