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

Move ParseUnaryExpression into ParserBase and add tests.

This also makes PreParser produce the strict_delete error the same way as
Parser (see test).

R=rossberg@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20079 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c04dd3fb
...@@ -433,6 +433,12 @@ bool ParserTraits::IsThisProperty(Expression* expression) { ...@@ -433,6 +433,12 @@ bool ParserTraits::IsThisProperty(Expression* expression) {
} }
bool ParserTraits::IsIdentifier(Expression* expression) {
VariableProxy* operand = expression->AsVariableProxy();
return operand != NULL && !operand->is_this();
}
void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left, void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
Expression* right) { Expression* right) {
ASSERT(left != NULL); ASSERT(left != NULL);
...@@ -525,6 +531,52 @@ bool ParserTraits::ShortcutNumericLiteralBinaryExpression( ...@@ -525,6 +531,52 @@ bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
} }
Expression* ParserTraits::BuildUnaryExpression(
Expression* expression, Token::Value op, int pos,
AstNodeFactory<AstConstructionVisitor>* factory) {
ASSERT(expression != NULL);
if (expression->AsLiteral() != NULL) {
Handle<Object> literal = expression->AsLiteral()->value();
if (op == Token::NOT) {
// Convert the literal to a boolean condition and negate it.
bool condition = literal->BooleanValue();
Handle<Object> result =
parser_->isolate()->factory()->ToBoolean(!condition);
return factory->NewLiteral(result, pos);
} else if (literal->IsNumber()) {
// Compute some expressions involving only number literals.
double value = literal->Number();
switch (op) {
case Token::ADD:
return expression;
case Token::SUB:
return factory->NewNumberLiteral(-value, pos);
case Token::BIT_NOT:
return factory->NewNumberLiteral(~DoubleToInt32(value), pos);
default:
break;
}
}
}
// Desugar '+foo' => 'foo*1'
if (op == Token::ADD) {
return factory->NewBinaryOperation(
Token::MUL, expression, factory->NewNumberLiteral(1, pos), pos);
}
// The same idea for '-foo' => 'foo*(-1)'.
if (op == Token::SUB) {
return factory->NewBinaryOperation(
Token::MUL, expression, factory->NewNumberLiteral(-1, pos), pos);
}
// ...and one more time for '~foo' => 'foo^(~0)'.
if (op == Token::BIT_NOT) {
return factory->NewBinaryOperation(
Token::BIT_XOR, expression, factory->NewNumberLiteral(~0, pos), pos);
}
return factory->NewUnaryOperation(op, expression, pos);
}
void ParserTraits::ReportMessageAt(Scanner::Location source_location, void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
Vector<const char*> args, Vector<const char*> args,
...@@ -688,8 +740,8 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( ...@@ -688,8 +740,8 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
} }
Expression* ParserTraits::ParseUnaryExpression(bool* ok) { Expression* ParserTraits::ParsePostfixExpression(bool* ok) {
return parser_->ParseUnaryExpression(ok); return parser_->ParsePostfixExpression(ok);
} }
...@@ -2990,111 +3042,6 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2990,111 +3042,6 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
} }
Expression* Parser::ParseUnaryExpression(bool* ok) {
// UnaryExpression ::
// PostfixExpression
// 'delete' UnaryExpression
// 'void' UnaryExpression
// 'typeof' UnaryExpression
// '++' UnaryExpression
// '--' UnaryExpression
// '+' UnaryExpression
// '-' UnaryExpression
// '~' UnaryExpression
// '!' UnaryExpression
Token::Value op = peek();
if (Token::IsUnaryOp(op)) {
op = Next();
int pos = position();
Expression* expression = ParseUnaryExpression(CHECK_OK);
if (expression != NULL && (expression->AsLiteral() != NULL)) {
Handle<Object> literal = expression->AsLiteral()->value();
if (op == Token::NOT) {
// Convert the literal to a boolean condition and negate it.
bool condition = literal->BooleanValue();
Handle<Object> result = isolate()->factory()->ToBoolean(!condition);
return factory()->NewLiteral(result, pos);
} else if (literal->IsNumber()) {
// Compute some expressions involving only number literals.
double value = literal->Number();
switch (op) {
case Token::ADD:
return expression;
case Token::SUB:
return factory()->NewNumberLiteral(-value, pos);
case Token::BIT_NOT:
return factory()->NewNumberLiteral(~DoubleToInt32(value), pos);
default:
break;
}
}
}
// "delete identifier" is a syntax error in strict mode.
if (op == Token::DELETE && strict_mode() == STRICT) {
VariableProxy* operand = expression->AsVariableProxy();
if (operand != NULL && !operand->is_this()) {
ReportMessage("strict_delete", Vector<const char*>::empty());
*ok = false;
return NULL;
}
}
// Desugar '+foo' into 'foo*1', this enables the collection of type feedback
// without any special stub and the multiplication is removed later in
// Crankshaft's canonicalization pass.
if (op == Token::ADD) {
return factory()->NewBinaryOperation(Token::MUL,
expression,
factory()->NewNumberLiteral(1, pos),
pos);
}
// The same idea for '-foo' => 'foo*(-1)'.
if (op == Token::SUB) {
return factory()->NewBinaryOperation(Token::MUL,
expression,
factory()->NewNumberLiteral(-1, pos),
pos);
}
// ...and one more time for '~foo' => 'foo^(~0)'.
if (op == Token::BIT_NOT) {
return factory()->NewBinaryOperation(Token::BIT_XOR,
expression,
factory()->NewNumberLiteral(~0, pos),
pos);
}
return factory()->NewUnaryOperation(op, expression, pos);
} else if (Token::IsCountOp(op)) {
op = Next();
Scanner::Location lhs_location = scanner()->peek_location();
Expression* expression = ParseUnaryExpression(CHECK_OK);
if (expression == NULL || !expression->IsValidLeftHandSide()) {
ReportMessageAt(lhs_location, "invalid_lhs_in_prefix_op", true);
*ok = false;
return NULL;
}
if (strict_mode() == STRICT) {
// Prefix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, CHECK_OK);
}
MarkExpressionAsLValue(expression);
return factory()->NewCountOperation(op,
true /* prefix */,
expression,
position());
} else {
return ParsePostfixExpression(ok);
}
}
Expression* Parser::ParsePostfixExpression(bool* ok) { Expression* Parser::ParsePostfixExpression(bool* ok) {
// PostfixExpression :: // PostfixExpression ::
// LeftHandSideExpression ('++' | '--')? // LeftHandSideExpression ('++' | '--')?
......
...@@ -460,6 +460,8 @@ class ParserTraits { ...@@ -460,6 +460,8 @@ class ParserTraits {
// Returns true if the expression is of type "this.foo". // Returns true if the expression is of type "this.foo".
static bool IsThisProperty(Expression* expression); static bool IsThisProperty(Expression* expression);
static bool IsIdentifier(Expression* expression);
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) { static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property); return ObjectLiteral::IsBoilerplateProperty(property);
} }
...@@ -509,6 +511,21 @@ class ParserTraits { ...@@ -509,6 +511,21 @@ class ParserTraits {
Expression** x, Expression* y, Token::Value op, int pos, Expression** x, Expression* y, Token::Value op, int pos,
AstNodeFactory<AstConstructionVisitor>* factory); AstNodeFactory<AstConstructionVisitor>* factory);
// Rewrites the following types of unary expressions:
// not <literal> -> true / false
// + <numeric literal> -> <numeric literal>
// - <numeric literal> -> <numeric literal with value negated>
// ! <literal> -> true / false
// The following rewriting rules enable the collection of type feedback
// without any special stub and the multiplication is removed later in
// Crankshaft's canonicalization pass.
// + foo -> foo * 1
// - foo -> foo * (-1)
// ~ foo -> foo ^(~0)
Expression* BuildUnaryExpression(
Expression* expression, Token::Value op, int pos,
AstNodeFactory<AstConstructionVisitor>* factory);
// Reporting errors. // Reporting errors.
void ReportMessageAt(Scanner::Location source_location, void ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
...@@ -572,7 +589,7 @@ class ParserTraits { ...@@ -572,7 +589,7 @@ class ParserTraits {
int function_token_position, int function_token_position,
FunctionLiteral::FunctionType type, FunctionLiteral::FunctionType type,
bool* ok); bool* ok);
Expression* ParseUnaryExpression(bool* ok); Expression* ParsePostfixExpression(bool* ok);
private: private:
Parser* parser_; Parser* parser_;
......
...@@ -146,8 +146,8 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral( ...@@ -146,8 +146,8 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
} }
PreParserExpression PreParserTraits::ParseUnaryExpression(bool* ok) { PreParserExpression PreParserTraits::ParsePostfixExpression(bool* ok) {
return pre_parser_->ParseUnaryExpression(ok); return pre_parser_->ParsePostfixExpression(ok);
} }
...@@ -842,37 +842,6 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) { ...@@ -842,37 +842,6 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
#undef DUMMY #undef DUMMY
PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
// UnaryExpression ::
// PostfixExpression
// 'delete' UnaryExpression
// 'void' UnaryExpression
// 'typeof' UnaryExpression
// '++' UnaryExpression
// '--' UnaryExpression
// '+' UnaryExpression
// '-' UnaryExpression
// '~' UnaryExpression
// '!' UnaryExpression
Token::Value op = peek();
if (Token::IsUnaryOp(op)) {
op = Next();
ParseUnaryExpression(ok);
return Expression::Default();
} else if (Token::IsCountOp(op)) {
op = Next();
Expression expression = ParseUnaryExpression(CHECK_OK);
if (strict_mode() == STRICT) {
CheckStrictModeLValue(expression, CHECK_OK);
}
return Expression::Default();
} else {
return ParsePostfixExpression(ok);
}
}
PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) { PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
// PostfixExpression :: // PostfixExpression ::
// LeftHandSideExpression ('++' | '--')? // LeftHandSideExpression ('++' | '--')?
......
...@@ -394,6 +394,7 @@ class ParserBase : public Traits { ...@@ -394,6 +394,7 @@ class ParserBase : public Traits {
ExpressionT ParseYieldExpression(bool* ok); ExpressionT ParseYieldExpression(bool* ok);
ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok);
ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
ExpressionT ParseUnaryExpression(bool* ok);
// Used to detect duplicates in object literals. Each of the values // Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents // kGetterProperty, kSetterProperty and kValueProperty represents
...@@ -742,6 +743,13 @@ class PreParserFactory { ...@@ -742,6 +743,13 @@ class PreParserFactory {
int pos) { int pos) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewCountOperation(Token::Value op,
bool is_prefix,
PreParserExpression expression,
int pos) {
return PreParserExpression::Default();
}
}; };
...@@ -794,6 +802,10 @@ class PreParserTraits { ...@@ -794,6 +802,10 @@ class PreParserTraits {
return expression.IsThisProperty(); return expression.IsThisProperty();
} }
static bool IsIdentifier(PreParserExpression expression) {
return expression.IsIdentifier();
}
static bool IsBoilerplateProperty(PreParserExpression property) { static bool IsBoilerplateProperty(PreParserExpression property) {
// PreParser doesn't count boilerplate properties. // PreParser doesn't count boilerplate properties.
return false; return false;
...@@ -841,6 +853,12 @@ class PreParserTraits { ...@@ -841,6 +853,12 @@ class PreParserTraits {
return false; return false;
} }
PreParserExpression BuildUnaryExpression(PreParserExpression expression,
Token::Value op, int pos,
PreParserFactory* factory) {
return PreParserExpression::Default();
}
// Reporting errors. // Reporting errors.
void ReportMessageAt(Scanner::Location location, void ReportMessageAt(Scanner::Location location,
const char* message, const char* message,
...@@ -922,7 +940,7 @@ class PreParserTraits { ...@@ -922,7 +940,7 @@ class PreParserTraits {
int function_token_position, int function_token_position,
FunctionLiteral::FunctionType type, FunctionLiteral::FunctionType type,
bool* ok); bool* ok);
PreParserExpression ParseUnaryExpression(bool* ok); PreParserExpression ParsePostfixExpression(bool* ok);
private: private:
PreParser* pre_parser_; PreParser* pre_parser_;
...@@ -1086,7 +1104,6 @@ class PreParser : public ParserBase<PreParserTraits> { ...@@ -1086,7 +1104,6 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseTryStatement(bool* ok); Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok); Statement ParseDebuggerStatement(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok); Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseUnaryExpression(bool* ok);
Expression ParsePostfixExpression(bool* ok); Expression ParsePostfixExpression(bool* ok);
Expression ParseLeftHandSideExpression(bool* ok); Expression ParseLeftHandSideExpression(bool* ok);
Expression ParseMemberExpression(bool* ok); Expression ParseMemberExpression(bool* ok);
...@@ -1778,6 +1795,64 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { ...@@ -1778,6 +1795,64 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
} }
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseUnaryExpression(bool* ok) {
// UnaryExpression ::
// PostfixExpression
// 'delete' UnaryExpression
// 'void' UnaryExpression
// 'typeof' UnaryExpression
// '++' UnaryExpression
// '--' UnaryExpression
// '+' UnaryExpression
// '-' UnaryExpression
// '~' UnaryExpression
// '!' UnaryExpression
Token::Value op = peek();
if (Token::IsUnaryOp(op)) {
op = Next();
int pos = position();
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
// "delete identifier" is a syntax error in strict mode.
if (op == Token::DELETE && strict_mode() == STRICT &&
this->IsIdentifier(expression)) {
ReportMessage("strict_delete", Vector<const char*>::empty());
*ok = false;
return this->EmptyExpression();
}
// Allow Traits do rewrite the expression.
return this->BuildUnaryExpression(expression, op, pos, factory());
} else if (Token::IsCountOp(op)) {
op = Next();
Scanner::Location lhs_location = scanner()->peek_location();
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
if (!this->IsValidLeftHandSide(expression)) {
ReportMessageAt(lhs_location, "invalid_lhs_in_prefix_op", true);
*ok = false;
return this->EmptyExpression();
}
if (strict_mode() == STRICT) {
// Prefix expression operand in strict mode may not be eval or arguments.
this->CheckStrictModeLValue(expression, CHECK_OK);
}
this->MarkExpressionAsLValue(expression);
return factory()->NewCountOperation(op,
true /* prefix */,
expression,
position());
} else {
return this->ParsePostfixExpression(ok);
}
}
#undef CHECK_OK #undef CHECK_OK
#undef CHECK_OK_CUSTOM #undef CHECK_OK_CUSTOM
......
...@@ -2472,3 +2472,57 @@ TEST(TooManyArguments) { ...@@ -2472,3 +2472,57 @@ TEST(TooManyArguments) {
static const ParserFlag empty_flags[] = {kAllowLazy}; static const ParserFlag empty_flags[] = {kAllowLazy};
RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1); RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
} }
TEST(StrictDelete) {
// "delete <Identifier>" is not allowed in strict mode.
const char* strict_context_data[][2] = {
{"\"use strict\"; ", ""},
{ NULL, NULL }
};
const char* sloppy_context_data[][2] = {
{"", ""},
{ NULL, NULL }
};
// These are errors in the strict mode.
const char* sloppy_statement_data[] = {
"delete foo;",
"delete foo + 1;",
"delete (foo);",
"delete eval;",
"delete interface;",
NULL
};
// These are always OK
const char* good_statement_data[] = {
"delete this;",
"delete 1;",
"delete 1 + 2;",
"delete foo();",
"delete foo.bar;",
"delete foo[bar];",
"delete foo--;",
"delete --foo;",
"delete new foo();",
"delete new foo(bar);",
NULL
};
// These are always errors
const char* bad_statement_data[] = {
"delete if;",
NULL
};
RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
RunParserSyncTest(strict_context_data, bad_statement_data, kError);
RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
}
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