| Index: src/parsing/pattern-rewriter.cc
|
| diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
|
| index 30d521dfa76c47616cbdaf9ecf89399881263795..8d3847237ee2aca8b4fd87bba18b135df2d9ee61 100644
|
| --- a/src/parsing/pattern-rewriter.cc
|
| +++ b/src/parsing/pattern-rewriter.cc
|
| @@ -161,6 +161,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
|
|
| DCHECK(initializer_position_ != kNoSourcePosition);
|
|
|
| + // TODO(adamk): This should probably be checking hoist_scope.
|
| + // Move it to Parser::Declare() to make it easier to test
|
| + // the right scope.
|
| Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode)
|
| ? descriptor_->scope
|
| : descriptor_->scope->GetDeclarationScope();
|
| @@ -173,8 +176,10 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
| names_->Add(name, zone());
|
| }
|
|
|
| - // Initialize variables if needed. A
|
| - // declaration of the form:
|
| + // If there's no initializer, we're done.
|
| + if (value == nullptr) return;
|
| +
|
| + // A declaration of the form:
|
| //
|
| // var v = x;
|
| //
|
| @@ -182,119 +187,57 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
| //
|
| // var v; v = x;
|
| //
|
| - // In particular, we need to re-lookup 'v' (in scope_, not
|
| - // declaration_scope) as it may be a different 'v' than the 'v' in the
|
| - // declaration (e.g., if we are inside a 'with' statement or 'catch'
|
| - // block).
|
| - //
|
| - // However, note that const declarations are different! A const
|
| - // declaration of the form:
|
| - //
|
| - // const c = x;
|
| - //
|
| - // is *not* syntactic sugar for:
|
| - //
|
| - // const c; c = x;
|
| - //
|
| - // The "variable" c initialized to x is the same as the declared
|
| - // one - there is no re-lookup (see the last parameter of the
|
| - // Declare() call above).
|
| - Scope* initialization_scope = IsImmutableVariableMode(descriptor_->mode)
|
| - ? declaration_scope
|
| - : descriptor_->scope;
|
| -
|
| -
|
| - // Global variable declarations must be compiled in a specific
|
| - // way. When the script containing the global variable declaration
|
| - // is entered, the global variable must be declared, so that if it
|
| - // doesn't exist (on the global object itself, see ES5 errata) it
|
| - // gets created with an initial undefined value. This is handled
|
| - // by the declarations part of the function representing the
|
| - // top-level global code; see Runtime::DeclareGlobalVariable. If
|
| - // it already exists (in the object or in a prototype), it is
|
| - // *not* touched until the variable declaration statement is
|
| - // executed.
|
| - //
|
| - // Executing the variable declaration statement will always
|
| - // guarantee to give the global object an own property.
|
| - // This way, global variable declarations can shadow
|
| - // properties in the prototype chain, but only after the variable
|
| - // declaration statement has been executed. This is important in
|
| - // browsers where the global object (window) has lots of
|
| - // properties defined in prototype objects.
|
| - if (initialization_scope->is_script_scope() &&
|
| - !IsLexicalVariableMode(descriptor_->mode)) {
|
| - // Compute the arguments for the runtime
|
| - // call.test-parsing/InitializedDeclarationsInStrictForOfError
|
| + // In particular, we need to re-lookup 'v' as it may be a different
|
| + // 'v' than the 'v' in the declaration (e.g., if we are inside a
|
| + // 'with' statement or 'catch' block). Global var declarations
|
| + // also need special treatment.
|
| + Scope* var_init_scope = descriptor_->scope;
|
| +
|
| + if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) {
|
| + // Global variable declarations must be compiled in a specific
|
| + // way. When the script containing the global variable declaration
|
| + // is entered, the global variable must be declared, so that if it
|
| + // doesn't exist (on the global object itself, see ES5 errata) it
|
| + // gets created with an initial undefined value. This is handled
|
| + // by the declarations part of the function representing the
|
| + // top-level global code; see Runtime::DeclareGlobalVariable. If
|
| + // it already exists (in the object or in a prototype), it is
|
| + // *not* touched until the variable declaration statement is
|
| + // executed.
|
| + //
|
| + // Executing the variable declaration statement will always
|
| + // guarantee to give the global object an own property.
|
| + // This way, global variable declarations can shadow
|
| + // properties in the prototype chain, but only after the variable
|
| + // declaration statement has been executed. This is important in
|
| + // browsers where the global object (window) has lots of
|
| + // properties defined in prototype objects.
|
| +
|
| ZoneList<Expression*>* arguments =
|
| new (zone()) ZoneList<Expression*>(3, zone());
|
| - // We have at least 1 parameter.
|
| arguments->Add(
|
| factory()->NewStringLiteral(name, descriptor_->declaration_pos),
|
| zone());
|
| - CallRuntime* initialize;
|
| -
|
| - if (IsImmutableVariableMode(descriptor_->mode)) {
|
| - arguments->Add(value, zone());
|
| - // Construct the call to Runtime_InitializeConstGlobal
|
| - // and add it to the initialization statement block.
|
| - // Note that the function does different things depending on
|
| - // the number of arguments (1 or 2).
|
| - initialize = factory()->NewCallRuntime(Runtime::kInitializeConstGlobal,
|
| - arguments, value->position());
|
| - value = NULL; // zap the value to avoid the unnecessary assignment
|
| - } else {
|
| - // Add language mode.
|
| - // We may want to pass singleton to avoid Literal allocations.
|
| - LanguageMode language_mode = initialization_scope->language_mode();
|
| - arguments->Add(
|
| - factory()->NewNumberLiteral(language_mode, kNoSourcePosition),
|
| - zone());
|
| + arguments->Add(factory()->NewNumberLiteral(var_init_scope->language_mode(),
|
| + kNoSourcePosition),
|
| + zone());
|
| + arguments->Add(value, zone());
|
|
|
| - // Be careful not to assign a value to the global variable if
|
| - // we're in a with. The initialization value should not
|
| - // necessarily be stored in the global object in that case,
|
| - // which is why we need to generate a separate assignment node.
|
| - if (value != NULL && !descriptor_->scope->inside_with()) {
|
| - arguments->Add(value, zone());
|
| - // Construct the call to Runtime_InitializeVarGlobal
|
| - // and add it to the initialization statement block.
|
| - initialize = factory()->NewCallRuntime(Runtime::kInitializeVarGlobal,
|
| - arguments, value->position());
|
| - value = NULL; // zap the value to avoid the unnecessary assignment
|
| - } else {
|
| - initialize = NULL;
|
| - }
|
| - }
|
| -
|
| - if (initialize != NULL) {
|
| - block_->statements()->Add(
|
| - factory()->NewExpressionStatement(initialize, initialize->position()),
|
| - zone());
|
| - }
|
| - } else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) {
|
| + CallRuntime* initialize = factory()->NewCallRuntime(
|
| + Runtime::kInitializeVarGlobal, arguments, value->position());
|
| + block_->statements()->Add(
|
| + factory()->NewExpressionStatement(initialize, initialize->position()),
|
| + zone());
|
| + } else {
|
| // For 'let' and 'const' declared variables the initialization always
|
| // assigns to the declared variable.
|
| - DCHECK_NOT_NULL(proxy);
|
| - DCHECK_NOT_NULL(proxy->var());
|
| - DCHECK_NOT_NULL(value);
|
| - // Add break location for destructured sub-pattern.
|
| - int pos = IsSubPattern() ? pattern->position() : value->position();
|
| - Assignment* assignment =
|
| - factory()->NewAssignment(Token::INIT, proxy, value, pos);
|
| - block_->statements()->Add(
|
| - factory()->NewExpressionStatement(assignment, pos), zone());
|
| - value = NULL;
|
| - }
|
| -
|
| - // Add an assignment node to the initialization statement block if we still
|
| - // have a pending initialization value.
|
| - if (value != NULL) {
|
| - DCHECK(descriptor_->mode == VAR);
|
| - // 'var' initializations are simply assignments (with all the consequences
|
| - // if they are inside a 'with' statement - they may change a 'with' object
|
| - // property).
|
| - VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
|
| + // But for var declarations we need to do a new lookup.
|
| + if (descriptor_->mode == VAR) {
|
| + proxy = var_init_scope->NewUnresolved(factory(), name);
|
| + } else {
|
| + DCHECK_NOT_NULL(proxy);
|
| + DCHECK_NOT_NULL(proxy->var());
|
| + }
|
| // Add break location for destructured sub-pattern.
|
| int pos = IsSubPattern() ? pattern->position() : value->position();
|
| Assignment* assignment =
|
|
|