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

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: 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
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index 5ea1c5e083ac44a15ea4ac100f1f6848d9d4fffd..338f34697c484ca3cfbbcd13db0591a537462592 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -561,6 +561,23 @@ class LexicalScope BASE_EMBEDDED {
int prev_level_;
};
+// ----------------------------------------------------------------------------
+// Support for strict mode parser stack. The constructor saves the current
+// state and the destructor resets it back.
+class StrictMode BASE_EMBEDDED {
+ public:
+ StrictMode(bool* strict_mode_variable)
+ : strict_mode_variable_(strict_mode_variable),
+ previous_strict_mode_(*strict_mode_variable) {
+ }
+
+ ~StrictMode() {
+ *strict_mode_variable_ = previous_strict_mode_;
+ }
+
+ bool *const strict_mode_variable_;
+ const bool previous_strict_mode_;
+};
// ----------------------------------------------------------------------------
// The CHECK_OK macro is a convenient macro to enforce error
@@ -600,7 +617,8 @@ Parser::Parser(Handle<Script> script,
extension_(extension),
pre_data_(pre_data),
fni_(NULL),
- stack_overflow_(false) {
+ stack_overflow_(false),
+ strict_mode_(false) {
AstNode::ResetIds();
}
@@ -668,7 +686,8 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
0,
source->length(),
false,
- temp_scope.ContainsLoops());
+ temp_scope.ContainsLoops(),
+ strict_mode_);
} else if (stack_overflow_) {
Top::StackOverflow();
}
@@ -1058,7 +1077,23 @@ 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 (!strict_mode_ && directive_prologue) {
+ if (peek() == Token::STRING) {
Lasse Reichstein 2011/01/13 07:18:40 As you pointed out, this is too simple (and ECMASc
Lasse Reichstein 2011/01/13 07:44:07 Argh, location should be: Scanner::Location loca
Martin Maly 2011/01/14 00:06:28 Done. However, we still need to add the directives
Lasse Reichstein 2011/01/14 11:42:05 I don't see how that example applies. The "Hello"
Martin Maly 2011/01/14 16:30:43 Sorry, the example was incorrect eval("'hello'").
Lasse Reichstein 2011/01/17 10:17:49 Ack, yes, now I see.
+ // "use strict" is an ascii literal so no need to check non-ascii ones.
+ if (scanner().is_next_literal_ascii() &&
+ Factory::use_strict()->IsAsciiEqualTo(
+ scanner().next_literal_ascii_string())) {
+ strict_mode_ = true;
+ }
+ } else {
+ // done with directive prologue
+ directive_prologue = false;
+ }
+ }
+
Statement* stat = ParseStatement(NULL, CHECK_OK);
if (stat == NULL || stat->IsEmpty()) continue;
// We find and mark the initialization blocks on top level code only.
@@ -1414,6 +1449,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 +1501,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 (strict_mode_ && 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 +1860,13 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
// 'with' '(' Expression ')' Statement
Expect(Token::WITH, CHECK_OK);
+
+ if (strict_mode_) {
+ 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 +1999,13 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK);
+
+ if (strict_mode_ && IsEvalOrArguments(name)) {
+ ReportMessage("strict_catch_variable", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
@@ -3188,6 +3248,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
TemporaryScope temp_scope(&this->temp_scope_);
top_scope_->SetScopeName(name);
+ // Strict mode stack
+ StrictMode strict(&strict_mode_);
Lasse Reichstein 2011/01/13 07:18:40 As stated earlier, we define the TemporaryScope ju
Martin Maly 2011/01/14 00:06:28 Done.
+
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
@@ -3265,6 +3328,32 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
end_pos = scanner().location().end_pos;
}
+ // Validate strict mode.
+ if (strict_mode_) {
+ int position = function_token_position != RelocInfo::kNoPosition
+ ? function_token_position
+ : (start_pos > 0 ? start_pos - 1 : start_pos);
+
+ if (IsEvalOrArguments(name)) {
+ ReportMessageAt(Scanner::Location(position, start_pos),
+ "strict_function_name", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ if (top_scope_->HasEvalOrArgumentsParameter()) {
+ ReportMessageAt(Scanner::Location(position, start_pos),
Lasse Reichstein 2011/01/13 07:18:40 Could you store the position of the argument that
Martin Maly 2011/01/14 00:06:28 It is definitely possible. I was trying to avoid a
Lasse Reichstein 2011/01/14 11:42:05 Yes, we need to either detect the problems when th
Martin Maly 2011/01/14 16:30:43 Sounds good. On 2011/01/14 11:42:05, Lasse Reichs
+ "strict_param_name", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ if (top_scope_->HasDuplicateParameterName()) {
+ ReportMessageAt(Scanner::Location(position, start_pos),
+ "strict_param_dupe", Vector<const char*>::empty());
Lasse Reichstein 2011/01/13 07:18:40 Also here, could you store the actual position of
Martin Maly 2011/01/14 00:06:28 I believe it can be done, also at a relatively sma
Lasse Reichstein 2011/01/14 11:42:05 I think I would just drop the HashMap and do the s
Martin Maly 2011/01/14 16:30:43 Done.
+ *ok = false;
+ return NULL;
+ }
Lasse Reichstein 2011/01/13 07:18:40 For later, I would also put the check for octal nu
Martin Maly 2011/01/14 00:06:28 Great idea. that will also handle the case where "
+ }
+
FunctionLiteral* function_literal =
new FunctionLiteral(name,
top_scope_,
@@ -3277,7 +3366,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
start_pos,
end_pos,
function_name->length() > 0,
- temp_scope.ContainsLoops());
+ temp_scope.ContainsLoops(),
+ strict_mode_);
function_literal->set_function_token_position(function_token_position);
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);

Powered by Google App Engine
This is Rietveld 408576698