Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 5ea1c5e083ac44a15ea4ac100f1f6848d9d4fffd..61f90377415f23e20e089f76e3f4373c29d95758 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -283,6 +283,11 @@ class TemporaryScope BASE_EMBEDDED { |
void AddLoop() { loop_count_++; } |
bool ContainsLoops() const { return loop_count_ > 0; } |
+ bool StrictMode() { return strict_mode_; } |
+ void EnableStrictMode() { |
+ strict_mode_ = FLAG_strict_mode; |
+ } |
+ |
private: |
// Captures the number of literals that need materialization in the |
// function. Includes regexp literals, and boilerplate for object |
@@ -300,6 +305,9 @@ class TemporaryScope BASE_EMBEDDED { |
// Captures the number of loops inside the scope. |
int loop_count_; |
+ // Parsing strict mode code. |
+ bool strict_mode_; |
+ |
// Bookkeeping |
TemporaryScope** variable_; |
TemporaryScope* parent_; |
@@ -314,6 +322,8 @@ TemporaryScope::TemporaryScope(TemporaryScope** variable) |
loop_count_(0), |
variable_(variable), |
parent_(*variable) { |
+ // Inherit the strict mode from the parent scope. |
+ strict_mode_ = (parent_ != NULL) && parent_->strict_mode_; |
*variable = this; |
} |
@@ -561,7 +571,6 @@ class LexicalScope BASE_EMBEDDED { |
int prev_level_; |
}; |
- |
// ---------------------------------------------------------------------------- |
// The CHECK_OK macro is a convenient macro to enforce error |
// handling for functions that may fail (by returning !*ok). |
@@ -668,7 +677,8 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, |
0, |
source->length(), |
false, |
- temp_scope.ContainsLoops()); |
+ temp_scope.ContainsLoops(), |
+ temp_scope.StrictMode()); |
} else if (stack_overflow_) { |
Top::StackOverflow(); |
} |
@@ -1058,9 +1068,46 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
ASSERT(processor != NULL); |
InitializationBlockFinder block_finder; |
ThisNamedPropertyAssigmentFinder this_property_assignment_finder; |
+ bool directive_prologue = true; // Parsing directive prologue. |
+ |
while (peek() != end_token) { |
+ if (directive_prologue && peek() != Token::STRING) { |
+ directive_prologue = false; |
+ } |
+ |
+ Scanner::Location token_loc = scanner().peek_location(); |
Statement* stat = ParseStatement(NULL, CHECK_OK); |
- if (stat == NULL || stat->IsEmpty()) continue; |
+ |
+ if (stat == NULL || stat->IsEmpty()) { |
+ directive_prologue = false; // End of directive prologue. |
+ continue; |
+ } |
+ |
+ if (directive_prologue) { |
+ // A shot at a directive. |
+ ExpressionStatement *e_stat; |
+ Literal *literal; |
+ // Still processing directive prologue? |
+ if ((e_stat = stat->AsExpressionStatement()) != NULL && |
+ (literal = e_stat->expression()->AsLiteral()) != NULL && |
+ literal->handle()->IsString()) { |
+ Handle<String> directive = Handle<String>::cast(literal->handle()); |
+ |
+ // Check "use strict" directive (ES5 14.1). |
+ if (!temp_scope_->StrictMode() && |
+ directive->Equals(Heap::use_strict()) && |
+ token_loc.end_pos - token_loc.beg_pos == |
+ Heap::use_strict()->length() + 2) { |
+ temp_scope_->EnableStrictMode(); |
+ // "use strict" is the only directive for now. |
+ directive_prologue = false; |
+ } |
+ } else { |
+ // End of the directive prologue. |
+ directive_prologue = false; |
+ } |
+ } |
+ |
// We find and mark the initialization blocks on top level code only. |
// This is because the optimization prevents reuse of the map transitions, |
// so it should be used only for code that will only be run once. |
@@ -1414,6 +1461,10 @@ Block* Parser::ParseVariableStatement(bool* ok) { |
return result; |
} |
+static bool IsEvalOrArguments(Handle<String> string) { |
+ return string.is_identical_to(Factory::eval_symbol()) || |
+ string.is_identical_to(Factory::arguments_symbol()); |
+} |
// If the variable declaration declares exactly one non-const |
// variable, then *var is set to that variable. In all other cases, |
@@ -1462,6 +1513,13 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, |
Handle<String> name = ParseIdentifier(CHECK_OK); |
if (fni_ != NULL) fni_->PushVariableName(name); |
+ // Strict mode variables may not be named eval or arguments |
+ if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) { |
+ ReportMessage("strict_var_name", Vector<const char*>::empty()); |
+ *ok = false; |
+ return NULL; |
+ } |
+ |
// Declare variable. |
// Note that we *always* must treat the initial value via a separate init |
// assignment for variables and constants because the value must be assigned |
@@ -1814,6 +1872,13 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { |
// 'with' '(' Expression ')' Statement |
Expect(Token::WITH, CHECK_OK); |
+ |
+ if (temp_scope_->StrictMode()) { |
+ ReportMessage("strict_mode_with", Vector<const char*>::empty()); |
+ *ok = false; |
+ return NULL; |
+ } |
+ |
Expect(Token::LPAREN, CHECK_OK); |
Expression* expr = ParseExpression(true, CHECK_OK); |
Expect(Token::RPAREN, CHECK_OK); |
@@ -1946,6 +2011,13 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { |
Expect(Token::LPAREN, CHECK_OK); |
Handle<String> name = ParseIdentifier(CHECK_OK); |
+ |
+ if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) { |
+ ReportMessage("strict_catch_variable", Vector<const char*>::empty()); |
+ *ok = false; |
+ return NULL; |
+ } |
+ |
Expect(Token::RPAREN, CHECK_OK); |
if (peek() == Token::LBRACE) { |
@@ -3192,11 +3264,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, |
// '(' (Identifier)*[','] ')' |
Expect(Token::LPAREN, CHECK_OK); |
int start_pos = scanner().location().beg_pos; |
+ |
bool done = (peek() == Token::RPAREN); |
while (!done) { |
Handle<String> param_name = ParseIdentifier(CHECK_OK); |
- top_scope_->AddParameter(top_scope_->DeclareLocal(param_name, |
- Variable::VAR)); |
+ Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR); |
+ top_scope_->AddParameter(parameter); |
num_parameters++; |
done = (peek() == Token::RPAREN); |
if (!done) Expect(Token::COMMA, CHECK_OK); |
@@ -3265,6 +3338,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, |
end_pos = scanner().location().end_pos; |
} |
+ // Validate strict mode. |
+ if (temp_scope_->StrictMode()) { |
+ if (IsEvalOrArguments(name)) { |
+ int position = function_token_position != RelocInfo::kNoPosition |
+ ? function_token_position |
+ : (start_pos > 0 ? start_pos - 1 : start_pos); |
+ ReportMessageAt(Scanner::Location(position, start_pos), |
+ "strict_function_name", Vector<const char*>::empty()); |
+ *ok = false; |
+ return NULL; |
+ } |
+ // TODO(mmaly): Check for octal escape sequence here. |
+ } |
+ |
FunctionLiteral* function_literal = |
new FunctionLiteral(name, |
top_scope_, |
@@ -3277,7 +3364,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, |
start_pos, |
end_pos, |
function_name->length() > 0, |
- temp_scope.ContainsLoops()); |
+ temp_scope.ContainsLoops(), |
+ temp_scope.StrictMode()); |
function_literal->set_function_token_position(function_token_position); |
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal); |