From: marja@chromium.org Date: Fri, 14 Feb 2014 16:08:14 +0000 (+0000) Subject: Revert "(Pre)Parser: Simplify NewExpression handling." X-Git-Tag: upstream/4.7.83~10700 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0323bf9cd7305405dfe8e92978f474b232060db8;p=platform%2Fupstream%2Fv8.git Revert "(Pre)Parser: Simplify NewExpression handling." 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 --- diff --git a/src/parser.cc b/src/parser.cc index afeb013..3ef2204 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* args = ParseArguments(CHECK_OK); - return factory()->NewCallNew(result, args, new_pos); - } - // NewExpression without arguments. - return factory()->NewCallNew( - result, new(zone()) ZoneList(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(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* args = ParseArguments(CHECK_OK); + int pos = stack->pop(); + result = factory()->NewCallNew(result, args, pos); + break; + } default: return result; } diff --git a/src/parser.h b/src/parser.h index d1d9b61..b21c275 100644 --- a/src/parser.h +++ b/src/parser.h @@ -638,8 +638,11 @@ class Parser : public ParserBase { 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); diff --git a/src/preparser.cc b/src/preparser.cc index 018f99d..6759550 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -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; } diff --git a/src/preparser.h b/src/preparser.h index 234dde9..cbc92da 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -854,8 +854,9 @@ class PreParser : public ParserBase { 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); diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 6cb8d8d..5de0eba 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -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); -}