Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index ce3deb5f93ab46263c6f4c1d5131916696f7c6ac..84e835f6be37f081daee8a6b5d5bf7e58621002c 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -3186,12 +3186,16 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator, |
throw_call, pos); |
} |
-void Parser::InitializeForEachStatement(ForEachStatement* stmt, |
- Expression* each, Expression* subject, |
- Statement* body, int each_keyword_pos) { |
+Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt, |
+ Expression* each, |
+ Expression* subject, |
+ Statement* body, |
+ int each_keyword_pos) { |
ForOfStatement* for_of = stmt->AsForOfStatement(); |
if (for_of != NULL) { |
- InitializeForOfStatement(for_of, each, subject, body, each_keyword_pos); |
+ const bool finalize = true; |
+ return InitializeForOfStatement(for_of, each, subject, body, finalize, |
+ each_keyword_pos); |
} else { |
if (each->IsArrayLiteral() || each->IsObjectLiteral()) { |
Variable* temp = |
@@ -3211,38 +3215,49 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, |
} |
stmt->AsForInStatement()->Initialize(each, subject, body); |
} |
+ return stmt; |
} |
-void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each, |
- Expression* iterable, Statement* body, |
- int next_result_pos) { |
+Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
+ Expression* each, |
+ Expression* iterable, |
+ Statement* body, bool finalize, |
+ int next_result_pos) { |
+ // Create the auxiliary expressions needed for iterating over the iterable, |
+ // and initialize the given ForOfStatement with them. |
+ // If finalize is true, also instrument the loop with code that performs the |
+ // proper ES6 iterator finalization. In that case, the result is not |
+ // immediately a ForOfStatement. |
+ |
+ const int nopos = kNoSourcePosition; |
+ auto avfactory = ast_value_factory(); |
+ |
Variable* iterator = |
scope_->NewTemporary(ast_value_factory()->dot_iterator_string()); |
Variable* result = |
scope_->NewTemporary(ast_value_factory()->dot_result_string()); |
- |
- Expression* assign_iterator; |
- Expression* next_result; |
- Expression* result_done; |
- Expression* assign_each; |
- |
- int get_iterator_pos = iterable->position(); |
+ Variable* completion = scope_->NewTemporary(avfactory->empty_string()); |
// iterator = iterable[Symbol.iterator]() |
- assign_iterator = factory()->NewAssignment( |
- Token::ASSIGN, factory()->NewVariableProxy(iterator), |
- GetIterator(iterable, factory(), get_iterator_pos), iterable->position()); |
+ Expression* assign_iterator; |
+ { |
+ assign_iterator = factory()->NewAssignment( |
+ Token::ASSIGN, factory()->NewVariableProxy(iterator), |
+ GetIterator(iterable, factory(), iterable->position()), |
+ iterable->position()); |
+ } |
// !%_IsJSReceiver(result = iterator.next()) && |
// %ThrowIteratorResultNotAnObject(result) |
+ Expression* next_result; |
{ |
- // result = iterator.next() |
Expression* iterator_proxy = factory()->NewVariableProxy(iterator); |
next_result = |
BuildIteratorNextResult(iterator_proxy, result, next_result_pos); |
} |
// result.done |
+ Expression* result_done; |
{ |
Expression* done_literal = factory()->NewStringLiteral( |
ast_value_factory()->done_string(), kNoSourcePosition); |
@@ -3251,23 +3266,84 @@ void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each, |
factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition); |
} |
- // each = result.value |
+ // result.value |
+ Expression* result_value; |
{ |
- Expression* value_literal = factory()->NewStringLiteral( |
- ast_value_factory()->value_string(), kNoSourcePosition); |
+ Expression* value_literal = |
+ factory()->NewStringLiteral(avfactory->value_string(), nopos); |
Expression* result_proxy = factory()->NewVariableProxy(result); |
- Expression* result_value = |
- factory()->NewProperty(result_proxy, value_literal, kNoSourcePosition); |
- assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value, |
- kNoSourcePosition); |
+ result_value = factory()->NewProperty(result_proxy, value_literal, nopos); |
+ } |
+ |
+ // {{completion = kAbruptCompletion;}} |
+ Statement* set_completion_abrupt; |
+ if (finalize) { |
+ Expression* proxy = factory()->NewVariableProxy(completion); |
+ Expression* assignment = factory()->NewAssignment( |
+ Token::ASSIGN, proxy, |
+ factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos); |
+ |
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos); |
+ block->statements()->Add( |
+ factory()->NewExpressionStatement(assignment, nopos), zone()); |
+ set_completion_abrupt = block; |
+ } |
+ |
+ // do { let tmp = #result_value; #set_completion_abrupt; tmp } |
+ // Expression* result_value (gets overwritten) |
+ if (finalize) { |
+ Variable* var_tmp = scope_->NewTemporary(avfactory->empty_string()); |
+ Expression* tmp = factory()->NewVariableProxy(var_tmp); |
+ Expression* assignment = |
+ factory()->NewAssignment(Token::ASSIGN, tmp, result_value, nopos); |
+ |
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos); |
+ block->statements()->Add( |
+ factory()->NewExpressionStatement(assignment, nopos), zone()); |
+ block->statements()->Add(set_completion_abrupt, zone()); |
+ |
+ result_value = factory()->NewDoExpression(block, var_tmp, nopos); |
+ } |
+ |
+ // each = #result_value; |
+ Expression* assign_each; |
+ { |
+ assign_each = |
+ factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos); |
if (each->IsArrayLiteral() || each->IsObjectLiteral()) { |
assign_each = PatternRewriter::RewriteDestructuringAssignment( |
this, assign_each->AsAssignment(), scope_); |
} |
} |
+ // {{completion = kNormalCompletion;}} |
+ Statement* set_completion_normal; |
+ if (finalize) { |
+ Expression* proxy = factory()->NewVariableProxy(completion); |
+ Expression* assignment = factory()->NewAssignment( |
+ Token::ASSIGN, proxy, |
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); |
+ |
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos); |
+ block->statements()->Add( |
+ factory()->NewExpressionStatement(assignment, nopos), zone()); |
+ set_completion_normal = block; |
+ } |
+ |
+ // { #loop-body; #set_completion_normal } |
+ // Statement* body (gets overwritten) |
+ if (finalize) { |
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos); |
+ block->statements()->Add(body, zone()); |
+ block->statements()->Add(set_completion_normal, zone()); |
+ body = block; |
+ } |
+ |
for_of->Initialize(body, iterator, assign_iterator, next_result, result_done, |
assign_each); |
+ return finalize |
+ ? ParserTraits::FinalizeForOfStatement(for_of, completion, nopos) |
+ : for_of; |
} |
Statement* Parser::DesugarLexicalBindingsInForStatement( |
@@ -3652,6 +3728,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
Block* body_block = |
factory()->NewBlock(NULL, 3, false, kNoSourcePosition); |
+ Statement* final_loop; |
{ |
ReturnExprScope no_tail_calls(function_state_, |
ReturnExprContext::kInsideForInOfBody); |
@@ -3678,8 +3755,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
body_block->statements()->Add(body, zone()); |
VariableProxy* temp_proxy = |
factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos); |
- InitializeForEachStatement(loop, temp_proxy, enumerable, body_block, |
- each_keyword_position); |
+ final_loop = InitializeForEachStatement( |
+ loop, temp_proxy, enumerable, body_block, each_keyword_position); |
} |
body_scope->set_end_position(scanner()->location().end_pos); |
body_scope = body_scope->FinalizeBlockScope(); |
@@ -3706,12 +3783,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
} |
} |
- Statement* final_loop = |
- loop->IsForOfStatement() |
- ? FinalizeForOfStatement(loop->AsForOfStatement(), |
- kNoSourcePosition) |
- : loop; |
- |
for_scope->set_end_position(scanner()->location().end_pos); |
for_scope = for_scope->FinalizeBlockScope(); |
// Parsed for-in loop w/ variable declarations. |
@@ -3775,14 +3846,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
// For legacy compat reasons, give for loops similar treatment to |
// if statements in allowing a function declaration for a body |
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); |
- InitializeForEachStatement(loop, expression, enumerable, body, |
- each_keyword_position); |
- |
- Statement* final_loop = |
- loop->IsForOfStatement() |
- ? FinalizeForOfStatement(loop->AsForOfStatement(), |
- kNoSourcePosition) |
- : loop; |
+ Statement* final_loop = InitializeForEachStatement( |
+ loop, expression, enumerable, body, each_keyword_position); |
for_scope->set_end_position(scanner()->location().end_pos); |
for_scope = for_scope->FinalizeBlockScope(); |
@@ -5876,9 +5941,10 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { |
// for (each of spread) %AppendElement($R, each) |
ForEachStatement* loop = factory()->NewForEachStatement( |
ForEachStatement::ITERATE, nullptr, kNoSourcePosition); |
+ const bool finalize = false; |
InitializeForOfStatement(loop->AsForOfStatement(), |
factory()->NewVariableProxy(each), subject, |
- append_body); |
+ append_body, finalize); |
do_block->statements()->Add(loop, zone()); |
} |
} |
@@ -6870,13 +6936,13 @@ void ParserTraits::BuildIteratorCloseForCompletion( |
statements->Add(maybe_call_return, zone); |
} |
- |
-Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
+Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, |
+ Variable* var_completion, |
+ int pos) { |
// |
// This function replaces the loop with the following wrapping: |
// |
- // let each; |
- // let completion = kNormalCompletion; |
+ // completion = kNormalCompletion; |
// try { |
// try { |
// #loop; |
@@ -6890,41 +6956,14 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
// } |
// } |
// |
- // where the loop's body is wrapped as follows: |
- // |
- // { |
- // #loop-body |
- // {{completion = kNormalCompletion;}} |
- // } |
- // |
- // and the loop's assign_each is wrapped as follows |
- // |
- // do { |
- // {{completion = kAbruptCompletion;}} |
- // #assign-each |
- // } |
+ // Note that the loop's body and its assign_each already contain appropriate |
+ // assignments to completion (see InitializeForOfStatement). |
// |
const int nopos = kNoSourcePosition; |
auto factory = parser_->factory(); |
- auto avfactory = parser_->ast_value_factory(); |
- auto scope = parser_->scope_; |
auto zone = parser_->zone(); |
- Variable* var_completion = scope->NewTemporary(avfactory->empty_string()); |
- |
- // let each; |
- Variable* var_each = scope->NewTemporary(avfactory->empty_string()); |
- Statement* initialize_each; |
- { |
- Expression* proxy = factory->NewVariableProxy(var_each); |
- Expression* assignment = factory->NewAssignment( |
- Token::ASSIGN, proxy, |
- factory->NewUndefinedLiteral(nopos), nopos); |
- initialize_each = |
- factory->NewExpressionStatement(assignment, nopos); |
- } |
- |
// !(completion === kNormalCompletion || IS_UNDEFINED(#iterator)) |
Expression* closing_condition; |
{ |
@@ -6939,66 +6978,13 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) { |
nopos); |
} |
- // {{completion = kNormalCompletion;}} |
- Statement* set_completion_normal; |
+ Block* final_loop = factory->NewBlock(nullptr, 2, false, nopos); |
{ |
- Expression* proxy = factory->NewVariableProxy(var_completion); |
- Expression* assignment = factory->NewAssignment( |
- Token::ASSIGN, proxy, |
- factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); |
- |
- Block* block = factory->NewBlock(nullptr, 1, true, nopos); |
- block->statements()->Add( |
- factory->NewExpressionStatement(assignment, nopos), zone); |
- set_completion_normal = block; |
- } |
- |
- // {{completion = kAbruptCompletion;}} |
- Statement* set_completion_abrupt; |
- { |
- Expression* proxy = factory->NewVariableProxy(var_completion); |
- Expression* assignment = factory->NewAssignment( |
- Token::ASSIGN, proxy, |
- factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos); |
- |
- Block* block = factory->NewBlock(nullptr, 1, true, nopos); |
- block->statements()->Add(factory->NewExpressionStatement(assignment, nopos), |
- zone); |
- set_completion_abrupt = block; |
- } |
- |
- // { #loop-body; #set_completion_normal } |
- Block* new_body = factory->NewBlock(nullptr, 2, false, nopos); |
- { |
- new_body->statements()->Add(loop->body(), zone); |
- new_body->statements()->Add(set_completion_normal, zone); |
- } |
- |
- // { #set_completion_abrupt; #assign-each } |
- Block* new_assign_each = factory->NewBlock(nullptr, 2, false, nopos); |
- { |
- new_assign_each->statements()->Add(set_completion_abrupt, zone); |
- new_assign_each->statements()->Add( |
- factory->NewExpressionStatement(loop->assign_each(), nopos), zone); |
- } |
- |
- // Now put things together. |
- |
- loop->set_body(new_body); |
- loop->set_assign_each( |
- factory->NewDoExpression(new_assign_each, var_each, nopos)); |
- |
- Statement* final_loop; |
- { |
- Block* target = factory->NewBlock(nullptr, 3, false, nopos); |
- target->statements()->Add(initialize_each, zone); |
- |
Block* try_block = factory->NewBlock(nullptr, 1, false, nopos); |
try_block->statements()->Add(loop, zone); |
FinalizeIteratorUse(var_completion, closing_condition, loop->iterator(), |
- try_block, target); |
- final_loop = target; |
+ try_block, final_loop); |
} |
return final_loop; |