Bug 1529772 - Part 1: Document current state of play in GeneralParser::propertyName. r=khyperia
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 15 Apr 2019 20:54:28 +0000
changeset 469564 7d26d6d473cf
parent 469563 5e0cf8b42fcf
child 469565 0f4a343adc59
push id35874
push userccoroiu@mozilla.com
push dateTue, 16 Apr 2019 04:04:58 +0000
treeherdermozilla-central@be3f40425b52 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhyperia
bugs1529772
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1529772 - Part 1: Document current state of play in GeneralParser::propertyName. r=khyperia Differential Revision: https://phabricator.services.mozilla.com/D26035
js/src/frontend/Parser.cpp
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -9638,45 +9638,75 @@ GeneralParser<ParseHandler, Unit>::array
   return literal;
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::propertyName(
     YieldHandling yieldHandling, PropertyNameContext propertyNameContext,
     const Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,
     PropertyType* propType, MutableHandleAtom propAtom) {
+  // We're parsing an object literal, class, or destructuring pattern;
+  // propertyNameContext tells which one. This method parses any of the
+  // following, storing the corresponding PropertyType in `*propType` to tell
+  // the caller what we parsed:
+  //
+  //     async [no LineTerminator here] PropertyName
+  //                            ==> PropertyType::AsyncMethod
+  //     async [no LineTerminator here] * PropertyName
+  //                            ==> PropertyType::AsyncGeneratorMethod
+  //     * PropertyName         ==> PropertyType::GeneratorMethod
+  //     get PropertyName       ==> PropertyType::Getter
+  //     set PropertyName       ==> PropertyType::Setter
+  //     PropertyName :         ==> PropertyType::Normal
+  //     PropertyName           ==> see below
+  //
+  // In the last case, where there's not a `:` token to consume, we peek at
+  // (but don't consume) the next token to decide how to set `*propType`.
+  //
+  //     `=` or `;`             ==> PropertyType::Field (classes only)
+  //     `=`                    ==> PropertyType::CoverInitializedName
+  //     `,` or `}`             ==> PropertyType::Shorthand
+  //     `(`                    ==> PropertyType::Method
+  //
+  // The caller must check `*propType` and throw if whatever we parsed isn't
+  // allowed here (for example, a getter in a destructuring pattern).
+  //
+  // The nonterminal PropertyName comes from the standard:
+  //
+  //     PropertyName[Yield, Await]:
+  //       LiteralPropertyName
+  //       ComputedPropertyName[?Yield, ?Await]
+  //
+  //     LiteralPropertyName:
+  //       IdentifierName
+  //       StringLiteral
+  //       NumericLiteral
+  //
+  //     ComputedPropertyName[Yield, Await]:
+  //       [ AssignmentExpression[+In, ?Yield, ?Await] ]
+  //
+  // This method does *not* match `static` (allowed in classes) or `...`
+  // (allowed in object literals and patterns). The caller must take care of
+  // those before calling this method.
+
   TokenKind ltok;
   if (!tokenStream.getToken(&ltok, TokenStream::SlashIsInvalid)) {
     return null();
   }
 
   MOZ_ASSERT(ltok != TokenKind::RightCurly,
              "caller should have handled TokenKind::RightCurly");
 
+  // Accept `async` and/or `*`, indicating an async or generator method.
   bool isGenerator = false;
   bool isAsync = false;
 
   if (ltok == TokenKind::Async) {
-    // AsyncMethod[Yield, Await]:
-    //   async [no LineTerminator here] PropertyName[?Yield, ?Await] ...
-    //
-    //  AsyncGeneratorMethod[Yield, Await]:
-    //    async [no LineTerminator here] * PropertyName[?Yield, ?Await] ...
-    //
-    // PropertyName:
-    //   LiteralPropertyName
-    //   ComputedPropertyName[?Yield, ?Await]
-    //
-    // LiteralPropertyName:
-    //   IdentifierName
-    //   StringLiteral
-    //   NumericLiteral
-    //
-    // ComputedPropertyName[Yield, Await]:
-    //   [ ...
+    // `async` is also a PropertyName by itself (it's a conditional keyword),
+    // so peek at the next token to see if we're really looking at a method.
     TokenKind tt = TokenKind::Eof;
     if (!tokenStream.peekTokenSameLine(&tt)) {
       return null();
     }
     if (tt == TokenKind::String || tt == TokenKind::Number ||
         tt == TokenKind::LeftBracket || TokenKindIsPossibleIdentifierName(tt) ||
         tt == TokenKind::Mul) {
       isAsync = true;
@@ -9687,16 +9717,17 @@ typename ParseHandler::Node GeneralParse
 
   if (ltok == TokenKind::Mul) {
     isGenerator = true;
     if (!tokenStream.getToken(&ltok)) {
       return null();
     }
   }
 
+  // Parse the PropertyName itself at last.
   propAtom.set(nullptr);
   Node propName;
   switch (ltok) {
     case TokenKind::Number:
       propAtom.set(NumberToAtom(cx_, anyChars.currentToken().number()));
       if (!propAtom.get()) {
         return null();
       }
@@ -9733,16 +9764,17 @@ typename ParseHandler::Node GeneralParse
 
     default: {
       if (!TokenKindIsPossibleIdentifierName(ltok)) {
         error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
         return null();
       }
 
       propAtom.set(anyChars.currentName());
+
       // Do not look for accessor syntax on generator or async methods.
       if (isGenerator || isAsync ||
           !(ltok == TokenKind::Get || ltok == TokenKind::Set)) {
         propName = handler_.newObjectLiteralPropertyName(propAtom, pos());
         if (!propName) {
           return null();
         }
         break;
@@ -9798,16 +9830,18 @@ typename ParseHandler::Node GeneralParse
       propName = handler_.newObjectLiteralPropertyName(propAtom.get(), pos());
       if (!propName) {
         return null();
       }
       break;
     }
   }
 
+  // Grab the next token following the property/method name.
+  // (If this isn't a colon, we're going to either put it back or throw.)
   TokenKind tt;
   if (!tokenStream.getToken(&tt)) {
     return null();
   }
 
   if (tt == TokenKind::Colon) {
     if (isGenerator || isAsync) {
       error(JSMSG_BAD_PROP_ID);