Revert "(Pre)Parser: Simplify NewExpression handling."
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Feb 2014 16:08:14 +0000 (16:08 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Feb 2014 16:08:14 +0000 (16:08 +0000)
This reverts revision 19386.

Reason: Mozilla failures.

BUG=
TBR=ulan@chromium.org,marja@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19388 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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

index afeb013..3ef2204 100644 (file)
 namespace v8 {
 namespace internal {
 
+// PositionStack is used for on-stack allocation of token positions for
+// new expressions. Please look at ParseNewExpression.
+
+class PositionStack  {
+ public:
+  explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {}
+  ~PositionStack() {
+    ASSERT(!*ok_ || is_empty());
+    USE(ok_);
+  }
+
+  class Element  {
+   public:
+    Element(PositionStack* stack, int value) {
+      previous_ = stack->top();
+      value_ = value;
+      stack->set_top(this);
+    }
+
+   private:
+    Element* previous() { return previous_; }
+    int value() { return value_; }
+    friend class PositionStack;
+    Element* previous_;
+    int value_;
+  };
+
+  bool is_empty() { return top_ == NULL; }
+  int pop() {
+    ASSERT(!is_empty());
+    int result = top_->value();
+    top_ = top_->previous();
+    return result;
+  }
+
+ private:
+  Element* top() { return top_; }
+  void set_top(Element* value) { top_ = value; }
+  Element* top_;
+  bool* ok_;
+};
+
+
 RegExpBuilder::RegExpBuilder(Zone* zone)
     : zone_(zone),
       pending_empty_(false),
@@ -3249,7 +3292,12 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
   // LeftHandSideExpression ::
   //   (NewExpression | MemberExpression) ...
 
-  Expression* result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
+  Expression* result;
+  if (peek() == Token::NEW) {
+    result = ParseNewExpression(CHECK_OK);
+  } else {
+    result = ParseMemberExpression(CHECK_OK);
+  }
 
   while (true) {
     switch (peek()) {
@@ -3318,42 +3366,50 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
 }
 
 
-Expression* Parser::ParseMemberWithNewPrefixesExpression(bool* ok) {
+Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
   // NewExpression ::
   //   ('new')+ MemberExpression
 
-  // The grammar for new expressions is pretty warped. We can have several 'new'
-  // keywords following each other, and then a MemberExpression. When we see '('
-  // after the MemberExpression, it's associated with the rightmost unassociated
-  // 'new' to create a NewExpression with arguments. However, a NewExpression
-  // can also occur without arguments.
-
-  // Examples of new expression:
-  // new foo.bar().baz means (new (foo.bar)()).baz
-  // new foo()() means (new foo())()
-  // new new foo()() means (new (new foo())())
-  // new new foo means new (new foo)
-  // new new foo() means new (new foo())
-
+  // The grammar for new expressions is pretty warped. The keyword
+  // 'new' can either be a part of the new expression (where it isn't
+  // followed by an argument list) or a part of the member expression,
+  // where it must be followed by an argument list. To accommodate
+  // this, we parse the 'new' keywords greedily and keep track of how
+  // many we have parsed. This information is then passed on to the
+  // member expression parser, which is only allowed to match argument
+  // lists as long as it has 'new' prefixes left
+  Expect(Token::NEW, CHECK_OK);
+  PositionStack::Element pos(stack, position());
+
+  Expression* result;
   if (peek() == Token::NEW) {
-    Consume(Token::NEW);
-    int new_pos = position();
-    Expression* result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
-    if (peek() == Token::LPAREN) {
-      // NewExpression with arguments.
-      ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
-      return factory()->NewCallNew(result, args, new_pos);
-    }
-    // NewExpression without arguments.
-    return factory()->NewCallNew(
-        result, new(zone()) ZoneList<Expression*>(0, zone()), new_pos);
+    result = ParseNewPrefix(stack, CHECK_OK);
+  } else {
+    result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
+  }
+
+  if (!stack->is_empty()) {
+    int last = stack->pop();
+    result = factory()->NewCallNew(
+        result, new(zone()) ZoneList<Expression*>(0, zone()), last);
   }
-  // No 'new' keyword.
-  return ParseMemberExpression(ok);
+  return result;
+}
+
+
+Expression* Parser::ParseNewExpression(bool* ok) {
+  PositionStack stack(ok);
+  return ParseNewPrefix(&stack, ok);
 }
 
 
 Expression* Parser::ParseMemberExpression(bool* ok) {
+  return ParseMemberWithNewPrefixesExpression(NULL, ok);
+}
+
+
+Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
+                                                         bool* ok) {
   // MemberExpression ::
   //   (PrimaryExpression | FunctionLiteral)
   //     ('[' Expression ']' | '.' Identifier | Arguments)*
@@ -3413,6 +3469,14 @@ Expression* Parser::ParseMemberExpression(bool* ok) {
         if (fni_ != NULL) fni_->PushLiteralName(name);
         break;
       }
+      case Token::LPAREN: {
+        if ((stack == NULL) || stack->is_empty()) return result;
+        // Consume one of the new prefixes (already parsed).
+        ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
+        int pos = stack->pop();
+        result = factory()->NewCallNew(result, args, pos);
+        break;
+      }
       default:
         return result;
     }
index d1d9b61..b21c275 100644 (file)
@@ -638,8 +638,11 @@ class Parser : public ParserBase<ParserTraits> {
   Expression* ParseUnaryExpression(bool* ok);
   Expression* ParsePostfixExpression(bool* ok);
   Expression* ParseLeftHandSideExpression(bool* ok);
-  Expression* ParseMemberWithNewPrefixesExpression(bool* ok);
+  Expression* ParseNewExpression(bool* ok);
   Expression* ParseMemberExpression(bool* ok);
+  Expression* ParseNewPrefix(PositionStack* stack, bool* ok);
+  Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack,
+                                                   bool* ok);
   Expression* ParseArrayLiteral(bool* ok);
   Expression* ParseObjectLiteral(bool* ok);
 
index 018f99d..6759550 100644 (file)
@@ -1007,7 +1007,12 @@ PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
   // LeftHandSideExpression ::
   //   (NewExpression | MemberExpression) ...
 
-  Expression result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
+  Expression result = Expression::Default();
+  if (peek() == Token::NEW) {
+    result = ParseNewExpression(CHECK_OK);
+  } else {
+    result = ParseMemberExpression(CHECK_OK);
+  }
 
   while (true) {
     switch (peek()) {
@@ -1047,28 +1052,35 @@ PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
 }
 
 
-PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
-    bool* ok) {
+PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
   // NewExpression ::
   //   ('new')+ MemberExpression
 
-  // See Parser::ParseNewExpression.
-
-  if (peek() == Token::NEW) {
+  // The grammar for new expressions is pretty warped. The keyword
+  // 'new' can either be a part of the new expression (where it isn't
+  // followed by an argument list) or a part of the member expression,
+  // where it must be followed by an argument list. To accommodate
+  // this, we parse the 'new' keywords greedily and keep track of how
+  // many we have parsed. This information is then passed on to the
+  // member expression parser, which is only allowed to match argument
+  // lists as long as it has 'new' prefixes left
+  unsigned new_count = 0;
+  do {
     Consume(Token::NEW);
-    ParseMemberWithNewPrefixesExpression(CHECK_OK);
-    if (peek() == Token::LPAREN) {
-      // NewExpression with arguments.
-      ParseArguments(CHECK_OK);
-    }
-    return Expression::Default();
-  }
-  // No 'new' keyword.
-  return ParseMemberExpression(ok);
+    new_count++;
+  } while (peek() == Token::NEW);
+
+  return ParseMemberWithNewPrefixesExpression(new_count, ok);
 }
 
 
 PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
+  return ParseMemberWithNewPrefixesExpression(0, ok);
+}
+
+
+PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
+    unsigned new_count, bool* ok) {
   // MemberExpression ::
   //   (PrimaryExpression | FunctionLiteral)
   //     ('[' Expression ']' | '.' Identifier | Arguments)*
@@ -1119,6 +1131,14 @@ PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
         }
         break;
       }
+      case Token::LPAREN: {
+        if (new_count == 0) return result;
+        // Consume one of the new prefixes (already parsed).
+        ParseArguments(CHECK_OK);
+        new_count--;
+        result = Expression::Default();
+        break;
+      }
       default:
         return result;
     }
index 234dde9..cbc92da 100644 (file)
@@ -854,8 +854,9 @@ class PreParser : public ParserBase<PreParserTraits> {
   Expression ParseUnaryExpression(bool* ok);
   Expression ParsePostfixExpression(bool* ok);
   Expression ParseLeftHandSideExpression(bool* ok);
+  Expression ParseNewExpression(bool* ok);
   Expression ParseMemberExpression(bool* ok);
-  Expression ParseMemberWithNewPrefixesExpression(bool* ok);
+  Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
   Expression ParseArrayLiteral(bool* ok);
   Expression ParseObjectLiteral(bool* ok);
   Expression ParseV8Intrinsic(bool* ok);
index 6cb8d8d..5de0eba 100644 (file)
@@ -2063,60 +2063,3 @@ TEST(Intrinsics) {
   // or not.
   RunParserSyncTest(context_data, statement_data, kSuccessOrError);
 }
-
-
-TEST(NoErrorsNewExpression) {
-  const char* context_data[][2] = {
-    {"", ""},
-    {"var f =", ""},
-    { NULL, NULL }
-  };
-
-  const char* statement_data[] = {
-    "new foo",
-    "new foo();",
-    "new foo(1);",
-    "new foo(1, 2);",
-    // The first () will be processed as a part of the NewExpression and the
-    // second () will be processed as part of LeftHandSideExpression.
-    "new foo()();",
-    // The first () will be processed as a part of the inner NewExpression and
-    // the second () will be processed as a part of the outer NewExpression.
-    "new new foo()();",
-    "new foo.bar;",
-    "new foo.bar();",
-    "new foo.bar.baz;",
-    "new foo.bar().baz;",
-    "new foo[bar];",
-    "new foo[bar]();",
-    "new foo[bar][baz];",
-    "new foo[bar]()[baz];",
-    "new foo[bar].baz(baz)()[bar].baz;",
-    "new \"foo\"",  // Runtime error
-    "new 1",  // Runtime error
-    "new foo++",
-    // This even runs:
-    "(new new Function(\"this.x = 1\")).x;",
-    NULL
-  };
-
-  RunParserSyncTest(context_data, statement_data, kSuccess);
-}
-
-
-TEST(ErrorsNewExpression) {
-  const char* context_data[][2] = {
-    {"", ""},
-    {"var f =", ""},
-    { NULL, NULL }
-  };
-
-  const char* statement_data[] = {
-    "new foo bar",
-    "new ) foo",
-    "new ++foo",
-    NULL
-  };
-
-  RunParserSyncTest(context_data, statement_data, kError);
-}