| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index afeb013b06ce5b423596521ea9f4c71fc0d1f353..3ef220478d10dcbb47f1f0d6f9124079ba6cc4b2 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -46,6 +46,49 @@
|
| 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;
|
| }
|
|
|