Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Unified Diff: src/parser.cc

Issue 7280012: Introduce scopes to keep track of catch blocks at compile time. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Update to HEAD. Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index 4e5ba1389a030cd3f32a1130b6218d3f2056b4cc..7cb0209a17a43687f0df46001d470b693c42a744 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -411,6 +411,15 @@ Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
return result;
}
+
+Scope* Parser::DeclarationScope() {
Kevin Millikin (Chromium) 2011/06/30 09:28:45 As an alternative, we could keep a pair of scopes.
+ Scope* scope = top_scope_;
+ while (scope->is_catch_scope()) {
+ scope = scope->outer_scope();
+ }
+ return scope;
+}
+
// ----------------------------------------------------------------------------
// Target is a support class to facilitate manipulation of the
// Parser's target_stack_ (the stack of potential 'break' and
@@ -1301,13 +1310,14 @@ VariableProxy* Parser::Declare(Handle<String> name,
// to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too.
- if (top_scope_->is_function_scope() ||
- top_scope_->is_strict_mode_eval_scope()) {
+ Scope* declaration_scope = DeclarationScope();
+ if (declaration_scope->is_function_scope() ||
+ declaration_scope->is_strict_mode_eval_scope()) {
// Declare the variable in the function scope.
- var = top_scope_->LocalLookup(name);
+ var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
- var = top_scope_->DeclareLocal(name, mode);
+ var = declaration_scope->DeclareLocal(name, mode);
} else {
// The name was declared before; check for conflicting
// re-declarations. If the previous declaration was a const or the
@@ -1323,7 +1333,7 @@ VariableProxy* Parser::Declare(Handle<String> name,
Expression* expression =
NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
type_string, name);
- top_scope_->SetIllegalRedeclaration(expression);
+ declaration_scope->SetIllegalRedeclaration(expression);
}
}
}
@@ -1344,14 +1354,18 @@ VariableProxy* Parser::Declare(Handle<String> name,
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
- VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with());
- top_scope_->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
+ VariableProxy* proxy = declaration_scope->NewUnresolved(name, false);
+ declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
// For global const variables we bind the proxy to a variable.
- if (mode == Variable::CONST && top_scope_->is_global_scope()) {
+ if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
- var = new(zone()) Variable(top_scope_, name, Variable::CONST, true, kind);
+ var = new(zone()) Variable(declaration_scope,
+ name,
+ Variable::CONST,
+ true,
+ kind);
}
// If requested and we have a local variable, bind the proxy to the variable
@@ -1407,7 +1421,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing
// because of lazy compilation.
- top_scope_->ForceEagerCompilation();
+ DeclarationScope()->ForceEagerCompilation();
// Compute the function template for the native function.
v8::Handle<v8::FunctionTemplate> fun_template =
@@ -1485,8 +1499,8 @@ Block* Parser::ParseVariableStatement(bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
- Expression* dummy; // to satisfy the ParseVariableDeclarations() signature
- Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK);
+ Handle<String> ignore;
+ Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -1504,18 +1518,19 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
Block* Parser::ParseVariableDeclarations(bool accept_IN,
- Expression** var,
+ Handle<String>* name,
Kevin Millikin (Chromium) 2011/06/30 09:28:45 In most cases (all but 'for (var ... in ...)' the
bool* ok) {
// VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
Variable::Mode mode = Variable::VAR;
bool is_const = false;
+ Scope* declaration_scope = DeclarationScope();
if (peek() == Token::VAR) {
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (top_scope_->is_strict_mode()) {
+ if (declaration_scope->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1540,18 +1555,17 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
//
// Create new block with one expected declaration.
Block* block = new(zone()) Block(NULL, 1, true);
- VariableProxy* last_var = NULL; // the last variable declared
int nvars = 0; // the number of variables declared
do {
if (fni_ != NULL) fni_->Enter();
// Parse variable name.
if (nvars > 0) Consume(Token::COMMA);
- Handle<String> name = ParseIdentifier(CHECK_OK);
- if (fni_ != NULL) fni_->PushVariableName(name);
+ *name = ParseIdentifier(CHECK_OK);
+ if (fni_ != NULL) fni_->PushVariableName(*name);
// Strict mode variables may not be named eval or arguments
- if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
+ if (declaration_scope->is_strict_mode() && IsEvalOrArguments(*name)) {
ReportMessage("strict_var_name", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1569,11 +1583,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// If we have a const declaration, in an inner scope, the proxy is always
// bound to the declared variable (independent of possibly surrounding with
// statements).
- last_var = Declare(name, mode, NULL,
- is_const /* always bound for CONST! */,
- CHECK_OK);
+ Declare(*name, mode, NULL, is_const /* always bound for CONST! */,
+ CHECK_OK);
nvars++;
- if (top_scope_->num_var_or_const() > kMaxNumFunctionLocals) {
+ if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
ReportMessageAt(scanner().location(), "too_many_variables",
Vector<const char*>::empty());
*ok = false;
@@ -1589,10 +1602,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
//
// var v; v = x;
//
- // In particular, we need to re-lookup 'v' as it may be a
- // different 'v' than the 'v' in the declaration (if we are inside
- // a 'with' statement that makes a object property with name 'v'
- // visible).
+ // In particular, we need to re-lookup 'v' (in top_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:
@@ -1607,6 +1620,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// one - there is no re-lookup (see the last parameter of the
// Declare() call above).
+ Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
Kevin Millikin (Chromium) 2011/06/30 09:28:45 It's subtle that the declaration and initializatio
Expression* value = NULL;
int position = -1;
if (peek() == Token::ASSIGN) {
@@ -1647,11 +1661,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
- if (top_scope_->is_global_scope()) {
+ if (initialization_scope->is_global_scope()) {
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
// We have at least 1 parameter.
- arguments->Add(new(zone()) Literal(name));
+ arguments->Add(new(zone()) Literal(*name));
CallRuntime* initialize;
if (is_const) {
@@ -1670,8 +1684,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
- arguments->Add(NewNumberLiteral(
- top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
+ StrictModeFlag flag = initialization_scope->is_strict_mode()
+ ? kStrictMode
+ : kNonStrictMode;
+ arguments->Add(NewNumberLiteral(flag));
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
@@ -1708,8 +1724,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the top context for variables). Sigh...
if (value != NULL) {
Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
+ bool in_with = is_const ? false : inside_with();
+ VariableProxy* proxy =
+ initialization_scope->NewUnresolved(*name, in_with);
Assignment* assignment =
- new(zone()) Assignment(op, last_var, value, position);
+ new(zone()) Assignment(op, proxy, value, position);
if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment));
}
@@ -1718,12 +1737,6 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
if (fni_ != NULL) fni_->Leave();
} while (peek() == Token::COMMA);
- if (!is_const && nvars == 1) {
- // We have a single, non-const variable.
- ASSERT(last_var != NULL);
- *var = last_var;
- }
-
return block;
}
@@ -1895,7 +1908,9 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// function. See ECMA-262, section 12.9, page 67.
//
// To be consistent with KJS we report the syntax error at runtime.
- if (!top_scope_->is_function_scope()) {
+ Scope* declaration_scope = DeclarationScope();
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_eval_scope()) {
Handle<String> type = isolate()->factory()->illegal_return_symbol();
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
return new(zone()) ExpressionStatement(throw_error);
@@ -1922,7 +1937,7 @@ Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
Statement* stat;
{ Target target(&this->target_stack_, &collector);
with_nesting_level_++;
- top_scope_->RecordWithStatement();
+ DeclarationScope()->RecordWithStatement();
Kevin Millikin (Chromium) 2011/06/30 09:28:45 This is wrong, let's talk about what to do here.
Mads Ager (chromium) 2011/06/30 12:08:32 But it is safe, right?
stat = ParseStatement(labels, CHECK_OK);
with_nesting_level_--;
}
@@ -2082,6 +2097,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// block. Since we don't know yet if there will be a finally block, we
// always collect the targets.
TargetCollector catch_collector;
+ Scope* catch_scope = NULL;
+ Variable* catch_variable = NULL;
Block* catch_block = NULL;
Handle<String> name;
if (tok == Token::CATCH) {
@@ -2108,10 +2125,16 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
TargetCollector inner_collector;
{ Target target(&this->target_stack_, &catch_collector);
{ Target target(&this->target_stack_, &inner_collector);
- ++with_nesting_level_;
- top_scope_->RecordWithStatement();
+ catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
+ if (top_scope_->is_strict_mode()) {
+ catch_scope->EnableStrictMode();
+ }
+ catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
+
+ Scope* saved_scope = top_scope_;
+ top_scope_ = catch_scope;
inner_body = ParseBlock(NULL, CHECK_OK);
- --with_nesting_level_;
+ top_scope_ = saved_scope;
}
}
@@ -2145,19 +2168,28 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// 'try { try B0 catch B1 } finally B2'
if (catch_block != NULL && finally_block != NULL) {
+ // If we have both, create an inner try/catch.
+ ASSERT(catch_scope != NULL && catch_variable != NULL);
TryCatchStatement* statement =
- new(zone()) TryCatchStatement(try_block, name, catch_block);
+ new(zone()) TryCatchStatement(try_block,
+ catch_scope,
+ catch_variable,
+ catch_block);
statement->set_escaping_targets(try_collector.targets());
try_block = new(zone()) Block(NULL, 1, false);
try_block->AddStatement(statement);
- catch_block = NULL;
+ catch_block = NULL; // Clear to indicate it's been handled.
}
TryStatement* result = NULL;
if (catch_block != NULL) {
ASSERT(finally_block == NULL);
+ ASSERT(catch_scope != NULL && catch_variable != NULL);
result =
- new(zone()) TryCatchStatement(try_block, name, catch_block);
+ new(zone()) TryCatchStatement(try_block,
+ catch_scope,
+ catch_variable,
+ catch_block);
} else {
ASSERT(finally_block != NULL);
result = new(zone()) TryFinallyStatement(try_block, finally_block);
@@ -2230,9 +2262,11 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::LPAREN, CHECK_OK);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) {
- Expression* each = NULL;
+ Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(false, &each, CHECK_OK);
+ ParseVariableDeclarations(false, &name, CHECK_OK);
+ VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
+
if (peek() == Token::IN && each != NULL) {
ForInStatement* loop = new(zone()) ForInStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2901,8 +2935,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
switch (peek()) {
case Token::THIS: {
Consume(Token::THIS);
- VariableProxy* recv = top_scope_->receiver();
- result = recv;
+ result = new(zone()) VariableProxy(top_scope_->receiver());
break;
}
@@ -3762,7 +3795,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
if (extension_ != NULL) {
// The extension structures are only accessible while parsing the
// very first time not when reparsing because of lazy compilation.
- top_scope_->ForceEagerCompilation();
+ DeclarationScope()->ForceEagerCompilation();
}
const Runtime::Function* function = Runtime::FunctionForSymbol(name);

Powered by Google App Engine
This is Rietveld 408576698