Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/parsing/parser.h" | 5 #include "src/parsing/parser.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/api.h" | 9 #include "src/api.h" |
| 10 #include "src/ast/ast-expression-rewriter.h" | 10 #include "src/ast/ast-expression-rewriter.h" |
| (...skipping 1977 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1988 zone()); | 1988 zone()); |
| 1989 block->statements()->Add(body, zone()); | 1989 block->statements()->Add(body, zone()); |
| 1990 body = block; | 1990 body = block; |
| 1991 each = factory()->NewVariableProxy(temp); | 1991 each = factory()->NewVariableProxy(temp); |
| 1992 } | 1992 } |
| 1993 stmt->AsForInStatement()->Initialize(each, subject, body); | 1993 stmt->AsForInStatement()->Initialize(each, subject, body); |
| 1994 } | 1994 } |
| 1995 return stmt; | 1995 return stmt; |
| 1996 } | 1996 } |
| 1997 | 1997 |
| 1998 // 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
| |
| 1999 Block* Parser::RewriteForVarInLegacy(ForInfo* for_info) { | |
| 2000 const DeclarationParsingResult::Declaration& decl = | |
| 2001 for_info->parsing_result.declarations[0]; | |
| 2002 if (!for_info->bound_names_are_lexical && decl.pattern->IsVariableProxy() && | |
| 2003 decl.initializer != nullptr) { | |
| 2004 DCHECK(!allow_harmony_for_in()); | |
| 2005 ++use_counts_[v8::Isolate::kForInInitializer]; | |
| 2006 const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name(); | |
| 2007 VariableProxy* single_var = NewUnresolved(name); | |
| 2008 Block* init_block = factory()->NewBlock( | |
| 2009 nullptr, 2, true, for_info->parsing_result.descriptor.declaration_pos); | |
| 2010 init_block->statements()->Add( | |
| 2011 factory()->NewExpressionStatement( | |
| 2012 factory()->NewAssignment(Token::ASSIGN, single_var, | |
| 2013 decl.initializer, kNoSourcePosition), | |
| 2014 kNoSourcePosition), | |
| 2015 zone()); | |
| 2016 return init_block; | |
| 2017 } else { | |
|
marja
2016/09/20 19:36:30
Style nit: else { } around the return is unnecessa
nickie
2016/09/21 09:20:02
Done.
| |
| 2018 return nullptr; | |
| 2019 } | |
| 2020 } | |
| 2021 | |
| 2022 // Rewrite a for-in/of statement of the form | |
| 2023 // | |
| 2024 // for (let/const/var x in/of e) b | |
| 2025 // | |
| 2026 // into | |
| 2027 // | |
| 2028 // { | |
| 2029 // <let x' be a temporary variable> | |
| 2030 // for (x' in/of e) { | |
| 2031 // let/const/var x; | |
| 2032 // x = x'; | |
| 2033 // b; | |
| 2034 // } | |
| 2035 // let x; // for TDZ | |
| 2036 // } | |
| 2037 std::pair<Block*, Expression*> Parser::DesugarBindingInForEachStatement( | |
| 2038 ForInfo* for_info, bool* ok) { | |
| 2039 DeclarationParsingResult::Declaration& decl = | |
| 2040 for_info->parsing_result.declarations[0]; | |
| 2041 Variable* temp = NewTemporary(ast_value_factory()->dot_for_string()); | |
| 2042 auto each_initialization_block = | |
| 2043 factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); | |
| 2044 { | |
| 2045 auto descriptor = for_info->parsing_result.descriptor; | |
| 2046 descriptor.declaration_pos = kNoSourcePosition; | |
| 2047 descriptor.initialization_pos = kNoSourcePosition; | |
| 2048 decl.initializer = factory()->NewVariableProxy(temp); | |
| 2049 | |
| 2050 bool is_for_var_of = | |
| 2051 for_info->mode == ForEachStatement::ITERATE && | |
| 2052 for_info->parsing_result.descriptor.mode == VariableMode::VAR; | |
| 2053 | |
| 2054 PatternRewriter::DeclareAndInitializeVariables( | |
| 2055 this, each_initialization_block, &descriptor, &decl, | |
| 2056 (for_info->bound_names_are_lexical || is_for_var_of) | |
| 2057 ? &for_info->bound_names | |
| 2058 : nullptr, | |
| 2059 CHECK_OK_VALUE(std::make_pair(nullptr, nullptr))); | |
| 2060 | |
| 2061 // Annex B.3.5 prohibits the form | |
| 2062 // `try {} catch(e) { for (var e of {}); }` | |
| 2063 // So if we are parsing a statement like `for (var ... of ...)` | |
| 2064 // we need to walk up the scope chain and look for catch scopes | |
| 2065 // which have a simple binding, then compare their binding against | |
| 2066 // all of the names declared in the init of the for-of we're | |
| 2067 // parsing. | |
| 2068 if (is_for_var_of) { | |
| 2069 Scope* catch_scope = scope(); | |
| 2070 while (catch_scope != nullptr && !catch_scope->is_declaration_scope()) { | |
| 2071 if (catch_scope->is_catch_scope()) { | |
| 2072 auto name = catch_scope->catch_variable_name(); | |
| 2073 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.
| |
| 2074 ast_value_factory() | |
| 2075 ->dot_catch_string()) { // i.e. is a simple binding | |
| 2076 if (for_info->bound_names.Contains(name)) { | |
| 2077 ReportMessageAt(for_info->parsing_result.bindings_loc, | |
| 2078 MessageTemplate::kVarRedeclaration, name); | |
| 2079 *ok = false; | |
| 2080 return std::make_pair(nullptr, nullptr); | |
| 2081 } | |
| 2082 } | |
| 2083 } | |
| 2084 catch_scope = catch_scope->outer_scope(); | |
| 2085 } | |
| 2086 } | |
| 2087 } | |
| 2088 | |
| 2089 Block* body_block = factory()->NewBlock(NULL, 3, false, kNoSourcePosition); | |
| 2090 body_block->statements()->Add(each_initialization_block, zone()); | |
| 2091 VariableProxy* temp_proxy = factory()->NewVariableProxy( | |
| 2092 temp, for_info->each_loc.beg_pos, for_info->each_loc.end_pos); | |
| 2093 return std::make_pair(body_block, temp_proxy); | |
| 2094 } | |
| 2095 | |
| 2096 // Create a TDZ for any lexically-bound names in for in/of statements. | |
| 2097 Block* Parser::CreateForEachStatementTDZ(Block* init_block, ForInfo* for_info, | |
| 2098 bool* ok) { | |
| 2099 if (for_info->bound_names_are_lexical) { | |
| 2100 DCHECK_NULL(init_block); | |
| 2101 | |
| 2102 init_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); | |
| 2103 | |
| 2104 for (int i = 0; i < for_info->bound_names.length(); ++i) { | |
| 2105 // TODO(adamk): This needs to be some sort of special | |
| 2106 // INTERNAL variable that's invisible to the debugger | |
| 2107 // but visible to everything else. | |
| 2108 Declaration* tdz_decl = DeclareVariable(for_info->bound_names[i], LET, | |
| 2109 kNoSourcePosition, CHECK_OK); | |
| 2110 tdz_decl->proxy()->var()->set_initializer_position(position()); | |
| 2111 } | |
| 2112 } | |
| 2113 return init_block; | |
| 2114 } | |
| 2115 | |
| 1998 Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, | 2116 Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| 1999 Expression* each, | 2117 Expression* each, |
| 2000 Expression* iterable, | 2118 Expression* iterable, |
| 2001 Statement* body, bool finalize, | 2119 Statement* body, bool finalize, |
| 2002 int next_result_pos) { | 2120 int next_result_pos) { |
| 2003 // Create the auxiliary expressions needed for iterating over the iterable, | 2121 // Create the auxiliary expressions needed for iterating over the iterable, |
| 2004 // and initialize the given ForOfStatement with them. | 2122 // and initialize the given ForOfStatement with them. |
| 2005 // If finalize is true, also instrument the loop with code that performs the | 2123 // If finalize is true, also instrument the loop with code that performs the |
| 2006 // proper ES6 iterator finalization. In that case, the result is not | 2124 // proper ES6 iterator finalization. In that case, the result is not |
| 2007 // immediately a ForOfStatement. | 2125 // immediately a ForOfStatement. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2112 block->statements()->Add(set_completion_normal, zone()); | 2230 block->statements()->Add(set_completion_normal, zone()); |
| 2113 body = block; | 2231 body = block; |
| 2114 } | 2232 } |
| 2115 | 2233 |
| 2116 for_of->Initialize(body, iterator, assign_iterator, next_result, result_done, | 2234 for_of->Initialize(body, iterator, assign_iterator, next_result, result_done, |
| 2117 assign_each); | 2235 assign_each); |
| 2118 return finalize ? FinalizeForOfStatement(for_of, completion, nopos) : for_of; | 2236 return finalize ? FinalizeForOfStatement(for_of, completion, nopos) : for_of; |
| 2119 } | 2237 } |
| 2120 | 2238 |
| 2121 Statement* Parser::DesugarLexicalBindingsInForStatement( | 2239 Statement* Parser::DesugarLexicalBindingsInForStatement( |
| 2122 Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names, | |
| 2123 ForStatement* loop, Statement* init, Expression* cond, Statement* next, | 2240 ForStatement* loop, Statement* init, Expression* cond, Statement* next, |
| 2124 Statement* body, bool* ok) { | 2241 Statement* body, Scope* inner_scope, ForInfo* for_info, bool* ok) { |
| 2125 // ES6 13.7.4.8 specifies that on each loop iteration the let variables are | 2242 // ES6 13.7.4.8 specifies that on each loop iteration the let variables are |
| 2126 // copied into a new environment. Moreover, the "next" statement must be | 2243 // copied into a new environment. Moreover, the "next" statement must be |
| 2127 // evaluated not in the environment of the just completed iteration but in | 2244 // evaluated not in the environment of the just completed iteration but in |
| 2128 // that of the upcoming one. We achieve this with the following desugaring. | 2245 // that of the upcoming one. We achieve this with the following desugaring. |
| 2129 // Extra care is needed to preserve the completion value of the original loop. | 2246 // Extra care is needed to preserve the completion value of the original loop. |
| 2130 // | 2247 // |
| 2131 // We are given a for statement of the form | 2248 // We are given a for statement of the form |
| 2132 // | 2249 // |
| 2133 // labels: for (let/const x = i; cond; next) body | 2250 // labels: for (let/const x = i; cond; next) body |
| 2134 // | 2251 // |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2152 // }} | 2269 // }} |
| 2153 // labels: for (; flag == 1; flag = 0, temp_x = x) { | 2270 // labels: for (; flag == 1; flag = 0, temp_x = x) { |
| 2154 // body | 2271 // body |
| 2155 // } | 2272 // } |
| 2156 // {{ if (flag == 1) // Body used break. | 2273 // {{ if (flag == 1) // Body used break. |
| 2157 // break; | 2274 // break; |
| 2158 // }} | 2275 // }} |
| 2159 // } | 2276 // } |
| 2160 // } | 2277 // } |
| 2161 | 2278 |
| 2162 DCHECK(names->length() > 0); | 2279 DCHECK(for_info->bound_names.length() > 0); |
| 2163 ZoneList<Variable*> temps(names->length(), zone()); | 2280 ZoneList<Variable*> temps(for_info->bound_names.length(), zone()); |
| 2164 | 2281 |
| 2165 Block* outer_block = | 2282 Block* outer_block = factory()->NewBlock( |
| 2166 factory()->NewBlock(NULL, names->length() + 4, false, kNoSourcePosition); | 2283 NULL, for_info->bound_names.length() + 4, false, kNoSourcePosition); |
| 2167 | 2284 |
| 2168 // Add statement: let/const x = i. | 2285 // Add statement: let/const x = i. |
| 2169 outer_block->statements()->Add(init, zone()); | 2286 outer_block->statements()->Add(init, zone()); |
| 2170 | 2287 |
| 2171 const AstRawString* temp_name = ast_value_factory()->dot_for_string(); | 2288 const AstRawString* temp_name = ast_value_factory()->dot_for_string(); |
| 2172 | 2289 |
| 2173 // For each lexical variable x: | 2290 // For each lexical variable x: |
| 2174 // make statement: temp_x = x. | 2291 // make statement: temp_x = x. |
| 2175 for (int i = 0; i < names->length(); i++) { | 2292 for (int i = 0; i < for_info->bound_names.length(); i++) { |
| 2176 VariableProxy* proxy = NewUnresolved(names->at(i)); | 2293 VariableProxy* proxy = NewUnresolved(for_info->bound_names[i]); |
| 2177 Variable* temp = NewTemporary(temp_name); | 2294 Variable* temp = NewTemporary(temp_name); |
| 2178 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); | 2295 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); |
| 2179 Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy, | 2296 Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy, |
| 2180 proxy, kNoSourcePosition); | 2297 proxy, kNoSourcePosition); |
| 2181 Statement* assignment_statement = | 2298 Statement* assignment_statement = |
| 2182 factory()->NewExpressionStatement(assignment, kNoSourcePosition); | 2299 factory()->NewExpressionStatement(assignment, kNoSourcePosition); |
| 2183 outer_block->statements()->Add(assignment_statement, zone()); | 2300 outer_block->statements()->Add(assignment_statement, zone()); |
| 2184 temps.Add(temp, zone()); | 2301 temps.Add(temp, zone()); |
| 2185 } | 2302 } |
| 2186 | 2303 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2210 // in this function that looks up break targets. | 2327 // in this function that looks up break targets. |
| 2211 ForStatement* outer_loop = | 2328 ForStatement* outer_loop = |
| 2212 factory()->NewForStatement(NULL, kNoSourcePosition); | 2329 factory()->NewForStatement(NULL, kNoSourcePosition); |
| 2213 outer_block->statements()->Add(outer_loop, zone()); | 2330 outer_block->statements()->Add(outer_loop, zone()); |
| 2214 outer_block->set_scope(scope()); | 2331 outer_block->set_scope(scope()); |
| 2215 | 2332 |
| 2216 Block* inner_block = factory()->NewBlock(NULL, 3, false, kNoSourcePosition); | 2333 Block* inner_block = factory()->NewBlock(NULL, 3, false, kNoSourcePosition); |
| 2217 { | 2334 { |
| 2218 BlockState block_state(&scope_state_, inner_scope); | 2335 BlockState block_state(&scope_state_, inner_scope); |
| 2219 | 2336 |
| 2220 Block* ignore_completion_block = | 2337 Block* ignore_completion_block = factory()->NewBlock( |
| 2221 factory()->NewBlock(NULL, names->length() + 3, true, kNoSourcePosition); | 2338 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.
| |
| 2222 ZoneList<Variable*> inner_vars(names->length(), zone()); | 2339 ZoneList<Variable*> inner_vars(for_info->bound_names.length(), zone()); |
| 2223 // For each let variable x: | 2340 // For each let variable x: |
| 2224 // make statement: let/const x = temp_x. | 2341 // make statement: let/const x = temp_x. |
| 2225 for (int i = 0; i < names->length(); i++) { | 2342 for (int i = 0; i < for_info->bound_names.length(); i++) { |
| 2226 Declaration* decl = | 2343 Declaration* decl = DeclareVariable( |
| 2227 DeclareVariable(names->at(i), mode, kNoSourcePosition, CHECK_OK); | 2344 for_info->bound_names[i], for_info->parsing_result.descriptor.mode, |
| 2345 kNoSourcePosition, CHECK_OK); | |
| 2228 inner_vars.Add(decl->proxy()->var(), zone()); | 2346 inner_vars.Add(decl->proxy()->var(), zone()); |
| 2229 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); | 2347 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); |
| 2230 Assignment* assignment = factory()->NewAssignment( | 2348 Assignment* assignment = factory()->NewAssignment( |
| 2231 Token::INIT, decl->proxy(), temp_proxy, kNoSourcePosition); | 2349 Token::INIT, decl->proxy(), temp_proxy, kNoSourcePosition); |
| 2232 Statement* assignment_statement = | 2350 Statement* assignment_statement = |
| 2233 factory()->NewExpressionStatement(assignment, kNoSourcePosition); | 2351 factory()->NewExpressionStatement(assignment, kNoSourcePosition); |
| 2234 DCHECK(init->position() != kNoSourcePosition); | 2352 DCHECK(init->position() != kNoSourcePosition); |
| 2235 decl->proxy()->var()->set_initializer_position(init->position()); | 2353 decl->proxy()->var()->set_initializer_position(init->position()); |
| 2236 ignore_completion_block->statements()->Add(assignment_statement, zone()); | 2354 ignore_completion_block->statements()->Add(assignment_statement, zone()); |
| 2237 } | 2355 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2301 // Make expression: flag = 0. | 2419 // Make expression: flag = 0. |
| 2302 { | 2420 { |
| 2303 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); | 2421 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); |
| 2304 Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition); | 2422 Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition); |
| 2305 compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy, | 2423 compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy, |
| 2306 const0, kNoSourcePosition); | 2424 const0, kNoSourcePosition); |
| 2307 } | 2425 } |
| 2308 | 2426 |
| 2309 // Make the comma-separated list of temp_x = x assignments. | 2427 // Make the comma-separated list of temp_x = x assignments. |
| 2310 int inner_var_proxy_pos = scanner()->location().beg_pos; | 2428 int inner_var_proxy_pos = scanner()->location().beg_pos; |
| 2311 for (int i = 0; i < names->length(); i++) { | 2429 for (int i = 0; i < for_info->bound_names.length(); i++) { |
| 2312 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); | 2430 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); |
| 2313 VariableProxy* proxy = | 2431 VariableProxy* proxy = |
| 2314 factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos); | 2432 factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos); |
| 2315 Assignment* assignment = factory()->NewAssignment( | 2433 Assignment* assignment = factory()->NewAssignment( |
| 2316 Token::ASSIGN, temp_proxy, proxy, kNoSourcePosition); | 2434 Token::ASSIGN, temp_proxy, proxy, kNoSourcePosition); |
| 2317 compound_next = factory()->NewBinaryOperation( | 2435 compound_next = factory()->NewBinaryOperation( |
| 2318 Token::COMMA, compound_next, assignment, kNoSourcePosition); | 2436 Token::COMMA, compound_next, assignment, kNoSourcePosition); |
| 2319 } | 2437 } |
| 2320 | 2438 |
| 2321 compound_next_statement = | 2439 compound_next_statement = |
| (...skipping 3146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5468 | 5586 |
| 5469 return final_loop; | 5587 return final_loop; |
| 5470 } | 5588 } |
| 5471 | 5589 |
| 5472 #undef CHECK_OK | 5590 #undef CHECK_OK |
| 5473 #undef CHECK_OK_VOID | 5591 #undef CHECK_OK_VOID |
| 5474 #undef CHECK_FAILED | 5592 #undef CHECK_FAILED |
| 5475 | 5593 |
| 5476 } // namespace internal | 5594 } // namespace internal |
| 5477 } // namespace v8 | 5595 } // namespace v8 |
| OLD | NEW |