Revision: 2994
Author: [email protected]
Date: Wed Sep 30 02:49:36 2009
Log: Two changes, one a refactoring and one that affects V8's JS semantics.

1. Change the AST node type CallNew to be a subclass of Expression
    rather than Call.  It's not really a call but it just happens to
    have the same fields.

2. Change our error reporting for invalid left-hand sides in for-in
    statements, pre- and postfix count expressions, and assignments.
    Before we signaled a syntax error at compile time *unless* the LHS
    was a function call or 'new' expression, in which case we signaled
    a reference error at runtime.  Now we signal a reference error at
    runtime in all cases.  This matches the JSC behavior in Safari 4.

Review URL: http://codereview.chromium.org/249039
http://code.google.com/p/v8/source/detail?r=2994

Modified:
  /branches/bleeding_edge/src/ast.h
  /branches/bleeding_edge/src/parser.cc
  /branches/bleeding_edge/src/usage-analyzer.cc
  /branches/bleeding_edge/test/mjsunit/invalid-lhs.js

=======================================
--- /branches/bleeding_edge/src/ast.h   Tue Sep 29 06:28:30 2009
+++ /branches/bleeding_edge/src/ast.h   Wed Sep 30 02:49:36 2009
@@ -954,12 +954,8 @@

  class Call: public Expression {
   public:
-  Call(Expression* expression,
-       ZoneList<Expression*>* arguments,
-       int pos)
-      : expression_(expression),
-        arguments_(arguments),
-        pos_(pos) { }
+  Call(Expression* expression, ZoneList<Expression*>* arguments, int pos)
+      : expression_(expression), arguments_(arguments), pos_(pos) { }

    virtual void Accept(AstVisitor* v);

@@ -981,12 +977,21 @@
  };


-class CallNew: public Call {
+class CallNew: public Expression {
   public:
    CallNew(Expression* expression, ZoneList<Expression*>* arguments, int  
pos)
-      : Call(expression, arguments, pos) { }
+      : expression_(expression), arguments_(arguments), pos_(pos) { }

    virtual void Accept(AstVisitor* v);
+
+  Expression* expression() const { return expression_; }
+  ZoneList<Expression*>* arguments() const { return arguments_; }
+  int position() { return pos_; }
+
+ private:
+  Expression* expression_;
+  ZoneList<Expression*>* arguments_;
+  int pos_;
  };


=======================================
--- /branches/bleeding_edge/src/parser.cc       Tue Sep 29 06:28:30 2009
+++ /branches/bleeding_edge/src/parser.cc       Wed Sep 30 02:49:36 2009
@@ -2660,25 +2660,13 @@
      } else {
        Expression* expression = ParseExpression(false, CHECK_OK);
        if (peek() == Token::IN) {
-        // Report syntax error if the expression is an invalid
-        // left-hand side expression.
+        // Signal a reference error if the expression is an invalid
+        // left-hand side expression.  We could report this as a syntax
+        // error here but for compatibility with JSC we choose to report
+        // the error at runtime.
          if (expression == NULL || !expression->IsValidLeftHandSide()) {
-          if (expression != NULL && expression->AsCall() != NULL) {
-            // According to ECMA-262 host function calls are permitted to
-            // return references.  This cannot happen in our system so we
-            // will always get an error.  We could report this as a syntax
-            // error here but for compatibility with KJS and SpiderMonkey  
we
-            // choose to report the error at runtime.
-            Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
-            expression = NewThrowReferenceError(type);
-          } else {
-            // Invalid left hand side expressions that are not function
-            // calls are reported as syntax errors at compile time.
-            ReportMessage("invalid_lhs_in_for_in",
-                          Vector<const char*>::empty());
-            *ok = false;
-            return NULL;
-          }
+          Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
+          expression = NewThrowReferenceError(type);
          }
          ForInStatement* loop = NEW(ForInStatement(labels));
          Target target(this, loop);
@@ -2755,29 +2743,14 @@
      return expression;
    }

+  // Signal a reference error if the expression is an invalid left-hand
+  // side expression.  We could report this as a syntax error here but
+  // for compatibility with JSC we choose to report the error at
+  // runtime.
    if (expression == NULL || !expression->IsValidLeftHandSide()) {
-    if (expression != NULL && expression->AsCall() != NULL) {
-      // According to ECMA-262 host function calls are permitted to
-      // return references.  This cannot happen in our system so we
-      // will always get an error.  We could report this as a syntax
-      // error here but for compatibility with KJS and SpiderMonkey we
-      // choose to report the error at runtime.
-      Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
-      expression = NewThrowReferenceError(type);
-    } else {
-      // Invalid left hand side expressions that are not function
-      // calls are reported as syntax errors at compile time.
-      //
-      // NOTE: KJS sometimes delay the error reporting to runtime. If
-      // we want to be completely compatible we should do the same.
-      // For example: "(x++) = 42" gives a reference error at runtime
-      // with KJS whereas we report a syntax error at compile time.
-      ReportMessage("invalid_lhs_in_assignment", Vector<const  
char*>::empty());
-      *ok = false;
-      return NULL;
-    }
-  }
-
+    Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
+    expression = NewThrowReferenceError(type);
+  }

    Token::Value op = Next();  // Get assignment operator.
    int pos = scanner().location().beg_pos;
@@ -2951,45 +2924,37 @@
    Token::Value op = peek();
    if (Token::IsUnaryOp(op)) {
      op = Next();
-    Expression* x = ParseUnaryExpression(CHECK_OK);
+    Expression* expression = ParseUnaryExpression(CHECK_OK);

      // Compute some expressions involving only number literals.
-    if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber()) {
-      double x_val = x->AsLiteral()->handle()->Number();
+    if (expression != NULL && expression->AsLiteral() &&
+        expression->AsLiteral()->handle()->IsNumber()) {
+      double value = expression->AsLiteral()->handle()->Number();
        switch (op) {
          case Token::ADD:
-          return x;
+          return expression;
          case Token::SUB:
-          return NewNumberLiteral(-x_val);
+          return NewNumberLiteral(-value);
          case Token::BIT_NOT:
-          return NewNumberLiteral(~DoubleToInt32(x_val));
+          return NewNumberLiteral(~DoubleToInt32(value));
          default: break;
        }
      }

-    return NEW(UnaryOperation(op, x));
+    return NEW(UnaryOperation(op, expression));

    } else if (Token::IsCountOp(op)) {
      op = Next();
-    Expression* x = ParseUnaryExpression(CHECK_OK);
-    if (x == NULL || !x->IsValidLeftHandSide()) {
-      if (x != NULL && x->AsCall() != NULL) {
-        // According to ECMA-262 host function calls are permitted to
-        // return references.  This cannot happen in our system so we
-        // will always get an error.  We could report this as a syntax
-        // error here but for compatibility with KJS and SpiderMonkey we
-        // choose to report the error at runtime.
-        Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
-        x = NewThrowReferenceError(type);
-      } else {
-        // Invalid left hand side expressions that are not function
-        // calls are reported as syntax errors at compile time.
-        ReportMessage("invalid_lhs_in_prefix_op", Vector<const  
char*>::empty());
-        *ok = false;
-        return NULL;
-      }
-    }
-    return NEW(CountOperation(true /* prefix */, op, x));
+    Expression* expression = ParseUnaryExpression(CHECK_OK);
+    // Signal a reference error if the expression is an invalid
+    // left-hand side expression.  We could report this as a syntax
+    // error here but for compatibility with JSC we choose to report the
+    // error at runtime.
+    if (expression == NULL || !expression->IsValidLeftHandSide()) {
+      Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
+      expression = NewThrowReferenceError(type);
+    }
+    return NEW(CountOperation(true /* prefix */, op, expression));

    } else {
      return ParsePostfixExpression(ok);
@@ -3001,30 +2966,20 @@
    // PostfixExpression ::
    //   LeftHandSideExpression ('++' | '--')?

-  Expression* result = ParseLeftHandSideExpression(CHECK_OK);
+  Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
    if (!scanner_.has_line_terminator_before_next() &&  
Token::IsCountOp(peek())) {
-    if (result == NULL || !result->IsValidLeftHandSide()) {
-      if (result != NULL && result->AsCall() != NULL) {
-        // According to ECMA-262 host function calls are permitted to
-        // return references.  This cannot happen in our system so we
-        // will always get an error.  We could report this as a syntax
-        // error here but for compatibility with KJS and SpiderMonkey we
-        // choose to report the error at runtime.
-        Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
-        result = NewThrowReferenceError(type);
-      } else {
-        // Invalid left hand side expressions that are not function
-        // calls are reported as syntax errors at compile time.
-        ReportMessage("invalid_lhs_in_postfix_op",
-                      Vector<const char*>::empty());
-        *ok = false;
-        return NULL;
-      }
+    // Signal a reference error if the expression is an invalid
+    // left-hand side expression.  We could report this as a syntax
+    // error here but for compatibility with JSC we choose to report the
+    // error at runtime.
+    if (expression == NULL || !expression->IsValidLeftHandSide()) {
+      Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
+      expression = NewThrowReferenceError(type);
      }
      Token::Value next = Next();
-    result = NEW(CountOperation(false /* postfix */, next, result));
-  }
-  return result;
+    expression = NEW(CountOperation(false /* postfix */, next,  
expression));
+  }
+  return expression;
  }


=======================================
--- /branches/bleeding_edge/src/usage-analyzer.cc       Tue Sep 29 06:28:30 2009
+++ /branches/bleeding_edge/src/usage-analyzer.cc       Wed Sep 30 02:49:36 2009
@@ -44,44 +44,12 @@
   public:
    static bool Traverse(AstNode* node);

-  void VisitBlock(Block* node);
-  void VisitDeclaration(Declaration* node);
-  void VisitExpressionStatement(ExpressionStatement* node);
-  void VisitEmptyStatement(EmptyStatement* node);
-  void VisitIfStatement(IfStatement* node);
-  void VisitContinueStatement(ContinueStatement* node);
-  void VisitBreakStatement(BreakStatement* node);
-  void VisitReturnStatement(ReturnStatement* node);
-  void VisitWithEnterStatement(WithEnterStatement* node);
-  void VisitWithExitStatement(WithExitStatement* node);
-  void VisitSwitchStatement(SwitchStatement* node);
-  void VisitLoopStatement(LoopStatement* node);
-  void VisitForInStatement(ForInStatement* node);
-  void VisitTryCatch(TryCatch* node);
-  void VisitTryFinally(TryFinally* node);
-  void VisitDebuggerStatement(DebuggerStatement* node);
-  void VisitFunctionLiteral(FunctionLiteral* node);
-  void VisitFunctionBoilerplateLiteral(FunctionBoilerplateLiteral* node);
-  void VisitConditional(Conditional* node);
-  void VisitSlot(Slot* node);
-  void VisitVariable(Variable* node);
-  void VisitVariableProxy(VariableProxy* node);
-  void VisitLiteral(Literal* node);
-  void VisitRegExpLiteral(RegExpLiteral* node);
-  void VisitObjectLiteral(ObjectLiteral* node);
-  void VisitArrayLiteral(ArrayLiteral* node);
-  void VisitCatchExtensionObject(CatchExtensionObject* node);
-  void VisitAssignment(Assignment* node);
-  void VisitThrow(Throw* node);
-  void VisitProperty(Property* node);
-  void VisitCall(Call* node);
-  void VisitCallNew(CallNew* node);
-  void VisitCallRuntime(CallRuntime* node);
-  void VisitUnaryOperation(UnaryOperation* node);
-  void VisitCountOperation(CountOperation* node);
-  void VisitBinaryOperation(BinaryOperation* node);
-  void VisitCompareOperation(CompareOperation* node);
-  void VisitThisFunction(ThisFunction* node);
+  // AST node visit functions.
+#define DECLARE_VISIT(type) void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  void VisitVariable(Variable* var);

   private:
    int weight_;
@@ -329,7 +297,8 @@


  void UsageComputer::VisitCallNew(CallNew* node) {
-  VisitCall(node);
+  Read(node->expression());
+  ReadList(node->arguments());
  }


=======================================
--- /branches/bleeding_edge/test/mjsunit/invalid-lhs.js Tue Sep  9 13:08:45  
2008
+++ /branches/bleeding_edge/test/mjsunit/invalid-lhs.js Wed Sep 30 02:49:36  
2009
@@ -25,9 +25,8 @@
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-// Test that we get exceptions for invalid left-hand sides.  Also
-// tests that if the invalid left-hand side is a function call, the
-// exception is delayed until runtime.
+// Test that we get exceptions for invalid left-hand sides.  The
+// exceptions are delayed until runtime.

  // Normal assignments:
  assertThrows("12 = 12");
@@ -57,12 +56,10 @@

  // Assignments to 'this'.
  assertThrows("this = 42");
-assertThrows("function f() { this = 12; }");
-assertThrows("for (this in Array) ;");
+assertDoesNotThrow("function f() { this = 12; }");
+assertThrows("for (this in {x:3, y:4, z:5}) ;");
  assertThrows("for (this = 0;;) ;");
  assertThrows("this++");
  assertThrows("++this");
  assertThrows("this--");
  assertThrows("--this");
-
-

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to