Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index a406b66ae32490e15c9c66db05696864132cdaf1..a6bd065d92a5f1eddeac4e36bf4a5e2ed1ad615c 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -1995,6 +1995,124 @@ Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt, |
| return stmt; |
| } |
| +// Special case for legacy for (var ... = ... in ...) |
|
marja
2016/09/20 19:36:30
Could this comment also explain what it is rewritt
nickie
2016/09/21 09:20:02
Done, with a bit of reverse-engineering. You may
|
| +Block* Parser::RewriteForVarInLegacy(ForInfo* for_info) { |
| + const DeclarationParsingResult::Declaration& decl = |
| + for_info->parsing_result.declarations[0]; |
| + if (!for_info->bound_names_are_lexical && decl.pattern->IsVariableProxy() && |
| + decl.initializer != nullptr) { |
| + DCHECK(!allow_harmony_for_in()); |
| + ++use_counts_[v8::Isolate::kForInInitializer]; |
| + const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name(); |
| + VariableProxy* single_var = NewUnresolved(name); |
| + Block* init_block = factory()->NewBlock( |
| + nullptr, 2, true, for_info->parsing_result.descriptor.declaration_pos); |
| + init_block->statements()->Add( |
| + factory()->NewExpressionStatement( |
| + factory()->NewAssignment(Token::ASSIGN, single_var, |
| + decl.initializer, kNoSourcePosition), |
| + kNoSourcePosition), |
| + zone()); |
| + return init_block; |
| + } else { |
|
marja
2016/09/20 19:36:30
Style nit: else { } around the return is unnecessa
nickie
2016/09/21 09:20:02
Done.
|
| + return nullptr; |
| + } |
| +} |
| + |
| +// Rewrite a for-in/of statement of the form |
| +// |
| +// for (let/const/var x in/of e) b |
| +// |
| +// into |
| +// |
| +// { |
| +// <let x' be a temporary variable> |
| +// for (x' in/of e) { |
| +// let/const/var x; |
| +// x = x'; |
| +// b; |
| +// } |
| +// let x; // for TDZ |
| +// } |
| +std::pair<Block*, Expression*> Parser::DesugarBindingInForEachStatement( |
| + ForInfo* for_info, bool* ok) { |
| + DeclarationParsingResult::Declaration& decl = |
| + for_info->parsing_result.declarations[0]; |
| + Variable* temp = NewTemporary(ast_value_factory()->dot_for_string()); |
| + auto each_initialization_block = |
| + factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
| + { |
| + auto descriptor = for_info->parsing_result.descriptor; |
| + descriptor.declaration_pos = kNoSourcePosition; |
| + descriptor.initialization_pos = kNoSourcePosition; |
| + decl.initializer = factory()->NewVariableProxy(temp); |
| + |
| + bool is_for_var_of = |
| + for_info->mode == ForEachStatement::ITERATE && |
| + for_info->parsing_result.descriptor.mode == VariableMode::VAR; |
| + |
| + PatternRewriter::DeclareAndInitializeVariables( |
| + this, each_initialization_block, &descriptor, &decl, |
| + (for_info->bound_names_are_lexical || is_for_var_of) |
| + ? &for_info->bound_names |
| + : nullptr, |
| + CHECK_OK_VALUE(std::make_pair(nullptr, nullptr))); |
| + |
| + // Annex B.3.5 prohibits the form |
| + // `try {} catch(e) { for (var e of {}); }` |
| + // So if we are parsing a statement like `for (var ... of ...)` |
| + // we need to walk up the scope chain and look for catch scopes |
| + // which have a simple binding, then compare their binding against |
| + // all of the names declared in the init of the for-of we're |
| + // parsing. |
| + if (is_for_var_of) { |
| + Scope* catch_scope = scope(); |
| + while (catch_scope != nullptr && !catch_scope->is_declaration_scope()) { |
| + if (catch_scope->is_catch_scope()) { |
| + auto name = catch_scope->catch_variable_name(); |
| + if (name != |
|
marja
2016/09/20 19:36:30
Style nit: I'd combine these two nested if's:
if
nickie
2016/09/21 09:20:02
Done. I think the part "name != ... dot_catch_str
marja
2016/09/21 10:31:42
I was thinking the same, wondering if it's redunda
nickie
2016/09/21 10:33:05
OK, let's play it safe and leave it.
|
| + ast_value_factory() |
| + ->dot_catch_string()) { // i.e. is a simple binding |
| + if (for_info->bound_names.Contains(name)) { |
| + ReportMessageAt(for_info->parsing_result.bindings_loc, |
| + MessageTemplate::kVarRedeclaration, name); |
| + *ok = false; |
| + return std::make_pair(nullptr, nullptr); |
| + } |
| + } |
| + } |
| + catch_scope = catch_scope->outer_scope(); |
| + } |
| + } |
| + } |
| + |
| + Block* body_block = factory()->NewBlock(NULL, 3, false, kNoSourcePosition); |
| + body_block->statements()->Add(each_initialization_block, zone()); |
| + VariableProxy* temp_proxy = factory()->NewVariableProxy( |
| + temp, for_info->each_loc.beg_pos, for_info->each_loc.end_pos); |
| + return std::make_pair(body_block, temp_proxy); |
| +} |
| + |
| +// Create a TDZ for any lexically-bound names in for in/of statements. |
| +Block* Parser::CreateForEachStatementTDZ(Block* init_block, ForInfo* for_info, |
| + bool* ok) { |
| + if (for_info->bound_names_are_lexical) { |
| + DCHECK_NULL(init_block); |
| + |
| + init_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); |
| + |
| + for (int i = 0; i < for_info->bound_names.length(); ++i) { |
| + // TODO(adamk): This needs to be some sort of special |
| + // INTERNAL variable that's invisible to the debugger |
| + // but visible to everything else. |
| + Declaration* tdz_decl = DeclareVariable(for_info->bound_names[i], LET, |
| + kNoSourcePosition, CHECK_OK); |
| + tdz_decl->proxy()->var()->set_initializer_position(position()); |
| + } |
| + } |
| + return init_block; |
| +} |
| + |
| Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| Expression* each, |
| Expression* iterable, |
| @@ -2119,9 +2237,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| } |
| Statement* Parser::DesugarLexicalBindingsInForStatement( |
| - Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names, |
| ForStatement* loop, Statement* init, Expression* cond, Statement* next, |
| - Statement* body, bool* ok) { |
| + Statement* body, Scope* inner_scope, ForInfo* for_info, bool* ok) { |
| // 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 |
| @@ -2159,11 +2276,11 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| // } |
| // } |
| - DCHECK(names->length() > 0); |
| - ZoneList<Variable*> temps(names->length(), zone()); |
| + DCHECK(for_info->bound_names.length() > 0); |
| + ZoneList<Variable*> temps(for_info->bound_names.length(), zone()); |
| - Block* outer_block = |
| - factory()->NewBlock(NULL, names->length() + 4, false, kNoSourcePosition); |
| + Block* outer_block = factory()->NewBlock( |
| + NULL, for_info->bound_names.length() + 4, false, kNoSourcePosition); |
| // Add statement: let/const x = i. |
| outer_block->statements()->Add(init, zone()); |
| @@ -2172,8 +2289,8 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| // For each lexical variable x: |
| // make statement: temp_x = x. |
| - for (int i = 0; i < names->length(); i++) { |
| - VariableProxy* proxy = NewUnresolved(names->at(i)); |
| + for (int i = 0; i < for_info->bound_names.length(); i++) { |
| + VariableProxy* proxy = NewUnresolved(for_info->bound_names[i]); |
| Variable* temp = NewTemporary(temp_name); |
| VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); |
| Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy, |
| @@ -2217,14 +2334,15 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| { |
| BlockState block_state(&scope_state_, inner_scope); |
| - Block* ignore_completion_block = |
| - factory()->NewBlock(NULL, names->length() + 3, true, kNoSourcePosition); |
| - ZoneList<Variable*> inner_vars(names->length(), zone()); |
| + Block* ignore_completion_block = factory()->NewBlock( |
| + NULL, for_info->bound_names.length() + 3, true, kNoSourcePosition); |
|
marja
2016/09/20 19:36:30
Nit: pls update to nullptr while anyway modifying
nickie
2016/09/21 09:20:02
Done. Here and elsewhere.
|
| + ZoneList<Variable*> inner_vars(for_info->bound_names.length(), zone()); |
| // For each let variable x: |
| // make statement: let/const x = temp_x. |
| - for (int i = 0; i < names->length(); i++) { |
| - Declaration* decl = |
| - DeclareVariable(names->at(i), mode, kNoSourcePosition, CHECK_OK); |
| + for (int i = 0; i < for_info->bound_names.length(); i++) { |
| + Declaration* decl = DeclareVariable( |
| + for_info->bound_names[i], for_info->parsing_result.descriptor.mode, |
| + kNoSourcePosition, CHECK_OK); |
| inner_vars.Add(decl->proxy()->var(), zone()); |
| VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); |
| Assignment* assignment = factory()->NewAssignment( |
| @@ -2308,7 +2426,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| // Make the comma-separated list of temp_x = x assignments. |
| int inner_var_proxy_pos = scanner()->location().beg_pos; |
| - for (int i = 0; i < names->length(); i++) { |
| + for (int i = 0; i < for_info->bound_names.length(); i++) { |
| VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); |
| VariableProxy* proxy = |
| factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos); |