Commit 81504642 authored by marja@chromium.org's avatar marja@chromium.org

Make strict more error messages about "eval" and "arguments" less specific.

We used to have error messages which provide context, like "Variable name may
not be eval or arguments in strict mode", but for other illegal words we only
have non-context specific error messages like "Unexpected reserved word".

Providing the context makes the code unnecessarily complex, since every
individual place must remember to check for eval or arguments. This CL produces
a unified error message ("Unexpected eval or arguments in strict mode"), and puts
the error reporting to (Pre)Parser::ParseIdentifier.

Notes:

- The module feature is so experimental, that I decided to not allow "eval" or
"arguments" as module-related identifiers in the strict mode (even though this
check wasn't there before).

- Unfortunately, there were some inconsistencies, since it was the
responsibility of the caller of ParseIdentifier to check "eval" and "arguments"
and some places didn't have the check for no good reason. This CL is supposed to
keep backward compatibility and *not* introduce any new errors.

- ECMA allows "eval" and "arguments" as labels even in strict mode. (Syntax:
"LabelledStatement: Identifier : Statement", and no strict mode restrictions on
Identifier are listed.)

- Tests which compare error message strings will fail, and need to be updated.

BUG=3126
LOG=N
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/152813005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5028ebaa
...@@ -155,21 +155,15 @@ var kMessages = { ...@@ -155,21 +155,15 @@ var kMessages = {
illegal_access: ["Illegal access"], illegal_access: ["Illegal access"],
invalid_preparser_data: ["Invalid preparser data for function ", "%0"], invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
strict_mode_with: ["Strict mode code may not include a with statement"], strict_mode_with: ["Strict mode code may not include a with statement"],
strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"], strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"], too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"],
too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"], too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"],
too_many_variables: ["Too many variables declared (only 131071 allowed)"], too_many_variables: ["Too many variables declared (only 131071 allowed)"],
strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"],
strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
strict_var_name: ["Variable name may not be eval or arguments in strict mode"],
strict_function_name: ["Function name may not be eval or arguments in strict mode"],
strict_octal_literal: ["Octal literals are not allowed in strict mode."], strict_octal_literal: ["Octal literals are not allowed in strict mode."],
strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
accessor_data_property: ["Object literal may not have data and accessor property with the same name"], accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"],
strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
strict_delete: ["Delete of an unqualified identifier in strict mode."], strict_delete: ["Delete of an unqualified identifier in strict mode."],
strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
strict_const: ["Use of const in strict mode."], strict_const: ["Use of const in strict mode."],
......
...@@ -983,7 +983,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { ...@@ -983,7 +983,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
// 'module' Identifier Module // 'module' Identifier Module
int pos = peek_position(); int pos = peek_position();
Handle<String> name = ParseIdentifier(CHECK_OK); Handle<String> name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
#ifdef DEBUG #ifdef DEBUG
if (FLAG_print_interface_details) if (FLAG_print_interface_details)
...@@ -1136,7 +1136,7 @@ Module* Parser::ParseModuleVariable(bool* ok) { ...@@ -1136,7 +1136,7 @@ Module* Parser::ParseModuleVariable(bool* ok) {
// Identifier // Identifier
int pos = peek_position(); int pos = peek_position();
Handle<String> name = ParseIdentifier(CHECK_OK); Handle<String> name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
#ifdef DEBUG #ifdef DEBUG
if (FLAG_print_interface_details) if (FLAG_print_interface_details)
PrintF("# Module variable %s ", name->ToAsciiArray()); PrintF("# Module variable %s ", name->ToAsciiArray());
...@@ -1261,13 +1261,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { ...@@ -1261,13 +1261,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
switch (peek()) { switch (peek()) {
case Token::IDENTIFIER: { case Token::IDENTIFIER: {
int pos = position(); int pos = position();
Handle<String> name = ParseIdentifier(CHECK_OK); Handle<String> name =
ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
// Handle 'module' as a context-sensitive keyword. // Handle 'module' as a context-sensitive keyword.
if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) { if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) {
names.Add(name, zone()); names.Add(name, zone());
while (peek() == Token::COMMA) { while (peek() == Token::COMMA) {
Consume(Token::COMMA); Consume(Token::COMMA);
name = ParseIdentifier(CHECK_OK); name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
names.Add(name, zone()); names.Add(name, zone());
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
...@@ -1632,11 +1633,12 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { ...@@ -1632,11 +1633,12 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
Statement* Parser::ParseNativeDeclaration(bool* ok) { Statement* Parser::ParseNativeDeclaration(bool* ok) {
int pos = peek_position(); int pos = peek_position();
Expect(Token::FUNCTION, CHECK_OK); Expect(Token::FUNCTION, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK); // Allow "eval" or "arguments" for backward compatibility.
Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
bool done = (peek() == Token::RPAREN); bool done = (peek() == Token::RPAREN);
while (!done) { while (!done) {
ParseIdentifier(CHECK_OK); ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
done = (peek() == Token::RPAREN); done = (peek() == Token::RPAREN);
if (!done) { if (!done) {
Expect(Token::COMMA, CHECK_OK); Expect(Token::COMMA, CHECK_OK);
...@@ -1900,16 +1902,9 @@ Block* Parser::ParseVariableDeclarations( ...@@ -1900,16 +1902,9 @@ Block* Parser::ParseVariableDeclarations(
// Parse variable name. // Parse variable name.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
name = ParseIdentifier(CHECK_OK); name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name); if (fni_ != NULL) fni_->PushVariableName(name);
// Strict mode variables may not be named eval or arguments
if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_var_name", Vector<const char*>::empty());
*ok = false;
return NULL;
}
// Declare variable. // Declare variable.
// Note that we *always* must treat the initial value via a separate init // Note that we *always* must treat the initial value via a separate init
// assignment for variables and constants because the value must be assigned // assignment for variables and constants because the value must be assigned
...@@ -2224,7 +2219,8 @@ Statement* Parser::ParseContinueStatement(bool* ok) { ...@@ -2224,7 +2219,8 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
Token::Value tok = peek(); Token::Value tok = peek();
if (!scanner().HasAnyLineTerminatorBeforeNext() && if (!scanner().HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK); // ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
} }
IterationStatement* target = NULL; IterationStatement* target = NULL;
target = LookupContinueTarget(label, CHECK_OK); target = LookupContinueTarget(label, CHECK_OK);
...@@ -2255,7 +2251,8 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { ...@@ -2255,7 +2251,8 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
Token::Value tok = peek(); Token::Value tok = peek();
if (!scanner().HasAnyLineTerminatorBeforeNext() && if (!scanner().HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK); // ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
} }
// Parse labeled break statements that target themselves into // Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;' // empty statements, e.g. 'l1: l2: l3: break l2;'
...@@ -2485,13 +2482,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2485,13 +2482,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
catch_scope = NewScope(top_scope_, CATCH_SCOPE); catch_scope = NewScope(top_scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner().location().beg_pos); catch_scope->set_start_position(scanner().location().beg_pos);
name = ParseIdentifier(CHECK_OK); name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_catch_variable", Vector<const char*>::empty());
*ok = false;
return NULL;
}
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
...@@ -2939,7 +2930,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2939,7 +2930,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
if (!top_scope_->is_classic_mode()) { if (!top_scope_->is_classic_mode()) {
// Assignment to eval or arguments is disallowed in strict mode. // Assignment to eval or arguments is disallowed in strict mode.
CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK); CheckStrictModeLValue(expression, CHECK_OK);
} }
MarkAsLValue(expression); MarkAsLValue(expression);
...@@ -3219,7 +3210,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { ...@@ -3219,7 +3210,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
if (!top_scope_->is_classic_mode()) { if (!top_scope_->is_classic_mode()) {
// Prefix expression operand in strict mode may not be eval or arguments. // Prefix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK); CheckStrictModeLValue(expression, CHECK_OK);
} }
MarkAsLValue(expression); MarkAsLValue(expression);
...@@ -3253,7 +3244,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { ...@@ -3253,7 +3244,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
if (!top_scope_->is_classic_mode()) { if (!top_scope_->is_classic_mode()) {
// Postfix expression operand in strict mode may not be eval or arguments. // Postfix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, "strict_lhs_postfix", CHECK_OK); CheckStrictModeLValue(expression, CHECK_OK);
} }
MarkAsLValue(expression); MarkAsLValue(expression);
...@@ -3563,7 +3554,8 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { ...@@ -3563,7 +3554,8 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::IDENTIFIER: case Token::IDENTIFIER:
case Token::YIELD: case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD: { case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK); // Using eval or arguments in this context is OK even in strict mode.
Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name); if (fni_ != NULL) fni_->PushVariableName(name);
// The name may refer to a module instance object, so its type is unknown. // The name may refer to a module instance object, so its type is unknown.
#ifdef DEBUG #ifdef DEBUG
...@@ -4303,13 +4295,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4303,13 +4295,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (!top_scope_->is_classic_mode()) { if (!top_scope_->is_classic_mode()) {
if (IsEvalOrArguments(function_name)) { if (IsEvalOrArguments(function_name)) {
ReportMessageAt(function_name_location, ReportMessageAt(function_name_location,
"strict_function_name", "strict_eval_arguments",
Vector<const char*>::empty()); Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
} }
if (name_loc.IsValid()) { if (name_loc.IsValid()) {
ReportMessageAt(name_loc, "strict_param_name", ReportMessageAt(name_loc, "strict_eval_arguments",
Vector<const char*>::empty()); Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
...@@ -4398,7 +4390,8 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { ...@@ -4398,7 +4390,8 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
int pos = peek_position(); int pos = peek_position();
Expect(Token::MOD, CHECK_OK); Expect(Token::MOD, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK); // Allow "eval" or "arguments" for backward compatibility.
Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
ZoneList<Expression*>* args = ParseArguments(CHECK_OK); ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
if (extension_ != NULL) { if (extension_ != NULL) {
...@@ -4505,13 +4498,25 @@ Literal* Parser::GetLiteralTheHole(int position) { ...@@ -4505,13 +4498,25 @@ Literal* Parser::GetLiteralTheHole(int position) {
// Parses an 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. // fails on strict mode future reserved keywords in a strict scope. If
Handle<String> Parser::ParseIdentifier(bool* ok) { // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
// "arguments" as identifier even in strict mode (this is needed in cases like
// "var foo = eval;").
Handle<String> Parser::ParseIdentifier(
AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
bool* ok) {
Token::Value next = Next(); Token::Value next = Next();
if (next == Token::IDENTIFIER || if (next == Token::IDENTIFIER) {
(top_scope_->is_classic_mode() && Handle<String> name = GetSymbol();
(next == Token::FUTURE_STRICT_RESERVED_WORD || if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
(next == Token::YIELD && !is_generator())))) { !top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
*ok = false;
}
return name;
} else if (top_scope_->is_classic_mode() &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
(next == Token::YIELD && !is_generator()))) {
return GetSymbol(); return GetSymbol();
} else { } else {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
...@@ -4566,7 +4571,6 @@ void Parser::MarkAsLValue(Expression* expression) { ...@@ -4566,7 +4571,6 @@ void Parser::MarkAsLValue(Expression* expression) {
// Checks LHS expression for assignment and prefix/postfix increment/decrement // Checks LHS expression for assignment and prefix/postfix increment/decrement
// in strict mode. // in strict mode.
void Parser::CheckStrictModeLValue(Expression* expression, void Parser::CheckStrictModeLValue(Expression* expression,
const char* error,
bool* ok) { bool* ok) {
ASSERT(!top_scope_->is_classic_mode()); ASSERT(!top_scope_->is_classic_mode());
VariableProxy* lhs = expression != NULL VariableProxy* lhs = expression != NULL
...@@ -4574,7 +4578,7 @@ void Parser::CheckStrictModeLValue(Expression* expression, ...@@ -4574,7 +4578,7 @@ void Parser::CheckStrictModeLValue(Expression* expression,
: NULL; : NULL;
if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) { if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
ReportMessage(error, Vector<const char*>::empty()); ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
*ok = false; *ok = false;
} }
} }
......
...@@ -687,7 +687,7 @@ class Parser : public ParserBase { ...@@ -687,7 +687,7 @@ class Parser : public ParserBase {
Literal* GetLiteralUndefined(int position); Literal* GetLiteralUndefined(int position);
Literal* GetLiteralTheHole(int position); Literal* GetLiteralTheHole(int position);
Handle<String> ParseIdentifier(bool* ok); Handle<String> ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
Handle<String> ParseIdentifierOrStrictReservedWord( Handle<String> ParseIdentifierOrStrictReservedWord(
bool* is_strict_reserved, bool* ok); bool* is_strict_reserved, bool* ok);
Handle<String> ParseIdentifierName(bool* ok); Handle<String> ParseIdentifierName(bool* ok);
...@@ -702,7 +702,6 @@ class Parser : public ParserBase { ...@@ -702,7 +702,6 @@ class Parser : public ParserBase {
// Strict mode validation of LValue expressions // Strict mode validation of LValue expressions
void CheckStrictModeLValue(Expression* expression, void CheckStrictModeLValue(Expression* expression,
const char* error,
bool* ok); bool* ok);
// For harmony block scoping mode: Check if the scope has conflicting var/let // For harmony block scoping mode: Check if the scope has conflicting var/let
......
...@@ -296,16 +296,19 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { ...@@ -296,16 +296,19 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
Expect(Token::FUNCTION, CHECK_OK); Expect(Token::FUNCTION, CHECK_OK);
bool is_generator = allow_generators() && Check(Token::MUL); bool is_generator = allow_generators() && Check(Token::MUL);
Identifier identifier = ParseIdentifier(CHECK_OK); Identifier identifier = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
Scanner::Location location = scanner()->location(); Scanner::Location location = scanner()->location();
Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK); Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK);
// If we're in strict mode, ParseIdentifier will catch using eval, arguments
// or a strict reserved word as function name. However, if only the function
// is strict, we need to do an extra check.
if (function_value.IsStrictFunction() && if (function_value.IsStrictFunction() &&
!identifier.IsValidStrictVariable()) { !identifier.IsValidStrictVariable()) {
// Strict mode violation, using either reserved word or eval/arguments // Strict mode violation, using either reserved word or eval/arguments
// as name of strict function. // as name of strict function.
const char* type = "strict_function_name"; const char* type = "strict_eval_arguments";
if (identifier.IsFutureStrictReserved() || identifier.IsYield()) { if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
type = "unexpected_strict_reserved"; type = "unexpected_strict_reserved";
} }
...@@ -446,14 +449,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -446,14 +449,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
do { do {
// Parse variable name. // Parse variable name.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
Identifier identifier = ParseIdentifier(CHECK_OK); ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
if (!is_classic_mode() && !identifier.IsValidStrictVariable()) {
StrictModeIdentifierViolation(scanner()->location(),
"strict_var_name",
identifier,
ok);
return Statement::Default();
}
nvars++; nvars++;
if (peek() == Token::ASSIGN || require_initializer) { if (peek() == Token::ASSIGN || require_initializer) {
Expect(Token::ASSIGN, CHECK_OK); Expect(Token::ASSIGN, CHECK_OK);
...@@ -519,7 +515,8 @@ PreParser::Statement PreParser::ParseContinueStatement(bool* ok) { ...@@ -519,7 +515,8 @@ PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
tok != Token::SEMICOLON && tok != Token::SEMICOLON &&
tok != Token::RBRACE && tok != Token::RBRACE &&
tok != Token::EOS) { tok != Token::EOS) {
ParseIdentifier(CHECK_OK); // ECMA allows "eval" or "arguments" as labels even in strict mode.
ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return Statement::Default(); return Statement::Default();
...@@ -536,7 +533,8 @@ PreParser::Statement PreParser::ParseBreakStatement(bool* ok) { ...@@ -536,7 +533,8 @@ PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
tok != Token::SEMICOLON && tok != Token::SEMICOLON &&
tok != Token::RBRACE && tok != Token::RBRACE &&
tok != Token::EOS) { tok != Token::EOS) {
ParseIdentifier(CHECK_OK); // ECMA allows "eval" or "arguments" as labels even in strict mode.
ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return Statement::Default(); return Statement::Default();
...@@ -753,14 +751,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) { ...@@ -753,14 +751,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
if (peek() == Token::CATCH) { if (peek() == Token::CATCH) {
Consume(Token::CATCH); Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
Identifier id = ParseIdentifier(CHECK_OK); ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
if (!is_classic_mode() && !id.IsValidStrictVariable()) {
StrictModeIdentifierViolation(scanner()->location(),
"strict_catch_variable",
id,
ok);
return Statement::Default();
}
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
{ Scope::InsideWith iw(scope_); { Scope::InsideWith iw(scope_);
ParseBlock(CHECK_OK); ParseBlock(CHECK_OK);
...@@ -841,7 +832,7 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN, ...@@ -841,7 +832,7 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
expression.AsIdentifier().IsEvalOrArguments()) { expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location(); Scanner::Location after = scanner()->location();
ReportMessageAt(before.beg_pos, after.end_pos, ReportMessageAt(before.beg_pos, after.end_pos,
"strict_lhs_assignment", NULL); "strict_eval_arguments", NULL);
*ok = false; *ok = false;
return Expression::Default(); return Expression::Default();
} }
...@@ -935,7 +926,7 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) { ...@@ -935,7 +926,7 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
expression.AsIdentifier().IsEvalOrArguments()) { expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location(); Scanner::Location after = scanner()->location();
ReportMessageAt(before.beg_pos, after.end_pos, ReportMessageAt(before.beg_pos, after.end_pos,
"strict_lhs_prefix", NULL); "strict_eval_arguments", NULL);
*ok = false; *ok = false;
} }
return Expression::Default(); return Expression::Default();
...@@ -958,7 +949,7 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) { ...@@ -958,7 +949,7 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
expression.AsIdentifier().IsEvalOrArguments()) { expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location(); Scanner::Location after = scanner()->location();
ReportMessageAt(before.beg_pos, after.end_pos, ReportMessageAt(before.beg_pos, after.end_pos,
"strict_lhs_postfix", NULL); "strict_eval_arguments", NULL);
*ok = false; *ok = false;
return Expression::Default(); return Expression::Default();
} }
...@@ -1059,12 +1050,15 @@ PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression( ...@@ -1059,12 +1050,15 @@ PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
bool is_generator = allow_generators() && Check(Token::MUL); bool is_generator = allow_generators() && Check(Token::MUL);
Identifier identifier = Identifier::Default(); Identifier identifier = Identifier::Default();
if (peek_any_identifier()) { if (peek_any_identifier()) {
identifier = ParseIdentifier(CHECK_OK); identifier = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
} }
result = ParseFunctionLiteral(is_generator, CHECK_OK); result = ParseFunctionLiteral(is_generator, CHECK_OK);
// If we're in strict mode, ParseIdentifier will catch using eval, arguments
// or a strict reserved word as function name. However, if only the function
// is strict, we need to do an extra check.
if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) { if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
StrictModeIdentifierViolation(scanner()->location(), StrictModeIdentifierViolation(scanner()->location(),
"strict_function_name", "strict_eval_arguments",
identifier, identifier,
ok); ok);
return Expression::Default(); return Expression::Default();
...@@ -1137,7 +1131,8 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) { ...@@ -1137,7 +1131,8 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
case Token::FUTURE_STRICT_RESERVED_WORD: case Token::FUTURE_STRICT_RESERVED_WORD:
case Token::YIELD: case Token::YIELD:
case Token::IDENTIFIER: { case Token::IDENTIFIER: {
Identifier id = ParseIdentifier(CHECK_OK); // Using eval or arguments in this context is OK even in strict mode.
Identifier id = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
result = Expression::FromIdentifier(id); result = Expression::FromIdentifier(id);
break; break;
} }
...@@ -1354,13 +1349,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator, ...@@ -1354,13 +1349,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
bool done = (peek() == Token::RPAREN); bool done = (peek() == Token::RPAREN);
DuplicateFinder duplicate_finder(scanner()->unicode_cache()); DuplicateFinder duplicate_finder(scanner()->unicode_cache());
while (!done) { while (!done) {
Identifier id = ParseIdentifier(CHECK_OK); ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
if (!id.IsValidStrictVariable()) {
StrictModeIdentifierViolation(scanner()->location(),
"strict_param_name",
id,
CHECK_OK);
}
int prev_value; int prev_value;
if (scanner()->is_literal_ascii()) { if (scanner()->is_literal_ascii()) {
prev_value = prev_value =
...@@ -1434,7 +1423,8 @@ PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { ...@@ -1434,7 +1423,8 @@ PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
*ok = false; *ok = false;
return Expression::Default(); return Expression::Default();
} }
ParseIdentifier(CHECK_OK); // Allow "eval" or "arguments" for backward compatibility.
ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
ParseArguments(ok); ParseArguments(ok);
return Expression::Default(); return Expression::Default();
...@@ -1493,12 +1483,26 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() { ...@@ -1493,12 +1483,26 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() {
} }
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) { // Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope. If
// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
// "arguments" as identifier even in strict mode (this is needed in cases like
// "var foo = eval;").
PreParser::Identifier PreParser::ParseIdentifier(
AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
bool* ok) {
Token::Value next = Next(); Token::Value next = Next();
if (next == Token::IDENTIFIER || if (next == Token::IDENTIFIER) {
(is_classic_mode() && PreParser::Identifier name = GetIdentifierSymbol();
(next == Token::FUTURE_STRICT_RESERVED_WORD || if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
(next == Token::YIELD && !scope_->is_generator())))) { !is_classic_mode() && name.IsEvalOrArguments()) {
StrictModeIdentifierViolation(
scanner()->location(), "strict_eval_arguments", name, ok);
}
return name;
} else if (is_classic_mode() &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
(next == Token::YIELD && !scope_->is_generator()))) {
return GetIdentifierSymbol(); return GetIdentifierSymbol();
} else { } else {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
......
...@@ -76,6 +76,11 @@ class ParserBase { ...@@ -76,6 +76,11 @@ class ParserBase {
} }
protected: protected:
enum AllowEvalOrArgumentsAsIdentifier {
kAllowEvalOrArguments,
kDontAllowEvalOrArguments
};
Scanner* scanner() const { return scanner_; } Scanner* scanner() const { return scanner_; }
int position() { return scanner_->location().beg_pos; } int position() { return scanner_->location().beg_pos; }
int peek_position() { return scanner_->peek_location().beg_pos; } int peek_position() { return scanner_->peek_location().beg_pos; }
...@@ -640,7 +645,7 @@ class PreParser : public ParserBase { ...@@ -640,7 +645,7 @@ class PreParser : public ParserBase {
Expression ParseFunctionLiteral(bool is_generator, bool* ok); Expression ParseFunctionLiteral(bool is_generator, bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok); void ParseLazyFunctionLiteralBody(bool* ok);
Identifier ParseIdentifier(bool* ok); Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
Identifier ParseIdentifierName(bool* ok); Identifier ParseIdentifierName(bool* ok);
Identifier ParseIdentifierNameOrGetOrSet(bool* is_get, Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
bool* is_set, bool* is_set,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment