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

Unified Diff: src/parser.cc

Issue 7778013: NewGC: Merge bleeding edge up to 9009. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 4 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
« no previous file with comments | « src/parser.h ('k') | src/platform-linux.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parser.cc
===================================================================
--- src/parser.cc (revision 9006)
+++ src/parser.cc (working copy)
@@ -584,7 +584,8 @@
pre_data_(pre_data),
fni_(NULL),
stack_overflow_(false),
- parenthesized_function_(false) {
+ parenthesized_function_(false),
+ harmony_block_scoping_(false) {
AstNode::ResetIds();
}
@@ -659,8 +660,8 @@
0,
0,
source->length(),
- false,
- false);
+ FunctionLiteral::ANONYMOUS_EXPRESSION,
+ false); // Does not have duplicate parameters.
} else if (stack_overflow_) {
isolate()->StackOverflow();
}
@@ -729,12 +730,13 @@
top_scope_->EnableStrictMode();
}
- FunctionLiteralType type =
- shared_info->is_expression() ? EXPRESSION : DECLARATION;
- Handle<String> function_name =
- shared_info->is_anonymous() ? Handle<String>::null() : name;
+ FunctionLiteral::Type type = shared_info->is_expression()
+ ? (shared_info->is_anonymous()
+ ? FunctionLiteral::ANONYMOUS_EXPRESSION
+ : FunctionLiteral::NAMED_EXPRESSION)
+ : FunctionLiteral::DECLARATION;
bool ok = true;
- result = ParseFunctionLiteral(function_name,
+ result = ParseFunctionLiteral(name,
false, // Strict mode name already checked.
RelocInfo::kNoPosition,
type,
@@ -808,6 +810,10 @@
isolate()->Throw(*result, &location);
}
+void Parser::SetHarmonyBlockScoping(bool block_scoping) {
+ scanner().SetHarmonyBlockScoping(block_scoping);
+ harmony_block_scoping_ = block_scoping;
+}
// Base class containing common code for the different finder classes used by
// the parser.
@@ -1088,6 +1094,25 @@
};
+Statement* Parser::ParseSourceElement(ZoneStringList* labels,
+ bool* ok) {
+ if (peek() == Token::FUNCTION) {
+ // FunctionDeclaration is only allowed in the context of SourceElements
+ // (Ecma 262 5th Edition, clause 14):
+ // SourceElement:
+ // Statement
+ // FunctionDeclaration
+ // Common language extension is to allow function declaration in place
+ // of any statement. This language extension is disabled in strict mode.
+ return ParseFunctionDeclaration(ok);
+ } else if (peek() == Token::LET) {
+ return ParseVariableStatement(kSourceElement, ok);
+ } else {
+ return ParseStatement(labels, ok);
+ }
+}
+
+
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool* ok) {
@@ -1111,21 +1136,7 @@
}
Scanner::Location token_loc = scanner().peek_location();
-
- Statement* stat;
- if (peek() == Token::FUNCTION) {
- // FunctionDeclaration is only allowed in the context of SourceElements
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
- // Statement
- // FunctionDeclaration
- // Common language extension is to allow function declaration in place
- // of any statement. This language extension is disabled in strict mode.
- stat = ParseFunctionDeclaration(CHECK_OK);
- } else {
- stat = ParseStatement(NULL, CHECK_OK);
- }
-
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@@ -1213,7 +1224,7 @@
case Token::CONST: // fall through
case Token::VAR:
- stmt = ParseVariableStatement(ok);
+ stmt = ParseVariableStatement(kStatement, ok);
break;
case Token::SEMICOLON:
@@ -1308,9 +1319,9 @@
bool resolve,
bool* ok) {
Variable* var = NULL;
- // If we are inside a function, a declaration of a variable
- // is a truly local variable, and the scope of the variable
- // is always the function scope.
+ // If we are inside a function, a declaration of a var/const variable is a
+ // truly local variable, and the scope of the variable is always the function
+ // scope.
// If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node
@@ -1320,24 +1331,28 @@
// 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.
- Scope* declaration_scope = top_scope_->DeclarationScope();
+
+ Scope* declaration_scope = mode == Variable::LET ? top_scope_
+ : top_scope_->DeclarationScope();
if (declaration_scope->is_function_scope() ||
- declaration_scope->is_strict_mode_eval_scope()) {
+ declaration_scope->is_strict_mode_eval_scope() ||
+ declaration_scope->is_block_scope()) {
// Declare the variable in the function scope.
var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
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
- // current declaration is a const then we have a conflict. There is
- // similar code in runtime.cc in the Declare functions.
- if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) {
- // We only have vars and consts in declarations.
+ // The name was declared 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 functions.
+ if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
+ // We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR ||
- var->mode() == Variable::CONST);
- const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
+ var->mode() == Variable::CONST ||
+ var->mode() == Variable::LET);
+ const char* type = (var->mode() == Variable::VAR) ? "var" :
+ (var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
@@ -1475,17 +1490,20 @@
FunctionLiteral* fun = ParseFunctionLiteral(name,
is_strict_reserved,
function_token_position,
- DECLARATION,
+ 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
// initial value upon entering the corresponding scope.
- Declare(name, Variable::VAR, fun, true, CHECK_OK);
+ Variable::Mode mode = harmony_block_scoping_ ? Variable::LET : Variable::VAR;
+ Declare(name, mode, fun, true, CHECK_OK);
return EmptyStatement();
}
Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
+ if (harmony_block_scoping_) return ParseScopedBlock(labels, ok);
+
// Block ::
// '{' Statement* '}'
@@ -1509,12 +1527,65 @@
}
-Block* Parser::ParseVariableStatement(bool* ok) {
+Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
+ // Construct block expecting 16 statements.
+ Block* body = new(zone()) Block(isolate(), labels, 16, false);
+ Scope* saved_scope = top_scope_;
+ Scope* block_scope = NewScope(top_scope_,
+ Scope::BLOCK_SCOPE,
+ inside_with());
+ body->set_block_scope(block_scope);
+ block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
+ Variable::VAR);
+ if (top_scope_->is_strict_mode()) {
+ block_scope->EnableStrictMode();
+ }
+ top_scope_ = block_scope;
+
+ // Parse the statements and collect escaping labels.
+ TargetCollector collector;
+ Target target(&this->target_stack_, &collector);
+ Expect(Token::LBRACE, CHECK_OK);
+ {
+ Target target_body(&this->target_stack_, body);
+ InitializationBlockFinder block_finder(top_scope_, target_stack_);
+
+ while (peek() != Token::RBRACE) {
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK);
+ if (stat && !stat->IsEmpty()) {
+ body->AddStatement(stat);
+ block_finder.Update(stat);
+ }
+ }
+ }
+ Expect(Token::RBRACE, CHECK_OK);
+
+ // Create exit block.
+ Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
+ exit->AddStatement(new(zone()) ExitContextStatement());
+
+ // Create a try-finally statement.
+ TryFinallyStatement* try_finally =
+ new(zone()) TryFinallyStatement(body, exit);
+ try_finally->set_escaping_targets(collector.targets());
+ top_scope_ = saved_scope;
+
+ // Create a result block.
+ Block* result = new(zone()) Block(isolate(), NULL, 1, false);
+ result->AddStatement(try_finally);
+ return result;
+}
+
+
+Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
+ bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
Handle<String> ignore;
- Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
+ Block* result = ParseVariableDeclarations(var_context,
+ &ignore,
+ CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -1531,7 +1602,7 @@
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
-Block* Parser::ParseVariableDeclarations(bool accept_IN,
+Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
@@ -1539,25 +1610,36 @@
Variable::Mode mode = Variable::VAR;
bool is_const = false;
- Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) {
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (declaration_scope->is_strict_mode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
}
mode = Variable::CONST;
is_const = true;
+ } else if (peek() == Token::LET) {
+ Consume(Token::LET);
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ ASSERT(var_context == kStatement);
+ ReportMessage("unprotected_let", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ mode = Variable::LET;
} else {
UNREACHABLE(); // by current callers
}
- // The scope of a variable/const declared anywhere inside a function
+ Scope* declaration_scope = mode == Variable::LET
+ ? top_scope_ : top_scope_->DeclarationScope();
+ // The scope of a var/const declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
- // transform a source-level variable/const declaration into a (Function)
+ // transform a source-level var/const declaration into a (Function)
// Scope declaration, and rewrite the source-level initialization into an
// assignment statement. We use a block to collect multiple assignments.
//
@@ -1641,7 +1723,7 @@
if (peek() == Token::ASSIGN) {
Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos;
- value = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
// Don't infer if it is "a = function(){...}();"-like expression.
if (fni_ != NULL &&
value->AsCall() == NULL &&
@@ -1955,41 +2037,6 @@
}
-Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
- // Parse the statement and collect escaping labels.
- TargetCollector collector;
- Statement* stat;
- { Target target(&this->target_stack_, &collector);
- with_nesting_level_++;
- top_scope_->DeclarationScope()->RecordWithStatement();
- stat = ParseStatement(labels, CHECK_OK);
- with_nesting_level_--;
- }
- // Create resulting block with two statements.
- // 1: Evaluate the with expression.
- // 2: The try-finally block evaluating the body.
- Block* result = new(zone()) Block(isolate(), NULL, 2, false);
-
- if (result != NULL) {
- result->AddStatement(new(zone()) EnterWithContextStatement(obj));
-
- // Create body block.
- Block* body = new(zone()) Block(isolate(), NULL, 1, false);
- body->AddStatement(stat);
-
- // Create exit block.
- Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
- exit->AddStatement(new(zone()) ExitContextStatement());
-
- // Return a try-finally statement.
- TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
- wrapper->set_escaping_targets(collector.targets());
- result->AddStatement(wrapper);
- }
- return result;
-}
-
-
Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
@@ -2006,7 +2053,11 @@
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- return WithHelper(expr, labels, CHECK_OK);
+ ++with_nesting_level_;
+ top_scope_->DeclarationScope()->RecordWithStatement();
+ Statement* stmt = ParseStatement(labels, CHECK_OK);
+ --with_nesting_level_;
+ return new(zone()) WithStatement(expr, stmt);
}
@@ -2141,39 +2192,22 @@
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
- // Rewrite the catch body B to a single statement block
- // { try B finally { PopContext }}.
- Block* inner_body;
- // We need to collect escapes from the body for both the inner
- // try/finally used to pop the catch context and any possible outer
- // try/finally.
- TargetCollector inner_collector;
- { Target target(&this->target_stack_, &catch_collector);
- { Target target(&this->target_stack_, &inner_collector);
- 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);
- top_scope_ = saved_scope;
- }
+ // Rewrite the catch body { B } to a block:
+ // { { B } ExitContext; }.
+ Target target(&this->target_stack_, &catch_collector);
+ 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);
+ catch_block = new(zone()) Block(isolate(), NULL, 2, false);
- // Create exit block.
- Block* inner_finally = new(zone()) Block(isolate(), NULL, 1, false);
- inner_finally->AddStatement(new(zone()) ExitContextStatement());
-
- // Create a try/finally statement.
- TryFinallyStatement* inner_try_finally =
- new(zone()) TryFinallyStatement(inner_body, inner_finally);
- inner_try_finally->set_escaping_targets(inner_collector.targets());
-
- catch_block = new(zone()) Block(isolate(), NULL, 1, false);
- catch_block->AddStatement(inner_try_finally);
+ Scope* saved_scope = top_scope_;
+ top_scope_ = catch_scope;
+ Block* catch_body = ParseBlock(NULL, CHECK_OK);
+ top_scope_ = saved_scope;
+ catch_block->AddStatement(catch_body);
+ catch_block->AddStatement(new(zone()) ExitContextStatement());
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@@ -2289,7 +2323,7 @@
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(false, &name, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
@@ -2846,10 +2880,13 @@
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
CHECK_OK);
}
+ FunctionLiteral::Type type = name.is_null()
+ ? FunctionLiteral::ANONYMOUS_EXPRESSION
+ : FunctionLiteral::NAMED_EXPRESSION;
result = ParseFunctionLiteral(name,
is_strict_reserved_name,
function_token_position,
- EXPRESSION,
+ type,
CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
@@ -3419,7 +3456,7 @@
ParseFunctionLiteral(name,
false, // reserved words are allowed here
RelocInfo::kNoPosition,
- EXPRESSION,
+ FunctionLiteral::ANONYMOUS_EXPRESSION,
CHECK_OK);
// Allow any number of parameters for compatiabilty with JSC.
// Specification only allows zero parameters for get and one for set.
@@ -3629,7 +3666,7 @@
FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
bool name_is_strict_reserved,
int function_token_position,
- FunctionLiteralType type,
+ FunctionLiteral::Type type,
bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -3645,8 +3682,11 @@
}
int num_parameters = 0;
- // Function declarations are hoisted.
- Scope* scope = (type == DECLARATION)
+ // Function declarations are function scoped in normal mode, so they are
+ // hoisted. In harmony block scoping mode they are block scoped, so they
+ // are not hoisted.
+ Scope* scope = (type == FunctionLiteral::DECLARATION &&
+ !harmony_block_scoping_)
? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
@@ -3709,7 +3749,7 @@
// NOTE: We create a proxy and resolve it here so that in the
// future we can change the AST to only refer to VariableProxies
// instead of Variables and Proxis as is the case now.
- if (type == EXPRESSION && function_name->length() > 0) {
+ if (type == FunctionLiteral::NAMED_EXPRESSION) {
Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
VariableProxy* fproxy =
top_scope_->NewUnresolved(function_name, inside_with());
@@ -3827,7 +3867,7 @@
num_parameters,
start_pos,
end_pos,
- type == EXPRESSION,
+ type,
has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
@@ -3948,7 +3988,7 @@
}
-// Parses and identifier that is valid for the current scope, in particular it
+// Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
if (top_scope_->is_strict_mode()) {
@@ -5029,9 +5069,11 @@
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
bool allow_lazy,
- ParserRecorder* recorder) {
+ ParserRecorder* recorder,
+ bool harmony_block_scoping) {
Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache());
+ scanner.SetHarmonyBlockScoping(harmony_block_scoping);
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
@@ -5052,7 +5094,8 @@
// Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
- v8::Extension* extension) {
+ v8::Extension* extension,
+ bool harmony_block_scoping) {
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
@@ -5060,16 +5103,17 @@
return NULL;
}
PartialParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder);
+ return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
- v8::Extension* extension) {
+ v8::Extension* extension,
+ bool harmony_block_scoping) {
Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder);
+ return DoPreParse(source, allow_lazy, &recorder, harmony_block_scoping);
}
@@ -5099,15 +5143,22 @@
ASSERT(info->function() == NULL);
FunctionLiteral* result = NULL;
Handle<Script> script = info->script();
+ bool harmony_block_scoping = !info->is_native() &&
+ FLAG_harmony_block_scoping;
if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL);
+ parser.SetHarmonyBlockScoping(harmony_block_scoping);
result = parser.ParseLazy(info);
} else {
// Whether we allow %identifier(..) syntax.
bool allow_natives_syntax =
info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
- Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
+ Parser parser(script,
+ allow_natives_syntax,
+ info->extension(),
+ pre_data);
+ parser.SetHarmonyBlockScoping(harmony_block_scoping);
if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage();
@@ -5126,7 +5177,6 @@
info->StrictMode());
}
}
-
info->SetFunction(result);
return (result != NULL);
}
« no previous file with comments | « src/parser.h ('k') | src/platform-linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698