| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 0c07c325d0308daa1bf570148342ac68ea274a49..2d4ec162763bfabca2832bbbf94b0166e3a907fd 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,
|
| @@ -470,6 +472,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);
|
| @@ -1100,7 +1103,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) {}
|
| @@ -1172,6 +1176,9 @@ class PreParserTraits {
|
| static PreParserExpression EmptyLiteral() {
|
| return PreParserExpression::Default();
|
| }
|
| + static PreParserExpression EmptyObjectLiteralProperty() {
|
| + return PreParserExpression::Default();
|
| + }
|
| static PreParserExpressionList NullExpressionList() {
|
| return PreParserExpressionList();
|
| }
|
| @@ -1780,14 +1787,89 @@ 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>
|
| 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.)
|
| + // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
|
|
|
| int pos = peek_position();
|
| typename Traits::Type::PropertyList properties =
|
| @@ -1800,112 +1882,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::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.
|
|
|