OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/ast/ast.h" | 5 #include "src/ast/ast.h" |
6 #include "src/messages.h" | 6 #include "src/messages.h" |
7 #include "src/parsing/parameter-initializer-rewriter.h" | 7 #include "src/parsing/parameter-initializer-rewriter.h" |
8 #include "src/parsing/parser.h" | 8 #include "src/parsing/parser.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 Variable* var = | 154 Variable* var = |
155 parser_->Declare(declaration, descriptor_->declaration_kind, | 155 parser_->Declare(declaration, descriptor_->declaration_kind, |
156 descriptor_->mode != VAR, ok_, descriptor_->hoist_scope); | 156 descriptor_->mode != VAR, ok_, descriptor_->hoist_scope); |
157 if (!*ok_) return; | 157 if (!*ok_) return; |
158 DCHECK_NOT_NULL(var); | 158 DCHECK_NOT_NULL(var); |
159 DCHECK(!proxy->is_resolved() || proxy->var() == var); | 159 DCHECK(!proxy->is_resolved() || proxy->var() == var); |
160 var->set_initializer_position(initializer_position_); | 160 var->set_initializer_position(initializer_position_); |
161 | 161 |
162 DCHECK(initializer_position_ != kNoSourcePosition); | 162 DCHECK(initializer_position_ != kNoSourcePosition); |
163 | 163 |
| 164 // TODO(adamk): This should probably be checking hoist_scope. |
| 165 // Move it to Parser::Declare() to make it easier to test |
| 166 // the right scope. |
164 Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode) | 167 Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode) |
165 ? descriptor_->scope | 168 ? descriptor_->scope |
166 : descriptor_->scope->GetDeclarationScope(); | 169 : descriptor_->scope->GetDeclarationScope(); |
167 if (declaration_scope->num_var() > kMaxNumFunctionLocals) { | 170 if (declaration_scope->num_var() > kMaxNumFunctionLocals) { |
168 parser_->ReportMessage(MessageTemplate::kTooManyVariables); | 171 parser_->ReportMessage(MessageTemplate::kTooManyVariables); |
169 *ok_ = false; | 172 *ok_ = false; |
170 return; | 173 return; |
171 } | 174 } |
172 if (names_) { | 175 if (names_) { |
173 names_->Add(name, zone()); | 176 names_->Add(name, zone()); |
174 } | 177 } |
175 | 178 |
176 // Initialize variables if needed. A | 179 // If there's no initializer, we're done. |
177 // declaration of the form: | 180 if (value == nullptr) return; |
| 181 |
| 182 // A declaration of the form: |
178 // | 183 // |
179 // var v = x; | 184 // var v = x; |
180 // | 185 // |
181 // is syntactic sugar for: | 186 // is syntactic sugar for: |
182 // | 187 // |
183 // var v; v = x; | 188 // var v; v = x; |
184 // | 189 // |
185 // In particular, we need to re-lookup 'v' (in scope_, not | 190 // In particular, we need to re-lookup 'v' as it may be a different |
186 // declaration_scope) as it may be a different 'v' than the 'v' in the | 191 // 'v' than the 'v' in the declaration (e.g., if we are inside a |
187 // declaration (e.g., if we are inside a 'with' statement or 'catch' | 192 // 'with' statement or 'catch' block). Global var declarations |
188 // block). | 193 // also need special treatment. |
189 // | 194 Scope* var_init_scope = descriptor_->scope; |
190 // However, note that const declarations are different! A const | |
191 // declaration of the form: | |
192 // | |
193 // const c = x; | |
194 // | |
195 // is *not* syntactic sugar for: | |
196 // | |
197 // const c; c = x; | |
198 // | |
199 // The "variable" c initialized to x is the same as the declared | |
200 // one - there is no re-lookup (see the last parameter of the | |
201 // Declare() call above). | |
202 Scope* initialization_scope = IsImmutableVariableMode(descriptor_->mode) | |
203 ? declaration_scope | |
204 : descriptor_->scope; | |
205 | 195 |
| 196 if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) { |
| 197 // Global variable declarations must be compiled in a specific |
| 198 // way. When the script containing the global variable declaration |
| 199 // is entered, the global variable must be declared, so that if it |
| 200 // doesn't exist (on the global object itself, see ES5 errata) it |
| 201 // gets created with an initial undefined value. This is handled |
| 202 // by the declarations part of the function representing the |
| 203 // top-level global code; see Runtime::DeclareGlobalVariable. If |
| 204 // it already exists (in the object or in a prototype), it is |
| 205 // *not* touched until the variable declaration statement is |
| 206 // executed. |
| 207 // |
| 208 // Executing the variable declaration statement will always |
| 209 // guarantee to give the global object an own property. |
| 210 // This way, global variable declarations can shadow |
| 211 // properties in the prototype chain, but only after the variable |
| 212 // declaration statement has been executed. This is important in |
| 213 // browsers where the global object (window) has lots of |
| 214 // properties defined in prototype objects. |
206 | 215 |
207 // Global variable declarations must be compiled in a specific | |
208 // way. When the script containing the global variable declaration | |
209 // is entered, the global variable must be declared, so that if it | |
210 // doesn't exist (on the global object itself, see ES5 errata) it | |
211 // gets created with an initial undefined value. This is handled | |
212 // by the declarations part of the function representing the | |
213 // top-level global code; see Runtime::DeclareGlobalVariable. If | |
214 // it already exists (in the object or in a prototype), it is | |
215 // *not* touched until the variable declaration statement is | |
216 // executed. | |
217 // | |
218 // Executing the variable declaration statement will always | |
219 // guarantee to give the global object an own property. | |
220 // This way, global variable declarations can shadow | |
221 // properties in the prototype chain, but only after the variable | |
222 // declaration statement has been executed. This is important in | |
223 // browsers where the global object (window) has lots of | |
224 // properties defined in prototype objects. | |
225 if (initialization_scope->is_script_scope() && | |
226 !IsLexicalVariableMode(descriptor_->mode)) { | |
227 // Compute the arguments for the runtime | |
228 // call.test-parsing/InitializedDeclarationsInStrictForOfError | |
229 ZoneList<Expression*>* arguments = | 216 ZoneList<Expression*>* arguments = |
230 new (zone()) ZoneList<Expression*>(3, zone()); | 217 new (zone()) ZoneList<Expression*>(3, zone()); |
231 // We have at least 1 parameter. | |
232 arguments->Add( | 218 arguments->Add( |
233 factory()->NewStringLiteral(name, descriptor_->declaration_pos), | 219 factory()->NewStringLiteral(name, descriptor_->declaration_pos), |
234 zone()); | 220 zone()); |
235 CallRuntime* initialize; | 221 arguments->Add(factory()->NewNumberLiteral(var_init_scope->language_mode(), |
| 222 kNoSourcePosition), |
| 223 zone()); |
| 224 arguments->Add(value, zone()); |
236 | 225 |
237 if (IsImmutableVariableMode(descriptor_->mode)) { | 226 CallRuntime* initialize = factory()->NewCallRuntime( |
238 arguments->Add(value, zone()); | 227 Runtime::kInitializeVarGlobal, arguments, value->position()); |
239 // Construct the call to Runtime_InitializeConstGlobal | 228 block_->statements()->Add( |
240 // and add it to the initialization statement block. | 229 factory()->NewExpressionStatement(initialize, initialize->position()), |
241 // Note that the function does different things depending on | 230 zone()); |
242 // the number of arguments (1 or 2). | 231 } else { |
243 initialize = factory()->NewCallRuntime(Runtime::kInitializeConstGlobal, | |
244 arguments, value->position()); | |
245 value = NULL; // zap the value to avoid the unnecessary assignment | |
246 } else { | |
247 // Add language mode. | |
248 // We may want to pass singleton to avoid Literal allocations. | |
249 LanguageMode language_mode = initialization_scope->language_mode(); | |
250 arguments->Add( | |
251 factory()->NewNumberLiteral(language_mode, kNoSourcePosition), | |
252 zone()); | |
253 | |
254 // Be careful not to assign a value to the global variable if | |
255 // we're in a with. The initialization value should not | |
256 // necessarily be stored in the global object in that case, | |
257 // which is why we need to generate a separate assignment node. | |
258 if (value != NULL && !descriptor_->scope->inside_with()) { | |
259 arguments->Add(value, zone()); | |
260 // Construct the call to Runtime_InitializeVarGlobal | |
261 // and add it to the initialization statement block. | |
262 initialize = factory()->NewCallRuntime(Runtime::kInitializeVarGlobal, | |
263 arguments, value->position()); | |
264 value = NULL; // zap the value to avoid the unnecessary assignment | |
265 } else { | |
266 initialize = NULL; | |
267 } | |
268 } | |
269 | |
270 if (initialize != NULL) { | |
271 block_->statements()->Add( | |
272 factory()->NewExpressionStatement(initialize, initialize->position()), | |
273 zone()); | |
274 } | |
275 } else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) { | |
276 // For 'let' and 'const' declared variables the initialization always | 232 // For 'let' and 'const' declared variables the initialization always |
277 // assigns to the declared variable. | 233 // assigns to the declared variable. |
278 DCHECK_NOT_NULL(proxy); | 234 // But for var declarations we need to do a new lookup. |
279 DCHECK_NOT_NULL(proxy->var()); | 235 if (descriptor_->mode == VAR) { |
280 DCHECK_NOT_NULL(value); | 236 proxy = var_init_scope->NewUnresolved(factory(), name); |
| 237 } else { |
| 238 DCHECK_NOT_NULL(proxy); |
| 239 DCHECK_NOT_NULL(proxy->var()); |
| 240 } |
281 // Add break location for destructured sub-pattern. | 241 // Add break location for destructured sub-pattern. |
282 int pos = IsSubPattern() ? pattern->position() : value->position(); | 242 int pos = IsSubPattern() ? pattern->position() : value->position(); |
283 Assignment* assignment = | 243 Assignment* assignment = |
284 factory()->NewAssignment(Token::INIT, proxy, value, pos); | |
285 block_->statements()->Add( | |
286 factory()->NewExpressionStatement(assignment, pos), zone()); | |
287 value = NULL; | |
288 } | |
289 | |
290 // Add an assignment node to the initialization statement block if we still | |
291 // have a pending initialization value. | |
292 if (value != NULL) { | |
293 DCHECK(descriptor_->mode == VAR); | |
294 // 'var' initializations are simply assignments (with all the consequences | |
295 // if they are inside a 'with' statement - they may change a 'with' object | |
296 // property). | |
297 VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); | |
298 // Add break location for destructured sub-pattern. | |
299 int pos = IsSubPattern() ? pattern->position() : value->position(); | |
300 Assignment* assignment = | |
301 factory()->NewAssignment(Token::INIT, proxy, value, pos); | 244 factory()->NewAssignment(Token::INIT, proxy, value, pos); |
302 block_->statements()->Add( | 245 block_->statements()->Add( |
303 factory()->NewExpressionStatement(assignment, pos), zone()); | 246 factory()->NewExpressionStatement(assignment, pos), zone()); |
304 } | 247 } |
305 } | 248 } |
306 | 249 |
307 | 250 |
308 Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { | 251 Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) { |
309 auto temp = scope()->NewTemporary(ast_value_factory()->empty_string()); | 252 auto temp = scope()->NewTemporary(ast_value_factory()->empty_string()); |
310 if (value != nullptr) { | 253 if (value != nullptr) { |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 NOT_A_PATTERN(TryFinallyStatement) | 701 NOT_A_PATTERN(TryFinallyStatement) |
759 NOT_A_PATTERN(UnaryOperation) | 702 NOT_A_PATTERN(UnaryOperation) |
760 NOT_A_PATTERN(VariableDeclaration) | 703 NOT_A_PATTERN(VariableDeclaration) |
761 NOT_A_PATTERN(WhileStatement) | 704 NOT_A_PATTERN(WhileStatement) |
762 NOT_A_PATTERN(WithStatement) | 705 NOT_A_PATTERN(WithStatement) |
763 NOT_A_PATTERN(Yield) | 706 NOT_A_PATTERN(Yield) |
764 | 707 |
765 #undef NOT_A_PATTERN | 708 #undef NOT_A_PATTERN |
766 } // namespace internal | 709 } // namespace internal |
767 } // namespace v8 | 710 } // namespace v8 |
OLD | NEW |