Move ParseUnaryExpression into ParserBase and add tests.
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Mar 2014 14:08:47 +0000 (14:08 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 19 Mar 2014 14:08:47 +0000 (14:08 +0000)
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

src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/cctest/test-parsing.cc

index 01bd853..0d1ba00 100644 (file)
@@ -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<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,
                                    const char* message,
                                    Vector<const char*> 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<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) {
   // PostfixExpression ::
   //   LeftHandSideExpression ('++' | '--')?
index 072658e..3d2f032 100644 (file)
@@ -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<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.
   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_;
index 8a621b4..398f327 100644 (file)
@@ -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 ('++' | '--')?
index a060c03..05ff972 100644 (file)
@@ -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<PreParserTraits> {
   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<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_CUSTOM
 
index 5a2ee13..c88b2dc 100644 (file)
@@ -2472,3 +2472,57 @@ TEST(TooManyArguments) {
   static const ParserFlag empty_flags[] = {kAllowLazy};
   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);
+}