Commit 88ee4324 authored by arv@chromium.org's avatar arv@chromium.org

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
parent 72ffc42d
......@@ -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<Expression*>* NullExpressionList() {
......
......@@ -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,60 +1801,59 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
bool* ok) {
// ObjectLiteral ::
// '{' ((
// ((IdentifierName | String | Number) ':' AssignmentExpression) |
// (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
// ) ',')* '}'
// (Except that the trailing comma is not required.)
int pos = peek_position();
typename Traits::Type::PropertyList properties =
this->NewPropertyList(4, zone_);
int number_of_boilerplate_properties = 0;
bool has_function = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter();
typename Traits::Type::Literal key = this->EmptyLiteral();
typename ParserBase<Traits>::ObjectLiteralPropertyT
ParserBase<Traits>::ParsePropertyDefinition(bool* ok) {
LiteralT 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: {
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);
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.
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->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));
}
IdentifierT name = this->GetSymbol(scanner_);
typename Traits::Type::FunctionLiteral value =
this->ParseFunctionLiteral(
name, scanner()->location(),
......@@ -1856,70 +1862,46 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
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
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);
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);
Expect(Token::COLON, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
ExpressionT value = this->ParseAssignmentExpression(
true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
return factory()->NewObjectLiteralProperty(key, value);
}
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
bool* ok) {
// ObjectLiteral ::
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
int pos = peek_position();
typename Traits::Type::PropertyList properties =
this->NewPropertyList(4, zone_);
int number_of_boilerplate_properties = 0;
bool has_function = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter();
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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment