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

Unified Diff: src/parser.cc

Issue 6144005: Early draft of strict mode (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Removing parameter validation; Created 9 years, 11 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/messages.js ('k') | test/mjsunit/strict-mode.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/messages.js ('k') | test/mjsunit/strict-mode.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698