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 { ...@@ -439,7 +439,8 @@ class ParserTraits {
} }
static void CheckFunctionLiteralInsideTopLevelObjectLiteral( 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() && if (scope->DeclarationScope()->is_global_scope() &&
value->AsFunctionLiteral() != NULL) { value->AsFunctionLiteral() != NULL) {
*has_function = true; *has_function = true;
...@@ -529,6 +530,7 @@ class ParserTraits { ...@@ -529,6 +530,7 @@ class ParserTraits {
static Literal* EmptyLiteral() { static Literal* EmptyLiteral() {
return NULL; return NULL;
} }
static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; }
// Used in error return values. // Used in error return values.
static ZoneList<Expression*>* NullExpressionList() { static ZoneList<Expression*>* NullExpressionList() {
......
...@@ -30,7 +30,7 @@ namespace internal { ...@@ -30,7 +30,7 @@ namespace internal {
// interface as AstNodeFactory, so ParserBase doesn't need to care which one is // interface as AstNodeFactory, so ParserBase doesn't need to care which one is
// used. // 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 // example, Parser keeps track of which function literals should be marked as
// pretenured, and PreParser doesn't care. // pretenured, and PreParser doesn't care.
...@@ -63,6 +63,8 @@ class ParserBase : public Traits { ...@@ -63,6 +63,8 @@ class ParserBase : public Traits {
typedef typename Traits::Type::Expression ExpressionT; typedef typename Traits::Type::Expression ExpressionT;
typedef typename Traits::Type::Identifier IdentifierT; typedef typename Traits::Type::Identifier IdentifierT;
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; 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, ParserBase(Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension,
ParserRecorder* log, typename Traits::Type::Zone* zone, ParserRecorder* log, typename Traits::Type::Zone* zone,
...@@ -474,6 +476,7 @@ class ParserBase : public Traits { ...@@ -474,6 +476,7 @@ class ParserBase : public Traits {
ExpressionT ParseExpression(bool accept_IN, bool* ok); ExpressionT ParseExpression(bool accept_IN, bool* ok);
ExpressionT ParseArrayLiteral(bool* ok); ExpressionT ParseArrayLiteral(bool* ok);
ExpressionT ParseObjectLiteral(bool* ok); ExpressionT ParseObjectLiteral(bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok); typename Traits::Type::ExpressionList ParseArguments(bool* ok);
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool* ok); ExpressionT ParseYieldExpression(bool* ok);
...@@ -1109,7 +1112,8 @@ class PreParserTraits { ...@@ -1109,7 +1112,8 @@ class PreParserTraits {
} }
static void CheckFunctionLiteralInsideTopLevelObjectLiteral( static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
PreParserScope* scope, PreParserExpression value, bool* has_function) {} PreParserScope* scope, PreParserExpression property, bool* has_function) {
}
static void CheckAssigningFunctionLiteralToProperty( static void CheckAssigningFunctionLiteralToProperty(
PreParserExpression left, PreParserExpression right) {} PreParserExpression left, PreParserExpression right) {}
...@@ -1181,6 +1185,9 @@ class PreParserTraits { ...@@ -1181,6 +1185,9 @@ class PreParserTraits {
static PreParserExpression EmptyLiteral() { static PreParserExpression EmptyLiteral() {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
static PreParserExpression EmptyObjectLiteralProperty() {
return PreParserExpression::Default();
}
static PreParserExpressionList NullExpressionList() { static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList(); return PreParserExpressionList();
} }
...@@ -1793,15 +1800,90 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( ...@@ -1793,15 +1800,90 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
} }
template <class Traits>
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::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 <class Traits> template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
bool* ok) { bool* ok) {
// ObjectLiteral :: // ObjectLiteral ::
// '{' (( // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
// ((IdentifierName | String | Number) ':' AssignmentExpression) |
// (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
// ) ',')* '}'
// (Except that the trailing comma is not required.)
int pos = peek_position(); int pos = peek_position();
typename Traits::Type::PropertyList properties = typename Traits::Type::PropertyList properties =
...@@ -1814,112 +1896,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( ...@@ -1814,112 +1896,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter(); if (fni_ != NULL) fni_->Enter();
typename Traits::Type::Literal key = this->EmptyLiteral(); ObjectLiteralPropertyT property = this->ParsePropertyDefinition(CHECK_OK);
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);
// Mark top-level object literals that contain function literals and // Mark top-level object literals that contain function literals and
// pretenure the literal so it can be added as a constant function // pretenure the literal so it can be added as a constant function
// property. (Parser only.) // property. (Parser only.)
this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, value, this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property,
&has_function); &has_function);
// Count CONSTANT or COMPUTED properties to maintain the enumeration order. // 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