Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index f122d9aa5e4b57ff1459cfa48e060c666bd407ff..4e6ffccc44a0d6db02a9acfdedd826b5abb5f42b 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -3333,16 +3333,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 blocks whose |
|
rossberg
2015/10/07 12:28:46
Nit: ...for "init-blocks", whose...
neis
2015/10/08 12:57:24
Done.
|
| + // completion value is ignored. |
| // |
| // { |
| // let/const x = i; |
| @@ -3350,29 +3352,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; |
| + // }} |
| // } |
| // } |
| @@ -3380,7 +3374,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. |
| @@ -3437,7 +3431,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. |
| @@ -3496,6 +3490,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; |
| @@ -3534,23 +3538,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. |
| @@ -3565,7 +3560,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); |