Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 472740e8931c2295334fc136247ecce9af0882c2..1ec133876c07cc20e5a084b101edeef36cb6a4e3 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -624,19 +624,20 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, |
FunctionLiteral* result = NULL; |
{ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE); |
info->SetGlobalScope(scope); |
+ if (!info->context().is_null()) { |
+ scope = Scope::DeserializeScopeChain(*info->context(), scope, zone()); |
+ } |
if (info->is_eval()) { |
- Handle<SharedFunctionInfo> shared = info->shared_info(); |
- if (!info->is_global() && (shared.is_null() || shared->is_function())) { |
- scope = Scope::DeserializeScopeChain(*info->calling_context(), scope, |
- zone()); |
- } |
if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) { |
scope = NewScope(scope, EVAL_SCOPE); |
} |
+ } else if (info->is_global()) { |
+ scope = NewScope(scope, GLOBAL_SCOPE); |
} |
scope->set_start_position(0); |
scope->set_end_position(source->length()); |
- FunctionState function_state(this, scope, isolate()); |
+ |
+ FunctionState function_state(this, scope, isolate()); // Enters 'scope'. |
top_scope_->SetLanguageMode(info->language_mode()); |
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); |
bool ok = true; |
@@ -1787,50 +1788,58 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { |
declaration_scope->is_strict_or_extended_eval_scope() || |
declaration_scope->is_block_scope() || |
declaration_scope->is_module_scope() || |
- declaration->AsModuleDeclaration() != NULL) { |
+ declaration_scope->is_global_scope()) { |
// Declare the variable in the declaration scope. |
- var = declaration_scope->LocalLookup(name); |
+ // For the global scope, we have to check for collisions with earlier |
+ // (i.e., enclosing) global scopes, to maintain the illusion of a single |
+ // global scope. |
+ var = declaration_scope->is_global_scope() |
+ ? declaration_scope->Lookup(name) |
+ : declaration_scope->LocalLookup(name); |
if (var == NULL) { |
// Declare the name. |
var = declaration_scope->DeclareLocal( |
name, mode, declaration->initialization(), proxy->interface()); |
- } else { |
+ } else if ((mode != VAR || var->mode() != VAR) && |
+ (!declaration_scope->is_global_scope() || |
+ (mode != VAR && mode != CONST) || |
Sven Panne
2012/08/28 07:35:00
o_O
rossberg
2012/08/28 11:09:39
You gotta love the beauty of semantic incoherence
|
+ (var->mode() != VAR && var->mode() != CONST))) { |
// The name was declared in this scope before; check for conflicting |
// re-declarations. We have a conflict if either of the declarations is |
- // not a var. There is similar code in runtime.cc in the Declare |
+ // not a var (in the global scope, we also have to ignore legacy const for |
+ // compatibility). There is similar code in runtime.cc in the Declare |
// functions. The function CheckNonConflictingScope checks for conflicting |
// var and let bindings from different scopes whereas this is a check for |
// conflicting declarations within the same scope. This check also covers |
+ // the special case |
// |
// function () { let x; { var x; } } |
// |
// because the var declaration is hoisted to the function scope where 'x' |
// is already bound. |
- if ((mode != VAR) || (var->mode() != VAR)) { |
- // We only have vars, consts and lets in declarations. |
- ASSERT(var->mode() == VAR || |
- var->mode() == CONST || |
- var->mode() == CONST_HARMONY || |
- var->mode() == LET); |
- if (is_extended_mode()) { |
- // In harmony mode we treat re-declarations as early errors. See |
- // ES5 16 for a definition of early errors. |
- SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS); |
- const char* elms[2] = { "Variable", *c_string }; |
- Vector<const char*> args(elms, 2); |
- ReportMessage("redeclaration", args); |
- *ok = false; |
- return; |
- } |
- const char* type = (var->mode() == VAR) |
- ? "var" : var->is_const_mode() ? "const" : "let"; |
- Handle<String> type_string = |
- isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED); |
- Expression* expression = |
- NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), |
- type_string, name); |
- declaration_scope->SetIllegalRedeclaration(expression); |
+ // We only have vars, consts and lets in declarations. |
+ ASSERT(var->mode() == VAR || |
+ var->mode() == CONST || |
+ var->mode() == CONST_HARMONY || |
+ var->mode() == LET); |
+ if (is_extended_mode()) { |
+ // In harmony mode we treat re-declarations as early errors. See |
+ // ES5 16 for a definition of early errors. |
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS); |
+ const char* elms[2] = { "Variable", *c_string }; |
+ Vector<const char*> args(elms, 2); |
+ ReportMessage("redeclaration", args); |
+ *ok = false; |
+ return; |
} |
+ const char* type = |
+ (var->mode() == VAR) ? "var" : var->is_const_mode() ? "const" : "let"; |
+ Handle<String> type_string = |
+ isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED); |
+ Expression* expression = |
+ NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), |
+ type_string, name); |
+ declaration_scope->SetIllegalRedeclaration(expression); |
} |
} |
@@ -1852,8 +1861,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { |
// Runtime::DeclareContextSlot() calls. |
declaration_scope->AddDeclaration(declaration); |
- if ((mode == CONST || mode == CONST_HARMONY) && |
- declaration_scope->is_global_scope()) { |
+ if (mode == CONST && declaration_scope->is_global_scope()) { |
// For global const variables we bind the proxy to a variable. |
ASSERT(resolve); // should be set by all callers |
Variable::Kind kind = Variable::NORMAL; |
@@ -2004,9 +2012,12 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) { |
FunctionLiteral::DECLARATION, |
CHECK_OK); |
// Even if we're not at the top-level of the global or a function |
- // scope, we treat is as such and introduce the function with it's |
+ // scope, we treat it as such and introduce the function with its |
// initial value upon entering the corresponding scope. |
- VariableMode mode = is_extended_mode() ? LET : VAR; |
+ // In extended mode, a function behaves as a lexical binding, except in the |
+ // global scope. |
+ VariableMode mode = |
+ is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR; |
VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue()); |
Declaration* declaration = |
factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_); |
@@ -2329,7 +2340,8 @@ Block* Parser::ParseVariableDeclarations( |
// 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_global_scope()) { |
+ if (initialization_scope->is_global_scope() && |
+ mode != LET && mode != CONST_HARMONY) { |
// Compute the arguments for the runtime call. |
ZoneList<Expression*>* arguments = |
new(zone()) ZoneList<Expression*>(3, zone()); |