| 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);
|
|
|