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),
// 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()) {
}
-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)*
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;
}
// 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()) {
}
-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)*
}
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;
}
// 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);
-}