diff options
author | Martok <martok@martoks-place.de> | 2023-04-09 02:01:53 +0200 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-05-01 17:16:18 +0200 |
commit | 0d3a394cad25be8e6acb6b8a249da3a809073fa2 (patch) | |
tree | d8e83cccc2136e3fa44839459c48dd16a393801e | |
parent | f7935ec5b2cfb652b403c1141b585ade25e56135 (diff) | |
download | uxp-0d3a394cad25be8e6acb6b8a249da3a809073fa2.tar.gz |
Issue #2142 - Factor out PropertyName parsing from Parser::propertyName()
Based-on: m-c 1529772/{1,2}
-rw-r--r-- | js/src/frontend/Parser.cpp | 235 | ||||
-rw-r--r-- | js/src/frontend/Parser.h | 6 |
2 files changed, 126 insertions, 115 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 8e09aea626..aa0e005268 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4469,7 +4469,8 @@ Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling y TokenPos namePos = tokenStream.nextToken().pos; PropertyType propType; - Node propName = propertyName(yieldHandling, PropertyNameInPattern, declKind, literal, &propType, &propAtom); + Node propName = propertyOrMethodName(yieldHandling, PropertyNameInPattern, declKind, + literal, &propType, &propAtom); if (!propName) return null(); if (propType == PropertyType::Normal) { @@ -7452,8 +7453,9 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d RootedAtom propAtom(context); PropertyType propType; - Node propName = propertyName(yieldHandling, PropertyNameInClass, /* maybeDecl = */ Nothing(), - classMembers, &propType, &propAtom); + Node propName = propertyOrMethodName(yieldHandling, PropertyNameInClass, + /* maybeDecl = */ Nothing(), + classMembers, &propType, &propAtom); if (!propName) return false; @@ -10559,85 +10561,37 @@ typename ParseHandler::Node Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, PropertyNameContext propertyNameContext, const Maybe<DeclarationKind>& maybeDecl, ListNodeType propList, - PropertyType* propType, MutableHandleAtom propAtom) + MutableHandleAtom propAtom) { - TokenKind ltok; - if (!tokenStream.getToken(<ok)) - return null(); - - MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC"); - - bool isGenerator = false; - bool isAsync = false; - - if (ltok == TOK_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]: - // [ ... - TokenKind tt = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&tt)) - return null(); - if (tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB || - TokenKindIsPossibleIdentifierName(tt) || tt == TOK_MUL) - { - isAsync = true; - tokenStream.consumeKnownToken(tt); - ltok = tt; - } - } - - if (ltok == TOK_MUL) { - isGenerator = true; - if (!tokenStream.getToken(<ok)) - return null(); - } + // PropertyName[Yield, Await]: + // LiteralPropertyName + // ComputedPropertyName[?Yield, ?Await] + // + // LiteralPropertyName: + // IdentifierName + // StringLiteral + // NumericLiteral + TokenKind ltok = tokenStream.currentToken().type; propAtom.set(nullptr); - Node propName; switch (ltok) { case TOK_NUMBER: propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number())); if (!propAtom.get()) return null(); - propName = newNumber(tokenStream.currentToken()); - if (!propName) - return null(); - break; + return newNumber(tokenStream.currentToken()); case TOK_STRING: { propAtom.set(tokenStream.currentToken().atom()); uint32_t index; if (propAtom->isIndex(&index)) { - propName = handler.newNumber(index, NoDecimal, pos()); - if (!propName) - return null(); - break; + return handler.newNumber(index, NoDecimal, pos()); } - propName = stringLiteral(); - if (!propName) - return null(); - break; + return stringLiteral(); } case TOK_LB: - propName = computedPropertyName(yieldHandling, maybeDecl, propList); - if (!propName) - return null(); - break; + return computedPropertyName(yieldHandling, maybeDecl, propList); default: { if (!TokenKindIsPossibleIdentifierName(ltok)) { @@ -10646,69 +10600,117 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, } propAtom.set(tokenStream.currentName()); - // Do not look for accessor syntax on generator or async methods. - if (isGenerator || isAsync || !(ltok == TOK_GET || ltok == TOK_SET)) { - propName = handler.newObjectLiteralPropertyName(propAtom, pos()); - if (!propName) - return null(); - break; - } + return handler.newObjectLiteralPropertyName(propAtom, pos()); + } + } +} - *propType = ltok == TOK_GET ? PropertyType::Getter : PropertyType::Setter; +// True if `kind` can be the first token of a PropertyName. +static bool +TokenKindCanStartPropertyName(TokenKind tt) +{ + return TokenKindIsPossibleIdentifierName(tt) || tt == TOK_STRING || + tt == TOK_NUMBER || tt == TOK_LB || + tt == TOK_MUL; +} - // We have parsed |get| or |set|. Look for an accessor property - // name next. - TokenKind tt; - if (!tokenStream.peekToken(&tt)) - return null(); - if (TokenKindIsPossibleIdentifierName(tt)) { - tokenStream.consumeKnownToken(tt); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::propertyOrMethodName(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). + // + // 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. - propAtom.set(tokenStream.currentName()); - return handler.newObjectLiteralPropertyName(propAtom, pos()); - } - if (tt == TOK_STRING) { - tokenStream.consumeKnownToken(TOK_STRING); + TokenKind ltok; + if (!tokenStream.getToken(<ok)) + return null(); - propAtom.set(tokenStream.currentToken().atom()); + MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC"); - uint32_t index; - if (propAtom->isIndex(&index)) { - propAtom.set(DoubleToAtom(context, index)); - if (!propAtom.get()) - return null(); - return handler.newNumber(index, NoDecimal, pos()); - } - return stringLiteral(); - } - if (tt == TOK_NUMBER) { - tokenStream.consumeKnownToken(TOK_NUMBER); + // Accept `async` and/or `*`, indicating an async or generator method; + // or `get` or `set`, indicating an accessor. + bool isGenerator = false; + bool isAsync = false; + bool isGetter = false; + bool isSetter = false; - propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number())); - if (!propAtom.get()) - return null(); - return newNumber(tokenStream.currentToken()); + if (ltok == TOK_ASYNC) { + // `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 = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&tt)) + return null(); + if (TokenKindCanStartPropertyName(tt)) + { + isAsync = true; + tokenStream.consumeKnownToken(tt); + ltok = tt; } - if (tt == TOK_LB) { - tokenStream.consumeKnownToken(TOK_LB); + } - return computedPropertyName(yieldHandling, maybeDecl, propList); - } + if (ltok == TOK_MUL) { + isGenerator = true; + if (!tokenStream.getToken(<ok)) + return null(); + } - // Not an accessor property after all. - propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos()); - if (!propName) + if (!isAsync && !isGenerator && + (ltok == TOK_GET || ltok == TOK_SET)) { + // We have parsed |get| or |set|. Look for an accessor property + // name next. + TokenKind tt; + if (!tokenStream.peekToken(&tt)) return null(); - break; - } + if (TokenKindCanStartPropertyName(tt)) { + tokenStream.consumeKnownToken(tt); + isGetter = (ltok == TOK_GET); + isSetter = (ltok == TOK_SET); + } } + Node propName = propertyName(yieldHandling, propertyNameContext, maybeDecl, + propList, propAtom); + if (!propName) + return null(); + + // 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 == TOK_COLON) { - if (isGenerator || isAsync) { + if (isGenerator || isAsync || isGetter || isSetter) { error(JSMSG_BAD_PROP_ID); return null(); } @@ -10717,7 +10719,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, } if (propertyNameContext == PropertyNameInClass && (tt == TOK_SEMI || tt == TOK_ASSIGN)) { - if (isGenerator || isAsync) { + if (isGenerator || isAsync || isGetter || isSetter) { error(JSMSG_BAD_PROP_ID); return null(); } @@ -10729,7 +10731,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, if (TokenKindIsPossibleIdentifierName(ltok) && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { - if (isGenerator || isAsync) { + if (isGenerator || isAsync || isGetter || isSetter) { error(JSMSG_BAD_PROP_ID); return null(); } @@ -10748,6 +10750,10 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, *propType = PropertyType::GeneratorMethod; else if (isAsync) *propType = PropertyType::AsyncMethod; + else if (isGetter) + *propType = PropertyType::Getter; + else if (isSetter) + *propType = PropertyType::Setter; else *propType = PropertyType::Method; return propName; @@ -10826,7 +10832,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError* TokenPos namePos = tokenStream.nextToken().pos; PropertyType propType; - Node propName = propertyName(yieldHandling, PropertyNameInLiteral, declKind, literal, &propType, &propAtom); + Node propName = propertyOrMethodName(yieldHandling, PropertyNameInLiteral, declKind, + literal, &propType, &propAtom); if (!propName) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 5a0722afa7..f29d5aaeed 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1629,7 +1629,11 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) Node propertyName(YieldHandling yieldHandling, PropertyNameContext propertyNameContext, const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType propList, - PropertyType* propType, MutableHandleAtom propAtom); + MutableHandleAtom propAtom); + Node propertyOrMethodName(YieldHandling yieldHandling, + PropertyNameContext propertyNameContext, + const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType propList, + PropertyType* propType, MutableHandleAtom propAtom); UnaryNodeType computedPropertyName(YieldHandling yieldHandling, const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType literal); ListNodeType arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError); |