From: marja@chromium.org Date: Wed, 19 Mar 2014 14:08:47 +0000 (+0000) Subject: Move ParseUnaryExpression into ParserBase and add tests. X-Git-Tag: upstream/4.7.83~10163 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e9717833f9d4f4731784b5908242f966f4eb40ad;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/parser.cc b/src/parser.cc index 01bd853..0d1ba00 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -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, Expression* right) { ASSERT(left != NULL); @@ -525,6 +531,52 @@ bool ParserTraits::ShortcutNumericLiteralBinaryExpression( } +Expression* ParserTraits::BuildUnaryExpression( + Expression* expression, Token::Value op, int pos, + AstNodeFactory* factory) { + ASSERT(expression != NULL); + if (expression->AsLiteral() != NULL) { + Handle literal = expression->AsLiteral()->value(); + if (op == Token::NOT) { + // Convert the literal to a boolean condition and negate it. + bool condition = literal->BooleanValue(); + Handle 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, const char* message, Vector args, @@ -688,8 +740,8 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( } -Expression* ParserTraits::ParseUnaryExpression(bool* ok) { - return parser_->ParseUnaryExpression(ok); +Expression* ParserTraits::ParsePostfixExpression(bool* ok) { + return parser_->ParsePostfixExpression(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 literal = expression->AsLiteral()->value(); - if (op == Token::NOT) { - // Convert the literal to a boolean condition and negate it. - bool condition = literal->BooleanValue(); - Handle 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::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) { // PostfixExpression :: // LeftHandSideExpression ('++' | '--')? diff --git a/src/parser.h b/src/parser.h index 072658e..3d2f032 100644 --- a/src/parser.h +++ b/src/parser.h @@ -460,6 +460,8 @@ class ParserTraits { // Returns true if the expression is of type "this.foo". static bool IsThisProperty(Expression* expression); + static bool IsIdentifier(Expression* expression); + static bool IsBoilerplateProperty(ObjectLiteral::Property* property) { return ObjectLiteral::IsBoilerplateProperty(property); } @@ -509,6 +511,21 @@ class ParserTraits { Expression** x, Expression* y, Token::Value op, int pos, AstNodeFactory* factory); + // Rewrites the following types of unary expressions: + // not -> true / false + // + -> + // - -> + // ! -> 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* factory); + // Reporting errors. void ReportMessageAt(Scanner::Location source_location, const char* message, @@ -572,7 +589,7 @@ class ParserTraits { int function_token_position, FunctionLiteral::FunctionType type, bool* ok); - Expression* ParseUnaryExpression(bool* ok); + Expression* ParsePostfixExpression(bool* ok); private: Parser* parser_; diff --git a/src/preparser.cc b/src/preparser.cc index 8a621b4..398f327 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -146,8 +146,8 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral( } -PreParserExpression PreParserTraits::ParseUnaryExpression(bool* ok) { - return pre_parser_->ParseUnaryExpression(ok); +PreParserExpression PreParserTraits::ParsePostfixExpression(bool* ok) { + return pre_parser_->ParsePostfixExpression(ok); } @@ -842,37 +842,6 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) { #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) { // PostfixExpression :: // LeftHandSideExpression ('++' | '--')? diff --git a/src/preparser.h b/src/preparser.h index a060c03..05ff972 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -394,6 +394,7 @@ class ParserBase : public Traits { ExpressionT ParseYieldExpression(bool* ok); ExpressionT ParseConditionalExpression(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 // kGetterProperty, kSetterProperty and kValueProperty represents @@ -742,6 +743,13 @@ class PreParserFactory { int pos) { return PreParserExpression::Default(); } + + PreParserExpression NewCountOperation(Token::Value op, + bool is_prefix, + PreParserExpression expression, + int pos) { + return PreParserExpression::Default(); + } }; @@ -794,6 +802,10 @@ class PreParserTraits { return expression.IsThisProperty(); } + static bool IsIdentifier(PreParserExpression expression) { + return expression.IsIdentifier(); + } + static bool IsBoilerplateProperty(PreParserExpression property) { // PreParser doesn't count boilerplate properties. return false; @@ -841,6 +853,12 @@ class PreParserTraits { return false; } + PreParserExpression BuildUnaryExpression(PreParserExpression expression, + Token::Value op, int pos, + PreParserFactory* factory) { + return PreParserExpression::Default(); + } + // Reporting errors. void ReportMessageAt(Scanner::Location location, const char* message, @@ -922,7 +940,7 @@ class PreParserTraits { int function_token_position, FunctionLiteral::FunctionType type, bool* ok); - PreParserExpression ParseUnaryExpression(bool* ok); + PreParserExpression ParsePostfixExpression(bool* ok); private: PreParser* pre_parser_; @@ -1086,7 +1104,6 @@ class PreParser : public ParserBase { Statement ParseTryStatement(bool* ok); Statement ParseDebuggerStatement(bool* ok); Expression ParseConditionalExpression(bool accept_IN, bool* ok); - Expression ParseUnaryExpression(bool* ok); Expression ParsePostfixExpression(bool* ok); Expression ParseLeftHandSideExpression(bool* ok); Expression ParseMemberExpression(bool* ok); @@ -1778,6 +1795,64 @@ ParserBase::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { } +template +typename ParserBase::ExpressionT +ParserBase::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::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_CUSTOM diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 5a2ee13..c88b2dc 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -2472,3 +2472,57 @@ TEST(TooManyArguments) { static const ParserFlag empty_flags[] = {kAllowLazy}; RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1); } + + +TEST(StrictDelete) { + // "delete " 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); +}