From 88ee432497cdfece785755923b5cad24609e50e0 Mon Sep 17 00:00:00 2001 From: "arv@chromium.org" Date: Wed, 20 Aug 2014 15:51:07 +0000 Subject: [PATCH] Refactor ParseObjectLiteral This extracts the parsing of the ObjectLiteralProperty into its own function. This is in preparation for adding support for parsing classes. BUG=None LOG=Y R=dslomov@chromium.org, marja@chromium.org Review URL: https://codereview.chromium.org/458613004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23249 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/parser.h | 4 +- src/preparser.h | 200 ++++++++++++++++++++++++++------------------------------ 2 files changed, 94 insertions(+), 110 deletions(-) diff --git a/src/parser.h b/src/parser.h index 93af699..4bc9b1d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -439,7 +439,8 @@ class ParserTraits { } static void CheckFunctionLiteralInsideTopLevelObjectLiteral( - Scope* scope, Expression* value, bool* has_function) { + Scope* scope, ObjectLiteralProperty* property, bool* has_function) { + Expression* value = property->value(); if (scope->DeclarationScope()->is_global_scope() && value->AsFunctionLiteral() != NULL) { *has_function = true; @@ -529,6 +530,7 @@ class ParserTraits { static Literal* EmptyLiteral() { return NULL; } + static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; } // Used in error return values. static ZoneList* NullExpressionList() { diff --git a/src/preparser.h b/src/preparser.h index 78bfd65..5ca161d 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -30,7 +30,7 @@ namespace internal { // interface as AstNodeFactory, so ParserBase doesn't need to care which one is // used. -// - Miscellanous other tasks interleaved with the recursive descent. For +// - Miscellaneous other tasks interleaved with the recursive descent. For // example, Parser keeps track of which function literals should be marked as // pretenured, and PreParser doesn't care. @@ -63,6 +63,8 @@ class ParserBase : public Traits { typedef typename Traits::Type::Expression ExpressionT; typedef typename Traits::Type::Identifier IdentifierT; typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; + typedef typename Traits::Type::Literal LiteralT; + typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT; ParserBase(Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension, ParserRecorder* log, typename Traits::Type::Zone* zone, @@ -474,6 +476,7 @@ class ParserBase : public Traits { ExpressionT ParseExpression(bool accept_IN, bool* ok); ExpressionT ParseArrayLiteral(bool* ok); ExpressionT ParseObjectLiteral(bool* ok); + ObjectLiteralPropertyT ParsePropertyDefinition(bool* ok); typename Traits::Type::ExpressionList ParseArguments(bool* ok); ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseYieldExpression(bool* ok); @@ -1109,7 +1112,8 @@ class PreParserTraits { } static void CheckFunctionLiteralInsideTopLevelObjectLiteral( - PreParserScope* scope, PreParserExpression value, bool* has_function) {} + PreParserScope* scope, PreParserExpression property, bool* has_function) { + } static void CheckAssigningFunctionLiteralToProperty( PreParserExpression left, PreParserExpression right) {} @@ -1181,6 +1185,9 @@ class PreParserTraits { static PreParserExpression EmptyLiteral() { return PreParserExpression::Default(); } + static PreParserExpression EmptyObjectLiteralProperty() { + return PreParserExpression::Default(); + } static PreParserExpressionList NullExpressionList() { return PreParserExpressionList(); } @@ -1794,14 +1801,89 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral( template +typename ParserBase::ObjectLiteralPropertyT +ParserBase::ParsePropertyDefinition(bool* ok) { + LiteralT key = this->EmptyLiteral(); + Token::Value next = peek(); + int next_pos = peek_position(); + + switch (next) { + case Token::STRING: { + Consume(Token::STRING); + IdentifierT string = this->GetSymbol(scanner_); + if (fni_ != NULL) this->PushLiteralName(fni_, string); + uint32_t index; + if (this->IsArrayIndex(string, &index)) { + key = factory()->NewNumberLiteral(index, next_pos); + break; + } + key = factory()->NewStringLiteral(string, next_pos); + break; + } + case Token::NUMBER: { + Consume(Token::NUMBER); + key = this->ExpressionFromLiteral(Token::NUMBER, next_pos, scanner_, + factory()); + break; + } + default: { + bool is_getter = false; + bool is_setter = false; + IdentifierT id = ParseIdentifierNameOrGetOrSet( + &is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + if (fni_ != NULL) this->PushLiteralName(fni_, id); + + if ((is_getter || is_setter) && peek() != Token::COLON) { + // Special handling of getter and setter syntax: + // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... } + // We have already read the "get" or "set" keyword. + IdentifierT name = this->EmptyIdentifier(); + switch (peek()) { + case Token::STRING: + Consume(Token::STRING); + name = this->GetSymbol(scanner_); + break; + case Token::NUMBER: + Consume(Token::NUMBER); + // TODO(arv): Fix issue with numeric keys. get 1.0() should be + // treated as if the key was '1' + // https://code.google.com/p/v8/issues/detail?id=3507 + name = this->GetSymbol(scanner_); + break; + default: + name = ParseIdentifierName( + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + } + typename Traits::Type::FunctionLiteral value = + this->ParseFunctionLiteral( + name, scanner()->location(), + false, // reserved words are allowed here + false, // not a generator + RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, + is_getter ? FunctionLiteral::GETTER_ARITY + : FunctionLiteral::SETTER_ARITY, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + return factory()->NewObjectLiteralProperty(is_getter, value, next_pos); + } + // Failed to parse as get/set property, so it's just a normal property + // (which might be called "get" or "set" or something else). + key = factory()->NewStringLiteral(id, next_pos); + } + } + + Expect(Token::COLON, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + ExpressionT value = this->ParseAssignmentExpression( + true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + + return factory()->NewObjectLiteralProperty(key, value); +} + + +template typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral( bool* ok) { // ObjectLiteral :: - // '{' (( - // ((IdentifierName | String | Number) ':' AssignmentExpression) | - // (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) - // ) ',')* '}' - // (Except that the trailing comma is not required.) + // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' int pos = peek_position(); typename Traits::Type::PropertyList properties = @@ -1814,112 +1896,12 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral( while (peek() != Token::RBRACE) { if (fni_ != NULL) fni_->Enter(); - typename Traits::Type::Literal key = this->EmptyLiteral(); - Token::Value next = peek(); - int next_pos = peek_position(); - - switch (next) { - case Token::FUTURE_RESERVED_WORD: - case Token::FUTURE_STRICT_RESERVED_WORD: - case Token::LET: - case Token::YIELD: - case Token::IDENTIFIER: { - bool is_getter = false; - bool is_setter = false; - IdentifierT id = - ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); - if (fni_ != NULL) this->PushLiteralName(fni_, id); - - if ((is_getter || is_setter) && peek() != Token::COLON) { - // Special handling of getter and setter syntax: - // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... } - // We have already read the "get" or "set" keyword. - Token::Value next = Next(); - if (next != i::Token::IDENTIFIER && - next != i::Token::FUTURE_RESERVED_WORD && - next != i::Token::FUTURE_STRICT_RESERVED_WORD && - next != i::Token::LET && - next != i::Token::YIELD && - next != i::Token::NUMBER && - next != i::Token::STRING && - !Token::IsKeyword(next)) { - ReportUnexpectedToken(next); - *ok = false; - return this->EmptyLiteral(); - } - IdentifierT name = this->GetSymbol(scanner_); - typename Traits::Type::FunctionLiteral value = - this->ParseFunctionLiteral( - name, scanner()->location(), - false, // reserved words are allowed here - false, // not a generator - RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, - is_getter ? FunctionLiteral::GETTER_ARITY - : FunctionLiteral::SETTER_ARITY, - CHECK_OK); - typename Traits::Type::ObjectLiteralProperty property = - factory()->NewObjectLiteralProperty(is_getter, value, next_pos); - if (this->IsBoilerplateProperty(property)) { - number_of_boilerplate_properties++; - } - properties->Add(property, zone()); - if (peek() != Token::RBRACE) { - // Need {} because of the CHECK_OK macro. - Expect(Token::COMMA, CHECK_OK); - } - - if (fni_ != NULL) { - fni_->Infer(); - fni_->Leave(); - } - continue; // restart the while - } - // Failed to parse as get/set property, so it's just a normal property - // (which might be called "get" or "set" or something else). - key = factory()->NewStringLiteral(id, next_pos); - break; - } - case Token::STRING: { - Consume(Token::STRING); - IdentifierT string = this->GetSymbol(scanner_); - if (fni_ != NULL) this->PushLiteralName(fni_, string); - uint32_t index; - if (this->IsArrayIndex(string, &index)) { - key = factory()->NewNumberLiteral(index, next_pos); - break; - } - key = factory()->NewStringLiteral(string, next_pos); - break; - } - case Token::NUMBER: { - Consume(Token::NUMBER); - key = this->ExpressionFromLiteral(Token::NUMBER, next_pos, scanner_, - factory()); - break; - } - default: - if (Token::IsKeyword(next)) { - Consume(next); - IdentifierT string = this->GetSymbol(scanner_); - key = factory()->NewStringLiteral(string, next_pos); - } else { - Token::Value next = Next(); - ReportUnexpectedToken(next); - *ok = false; - return this->EmptyLiteral(); - } - } - - Expect(Token::COLON, CHECK_OK); - ExpressionT value = this->ParseAssignmentExpression(true, CHECK_OK); - - typename Traits::Type::ObjectLiteralProperty property = - factory()->NewObjectLiteralProperty(key, value); + ObjectLiteralPropertyT property = this->ParsePropertyDefinition(CHECK_OK); // Mark top-level object literals that contain function literals and // pretenure the literal so it can be added as a constant function // property. (Parser only.) - this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, value, + this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property, &has_function); // Count CONSTANT or COMPUTED properties to maintain the enumeration order. -- 2.7.4