| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index e202afe46bf9d9fd75743ab856e8965a1bb7b3ba..55f4f33a7059102cfd6d4e7a55690db7a600a1d2 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -2986,29 +2986,33 @@ Statement* Parser::DesugarLetBindingsInForStatement(
|
| //
|
| // We rewrite a for statement of the form
|
| //
|
| - // for (let x = i; cond; next) body
|
| + // labels: for (let x = i; cond; next) body
|
| //
|
| // into
|
| //
|
| // {
|
| - // let x = i;
|
| - // temp_x = x;
|
| - // flag = 1;
|
| - // for (;;) {
|
| - // let x = temp_x;
|
| - // if (flag == 1) {
|
| - // flag = 0;
|
| - // } else {
|
| - // next;
|
| - // }
|
| + // let x = i;
|
| + // temp_x = x;
|
| + // first = 1;
|
| + // outer: for (;;) {
|
| + // let x = temp_x;
|
| + // if (first == 1) {
|
| + // first = 0;
|
| + // } else {
|
| + // next;
|
| + // }
|
| + // flag = 1;
|
| + // labels: for (; flag == 1; flag = 0, temp_x = x) {
|
| // if (cond) {
|
| - // <empty>
|
| + // body
|
| // } else {
|
| - // break;
|
| + // break outer;
|
| // }
|
| - // b
|
| - // temp_x = x;
|
| - // }
|
| + // }
|
| + // if (flag == 1) {
|
| + // break;
|
| + // }
|
| + // }
|
| // }
|
|
|
| DCHECK(names->length() > 0);
|
| @@ -3017,6 +3021,8 @@ Statement* Parser::DesugarLetBindingsInForStatement(
|
|
|
| Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
|
| RelocInfo::kNoPosition);
|
| +
|
| + // Add statement: let x = i.
|
| outer_block->AddStatement(init, zone());
|
|
|
| const AstRawString* temp_name = ast_value_factory()->dot_for_string();
|
| @@ -3036,24 +3042,33 @@ Statement* Parser::DesugarLetBindingsInForStatement(
|
| temps.Add(temp, zone());
|
| }
|
|
|
| - Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
|
| - // Make statement: flag = 1.
|
| - {
|
| - VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + Variable* first = NULL;
|
| + // Make statement: first = 1.
|
| + if (next) {
|
| + first = scope_->DeclarationScope()->NewTemporary(temp_name);
|
| + VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
| Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
|
| Assignment* assignment = factory()->NewAssignment(
|
| - Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
|
| - Statement* assignment_statement = factory()->NewExpressionStatement(
|
| - assignment, RelocInfo::kNoPosition);
|
| + Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition);
|
| + Statement* assignment_statement =
|
| + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
|
| outer_block->AddStatement(assignment_statement, zone());
|
| }
|
|
|
| - outer_block->AddStatement(loop, zone());
|
| + // Make statement: outer: for (;;)
|
| + // Note that we don't actually create the label, or set this loop up as an
|
| + // explicit break target, instead handing it directly to those nodes that
|
| + // need to know about it. This should be safe because we don't run any code
|
| + // in this function that looks up break targets.
|
| + ForStatement* outer_loop =
|
| + factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
|
| + outer_block->AddStatement(outer_loop, zone());
|
| +
|
| outer_block->set_scope(for_scope);
|
| scope_ = inner_scope;
|
|
|
| - Block* inner_block = factory()->NewBlock(NULL, 2 * names->length() + 3,
|
| - false, RelocInfo::kNoPosition);
|
| + Block* inner_block = factory()->NewBlock(NULL, names->length() + 4, false,
|
| + RelocInfo::kNoPosition);
|
| int pos = scanner()->location().beg_pos;
|
| ZoneList<Variable*> inner_vars(names->length(), zone());
|
|
|
| @@ -3075,61 +3090,118 @@ Statement* Parser::DesugarLetBindingsInForStatement(
|
| inner_block->AddStatement(assignment_statement, zone());
|
| }
|
|
|
| - // Make statement: if (flag == 1) { flag = 0; } else { next; }.
|
| + // Make statement: if (first == 1) { first = 0; } else { next; }
|
| if (next) {
|
| + DCHECK(first);
|
| Expression* compare = NULL;
|
| - // Make compare expresion: flag == 1.
|
| + // Make compare expression: first == 1.
|
| {
|
| Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
|
| - VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| - compare = factory()->NewCompareOperation(
|
| - Token::EQ, flag_proxy, const1, pos);
|
| + VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
| + compare =
|
| + factory()->NewCompareOperation(Token::EQ, first_proxy, const1, pos);
|
| }
|
| - Statement* clear_flag = NULL;
|
| - // Make statement: flag = 0.
|
| + Statement* clear_first = NULL;
|
| + // Make statement: first = 0.
|
| {
|
| - VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + VariableProxy* first_proxy = factory()->NewVariableProxy(first);
|
| Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
|
| Assignment* assignment = factory()->NewAssignment(
|
| - Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
|
| - clear_flag = factory()->NewExpressionStatement(assignment, pos);
|
| + Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
|
| + clear_first =
|
| + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
|
| }
|
| - Statement* clear_flag_or_next = factory()->NewIfStatement(
|
| - compare, clear_flag, next, RelocInfo::kNoPosition);
|
| - inner_block->AddStatement(clear_flag_or_next, zone());
|
| + Statement* clear_first_or_next = factory()->NewIfStatement(
|
| + compare, clear_first, next, RelocInfo::kNoPosition);
|
| + inner_block->AddStatement(clear_first_or_next, zone());
|
| + }
|
| +
|
| + Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
|
| + // Make statement: flag = 1.
|
| + {
|
| + VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
|
| + Assignment* assignment = factory()->NewAssignment(
|
| + Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
|
| + Statement* assignment_statement =
|
| + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
|
| + inner_block->AddStatement(assignment_statement, zone());
|
| + }
|
| +
|
| + // Make cond expression for main loop: flag == 1.
|
| + Expression* flag_cond = NULL;
|
| + {
|
| + Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
|
| + VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + flag_cond =
|
| + factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
|
| }
|
|
|
| + // Create chain of expressions "flag = 0, temp_x = x, ..."
|
| + Statement* compound_next_statement = NULL;
|
| + {
|
| + Expression* compound_next = NULL;
|
| + // Make expression: flag = 0.
|
| + {
|
| + VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
|
| + compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
|
| + const0, RelocInfo::kNoPosition);
|
| + }
|
|
|
| - // Make statement: if (cond) { } else { break; }.
|
| + // Make the comma-separated list of temp_x = x assignments.
|
| + for (int i = 0; i < names->length(); i++) {
|
| + VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
|
| + VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
|
| + Assignment* assignment = factory()->NewAssignment(
|
| + Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
|
| + compound_next = factory()->NewBinaryOperation(
|
| + Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
|
| + }
|
| +
|
| + compound_next_statement = factory()->NewExpressionStatement(
|
| + compound_next, RelocInfo::kNoPosition);
|
| + }
|
| +
|
| + // Make statement: if (cond) { body; } else { break outer; }
|
| + Statement* body_or_stop = body;
|
| if (cond) {
|
| - Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
| - BreakableStatement* t = LookupBreakTarget(NULL, CHECK_OK);
|
| - Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition);
|
| - Statement* if_not_cond_break = factory()->NewIfStatement(
|
| - cond, empty, stop, cond->position());
|
| - inner_block->AddStatement(if_not_cond_break, zone());
|
| + Statement* stop =
|
| + factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
|
| + body_or_stop =
|
| + factory()->NewIfStatement(cond, body, stop, cond->position());
|
| }
|
|
|
| - inner_block->AddStatement(body, zone());
|
| + // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
|
| + // Note that we re-use the original loop node, which retains it 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);
|
| + inner_block->AddStatement(loop, zone());
|
|
|
| - // For each let variable x:
|
| - // make statement: temp_x = x;
|
| - for (int i = 0; i < names->length(); i++) {
|
| - VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
|
| - int pos = scanner()->location().end_pos;
|
| - VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
|
| - Assignment* assignment = factory()->NewAssignment(
|
| - Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
|
| - Statement* assignment_statement = factory()->NewExpressionStatement(
|
| - assignment, RelocInfo::kNoPosition);
|
| - inner_block->AddStatement(assignment_statement, zone());
|
| + // Make statement: if (flag == 1) { break; }
|
| + {
|
| + Expression* compare = NULL;
|
| + // Make compare expresion: flag == 1.
|
| + {
|
| + Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
|
| + VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
|
| + compare =
|
| + factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
|
| + }
|
| + Statement* stop =
|
| + factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
|
| + Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
| + Statement* if_flag_break =
|
| + factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
|
| + inner_block->AddStatement(if_flag_break, zone());
|
| }
|
|
|
| inner_scope->set_end_position(scanner()->location().end_pos);
|
| inner_block->set_scope(inner_scope);
|
| scope_ = for_scope;
|
|
|
| - loop->Initialize(NULL, NULL, NULL, inner_block);
|
| + outer_loop->Initialize(NULL, NULL, NULL, inner_block);
|
| return outer_block;
|
| }
|
|
|
|
|