Revision: 20079
Author:   [email protected]
Date:     Wed Mar 19 14:08:47 2014 UTC
Log:      Move ParseUnaryExpression into ParserBase and add tests.

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

[email protected]
BUG=

Review URL: https://codereview.chromium.org/203193004
http://code.google.com/p/v8/source/detail?r=20079

Modified:
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/parser.h
 /branches/bleeding_edge/src/preparser.cc
 /branches/bleeding_edge/src/preparser.h
 /branches/bleeding_edge/test/cctest/test-parsing.cc

=======================================
--- /branches/bleeding_edge/src/parser.cc       Wed Mar 19 13:58:15 2014 UTC
+++ /branches/bleeding_edge/src/parser.cc       Wed Mar 19 14:08:47 2014 UTC
@@ -431,6 +431,12 @@
       property->obj()->AsVariableProxy() != NULL &&
       property->obj()->AsVariableProxy()->is_this();
 }
+
+
+bool ParserTraits::IsIdentifier(Expression* expression) {
+  VariableProxy* operand = expression->AsVariableProxy();
+  return operand != NULL && !operand->is_this();
+}


void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
@@ -523,6 +529,52 @@
   }
   return false;
 }
+
+
+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,
@@ -688,8 +740,8 @@
 }


-Expression* ParserTraits::ParseUnaryExpression(bool* ok) {
-  return parser_->ParseUnaryExpression(ok);
+Expression* ParserTraits::ParsePostfixExpression(bool* ok) {
+  return parser_->ParsePostfixExpression(ok);
 }


@@ -2988,111 +3040,6 @@
     return loop;
   }
 }
-
-
-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) {
=======================================
--- /branches/bleeding_edge/src/parser.h        Wed Mar 19 13:58:15 2014 UTC
+++ /branches/bleeding_edge/src/parser.h        Wed Mar 19 14:08:47 2014 UTC
@@ -460,6 +460,8 @@
   // 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 @@
       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 @@
       int function_token_position,
       FunctionLiteral::FunctionType type,
       bool* ok);
-  Expression* ParseUnaryExpression(bool* ok);
+  Expression* ParsePostfixExpression(bool* ok);

  private:
   Parser* parser_;
=======================================
--- /branches/bleeding_edge/src/preparser.cc    Wed Mar 19 13:58:15 2014 UTC
+++ /branches/bleeding_edge/src/preparser.cc    Wed Mar 19 14:08:47 2014 UTC
@@ -146,8 +146,8 @@
 }


-PreParserExpression PreParserTraits::ParseUnaryExpression(bool* ok) {
-  return pre_parser_->ParseUnaryExpression(ok);
+PreParserExpression PreParserTraits::ParsePostfixExpression(bool* ok) {
+  return pre_parser_->ParsePostfixExpression(ok);
 }


@@ -842,37 +842,6 @@
 #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 ('++' | '--')?
=======================================
--- /branches/bleeding_edge/src/preparser.h     Wed Mar 19 13:58:15 2014 UTC
+++ /branches/bleeding_edge/src/preparser.h     Wed Mar 19 14:08:47 2014 UTC
@@ -394,6 +394,7 @@
   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 @@
                                      int pos) {
     return PreParserExpression::Default();
   }
+
+  PreParserExpression NewCountOperation(Token::Value op,
+                                        bool is_prefix,
+                                        PreParserExpression expression,
+                                        int pos) {
+    return PreParserExpression::Default();
+  }
 };


@@ -793,6 +801,10 @@
   static bool IsThisProperty(PreParserExpression expression) {
     return expression.IsThisProperty();
   }
+
+  static bool IsIdentifier(PreParserExpression expression) {
+    return expression.IsIdentifier();
+  }

   static bool IsBoilerplateProperty(PreParserExpression property) {
     // PreParser doesn't count boilerplate properties.
@@ -840,6 +852,12 @@
                                               PreParserFactory* factory) {
     return false;
   }
+
+  PreParserExpression BuildUnaryExpression(PreParserExpression expression,
+                                           Token::Value op, int pos,
+                                           PreParserFactory* factory) {
+    return PreParserExpression::Default();
+  }

   // Reporting errors.
   void ReportMessageAt(Scanner::Location location,
@@ -922,7 +940,7 @@
       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 @@
   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);
@@ -1776,6 +1793,64 @@
   }
   return x;
 }
+
+
+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
=======================================
--- /branches/bleeding_edge/test/cctest/test-parsing.cc Wed Mar 19 13:58:15 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-parsing.cc Wed Mar 19 14:08:47 2014 UTC
@@ -2472,3 +2472,57 @@
   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);
+}

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to