Chromium Code Reviews| 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); |