Refactor ParseObjectLiteral
authorarv@chromium.org <arv@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 15:51:07 +0000 (15:51 +0000)
committerarv@chromium.org <arv@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 15:51:07 +0000 (15:51 +0000)
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
src/preparser.h

index 93af699..4bc9b1d 100644 (file)
@@ -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() {
index 78bfd65..5ca161d 100644 (file)
@@ -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<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 =
@@ -1814,112 +1896,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.