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();
} }
...@@ -1794,60 +1801,59 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( ...@@ -1794,60 +1801,59 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
template <class Traits> template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( typename ParserBase<Traits>::ObjectLiteralPropertyT
bool* ok) { ParserBase<Traits>::ParsePropertyDefinition(bool* ok) {
// ObjectLiteral :: LiteralT key = this->EmptyLiteral();
// '{' ((
// ((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();
Token::Value next = peek(); Token::Value next = peek();
int next_pos = peek_position(); int next_pos = peek_position();
switch (next) { switch (next) {
case Token::FUTURE_RESERVED_WORD: case Token::STRING: {
case Token::FUTURE_STRICT_RESERVED_WORD: Consume(Token::STRING);
case Token::LET: IdentifierT string = this->GetSymbol(scanner_);
case Token::YIELD: if (fni_ != NULL) this->PushLiteralName(fni_, string);
case Token::IDENTIFIER: { 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_getter = false;
bool is_setter = false; bool is_setter = false;
IdentifierT id = IdentifierT id = ParseIdentifierNameOrGetOrSet(
ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); &is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != NULL) this->PushLiteralName(fni_, id); if (fni_ != NULL) this->PushLiteralName(fni_, id);
if ((is_getter || is_setter) && peek() != Token::COLON) { if ((is_getter || is_setter) && peek() != Token::COLON) {
// Special handling of getter and setter syntax: // Special handling of getter and setter syntax:
// { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... } // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
// We have already read the "get" or "set" keyword. // We have already read the "get" or "set" keyword.
Token::Value next = Next(); IdentifierT name = this->EmptyIdentifier();
if (next != i::Token::IDENTIFIER && switch (peek()) {
next != i::Token::FUTURE_RESERVED_WORD && case Token::STRING:
next != i::Token::FUTURE_STRICT_RESERVED_WORD && Consume(Token::STRING);
next != i::Token::LET && name = this->GetSymbol(scanner_);
next != i::Token::YIELD && break;
next != i::Token::NUMBER && case Token::NUMBER:
next != i::Token::STRING && Consume(Token::NUMBER);
!Token::IsKeyword(next)) { // TODO(arv): Fix issue with numeric keys. get 1.0() should be
ReportUnexpectedToken(next); // treated as if the key was '1'
*ok = false; // https://code.google.com/p/v8/issues/detail?id=3507
return this->EmptyLiteral(); name = this->GetSymbol(scanner_);
break;
default:
name = ParseIdentifierName(
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} }
IdentifierT name = this->GetSymbol(scanner_);
typename Traits::Type::FunctionLiteral value = typename Traits::Type::FunctionLiteral value =
this->ParseFunctionLiteral( this->ParseFunctionLiteral(
name, scanner()->location(), name, scanner()->location(),
...@@ -1856,70 +1862,46 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( ...@@ -1856,70 +1862,46 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
is_getter ? FunctionLiteral::GETTER_ARITY is_getter ? FunctionLiteral::GETTER_ARITY
: FunctionLiteral::SETTER_ARITY, : FunctionLiteral::SETTER_ARITY,
CHECK_OK); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
typename Traits::Type::ObjectLiteralProperty property = return factory()->NewObjectLiteralProperty(is_getter, value, next_pos);
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 // Failed to parse as get/set property, so it's just a normal property
// (which might be called "get" or "set" or something else). // (which might be called "get" or "set" or something else).
key = factory()->NewStringLiteral(id, next_pos); 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); Expect(Token::COLON, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
ExpressionT value = this->ParseAssignmentExpression(true, CHECK_OK); 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 = ObjectLiteralPropertyT property = this->ParsePropertyDefinition(CHECK_OK);
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