Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 9113e8c7a4e3ba46b936b38d1f4627ff0c426cf4..7cf81c4f0569b0d770bf6751cc3f26a814a2a9aa 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -3339,16 +3339,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names, |
ForStatement* loop, Statement* init, Expression* cond, Statement* next, |
Statement* body, bool* ok) { |
- // ES6 13.6.3.4 specifies that on each loop iteration the let variables are |
- // copied into a new environment. After copying, the "next" statement of the |
- // loop is executed to update the loop variables. The loop condition is |
- // checked and the loop body is executed. |
+ // ES6 13.7.4.8 specifies that on each loop iteration the let variables are |
+ // copied into a new environment. Moreover, the "next" statement must be |
+ // evaluated not in the environment of the just completed iteration but in |
+ // that of the upcoming one. We achieve this with the following desugaring. |
+ // Extra care is needed to preserve the completion value of the original loop. |
// |
- // We rewrite a for statement of the form |
+ // We are given a for statement of the form |
// |
// labels: for (let/const x = i; cond; next) body |
// |
- // into |
+ // and rewrite it as follows. Here we write {{ ... }} for init-blocks, ie., |
+ // blocks whose ignore_completion_value_ flag is set. |
// |
// { |
// let/const x = i; |
@@ -3356,29 +3358,21 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
// first = 1; |
// undefined; |
// outer: for (;;) { |
- // { // This block's only function is to ensure that the statements it |
- // // contains do not affect the normal completion value. This is |
- // // accomplished by setting its ignore_completion_value bit. |
- // // No new lexical scope is introduced, so lexically scoped variables |
- // // declared here will be scoped to the outer for loop. |
- // let/const x = temp_x; |
- // if (first == 1) { |
- // first = 0; |
- // } else { |
- // next; |
- // } |
- // flag = 1; |
- // } |
+ // let/const x = temp_x; |
+ // {{ if (first == 1) { |
+ // first = 0; |
+ // } else { |
+ // next; |
+ // } |
+ // flag = 1; |
+ // if (!cond) break; |
+ // }} |
// labels: for (; flag == 1; flag = 0, temp_x = x) { |
- // if (cond) { |
- // body |
- // } else { |
- // break outer; |
- // } |
- // } |
- // if (flag == 1) { |
- // break; |
+ // body |
// } |
+ // {{ if (flag == 1) // Body used break. |
+ // break; |
+ // }} |
// } |
// } |
@@ -3386,7 +3380,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
Scope* for_scope = scope_; |
ZoneList<Variable*> temps(names->length(), zone()); |
- Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false, |
+ Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false, |
RelocInfo::kNoPosition); |
// Add statement: let/const x = i. |
@@ -3443,7 +3437,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
Block* inner_block = |
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); |
Block* ignore_completion_block = factory()->NewBlock( |
- NULL, names->length() + 2, true, RelocInfo::kNoPosition); |
+ NULL, names->length() + 3, true, RelocInfo::kNoPosition); |
ZoneList<Variable*> inner_vars(names->length(), zone()); |
// For each let variable x: |
// make statement: let/const x = temp_x. |
@@ -3502,6 +3496,16 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); |
ignore_completion_block->statements()->Add(assignment_statement, zone()); |
} |
+ |
+ // Make statement: if (!cond) break. |
+ if (cond) { |
+ Statement* stop = |
+ factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition); |
+ Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
+ ignore_completion_block->statements()->Add( |
+ factory()->NewIfStatement(cond, noop, stop, cond->position()), zone()); |
+ } |
+ |
inner_block->statements()->Add(ignore_completion_block, zone()); |
// Make cond expression for main loop: flag == 1. |
Expression* flag_cond = NULL; |
@@ -3540,23 +3544,14 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
compound_next, RelocInfo::kNoPosition); |
} |
- // Make statement: if (cond) { body; } else { break outer; } |
- Statement* body_or_stop = body; |
- if (cond) { |
- Statement* stop = |
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition); |
- body_or_stop = |
- factory()->NewIfStatement(cond, body, stop, cond->position()); |
- } |
- |
// Make statement: labels: for (; flag == 1; flag = 0, temp_x = x) |
// Note that we re-use the original loop node, which retains its labels |
// and ensures that any break or continue statements in body point to |
// the right place. |
- loop->Initialize(NULL, flag_cond, compound_next_statement, body_or_stop); |
+ loop->Initialize(NULL, flag_cond, compound_next_statement, body); |
inner_block->statements()->Add(loop, zone()); |
- // Make statement: if (flag == 1) { break; } |
+ // Make statement: {{if (flag == 1) break;}} |
{ |
Expression* compare = NULL; |
// Make compare expresion: flag == 1. |
@@ -3571,7 +3566,10 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
Statement* if_flag_break = |
factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition); |
- inner_block->statements()->Add(if_flag_break, zone()); |
+ Block* ignore_completion_block = |
+ factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition); |
+ ignore_completion_block->statements()->Add(if_flag_break, zone()); |
+ inner_block->statements()->Add(ignore_completion_block, zone()); |
} |
inner_scope->set_end_position(scanner()->location().end_pos); |