Issue #1691 - Part 13: Remove MUST_MATCH_TOKEN* macros in Parser. https://bugzilla.mozilla.org/show_bug.cgi?id=1501928 This was helpful in debugging one of the crashes, the macros made debugging a nightmare.

(cherry picked from commit 7bceec3f7dff086305c3f50939a8c830ca7f107b)
This commit is contained in:
Brian Smith 2023-04-24 06:06:27 -05:00 committed by roytam1
commit bc895eba9b
3 changed files with 284 additions and 111 deletions

View file

@ -1321,7 +1321,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
return true;
case PNK_CALL_IMPORT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->is<BinaryNode>());
*answer = true;
return true;

View file

@ -65,46 +65,6 @@ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
using BindingIter = ParseContext::Scope::BindingIter;
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
// Read a token. Report an error and return null() if that token doesn't match
// to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly.
#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport, failureValue) \
JS_BEGIN_MACRO \
TokenKind token; \
if (!tokenStream.getToken(&token, modifier)) \
return failureValue; \
if (!(cond)) { \
errorReport; \
return failureValue; \
} \
JS_END_MACRO
#define MUST_MATCH_TOKEN_MOD_OR(tt, modifier, errorNumber, failureValue) \
MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber), failureValue)
#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
MUST_MATCH_TOKEN_MOD_OR(tt, modifier, errorNumber, null())
#define MUST_MATCH_TOKEN_OR(tt, errorNumber, failureValue) \
MUST_MATCH_TOKEN_MOD_OR(tt, TokenStream::None, errorNumber, failureValue)
#define MUST_MATCH_TOKEN(tt, errorNumber) \
MUST_MATCH_TOKEN_OR(tt, errorNumber, null())
#define MUST_MATCH_TOKEN_FUNC_MOD_OR(func, modifier, errorNumber, failureValue) \
MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber), failureValue)
#define MUST_MATCH_TOKEN_FUNC_OR(func, errorNumber, failureValue) \
MUST_MATCH_TOKEN_FUNC_MOD_OR(func, TokenStream::None, errorNumber, failureValue)
#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \
MUST_MATCH_TOKEN_FUNC_OR(func, errorNumber, null())
#define MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(tt, modifier, errorReport, failureValue) \
MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport, failureValue)
#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \
MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(tt, modifier, errorReport, null())
template <class T, class U>
static inline void
PropagateTransitiveParseFlags(const T* inner, U* outer)
@ -611,6 +571,23 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
computeInWith(enclosingScope);
}
template <typename ParseHandler>
template <typename ConditionT, typename ErrorReportT>
bool
Parser<ParseHandler>::mustMatchTokenInternal(ConditionT condition, Modifier modifier,
ErrorReportT errorReport)
{
TokenKind actual;
if (!tokenStream.getToken(&actual, modifier)) {
return false;
}
if (!condition(actual)) {
errorReport(actual);
return false;
}
return true;
}
void
ParserBase::error(unsigned errorNumber, ...)
{
@ -3769,10 +3746,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
}
if (bodyType == StatementListBody) {
MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
JSMSG_CURLY_OPENED, openedPos),
false);
if (!mustMatchToken(TOK_RC, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
JSMSG_CURLY_OPENED, openedPos);
}))
{
return false;
}
funbox->setEnd(pos().end);
} else {
#if !JS_HAS_EXPR_CLOSURES
@ -4140,11 +4121,16 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::condition(InHandling inHandling, YieldHandling yieldHandling)
{
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_BEFORE_COND)) {
return null();
}
Node pn = exprInParens(inHandling, yieldHandling, TripledotProhibited);
if (!pn)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_COND)) {
return null();
}
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(pn)) {
@ -4505,9 +4491,14 @@ Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling y
}
}
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, begin));
if (!mustMatchToken(TOK_RC, TokenStream::None,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, begin);
}))
{
return null();
}
handler.setEndPosition(literal, pos().end);
return literal;
@ -4593,9 +4584,14 @@ Parser<ParseHandler>::arrayBindingPattern(DeclarationKind kind, YieldHandling yi
}
}
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin));
if (!mustMatchToken(TOK_RB, modifier,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin);
}))
{
return null();
}
handler.setEndPosition(literal, pos().end);
return literal;
@ -4652,9 +4648,13 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error
if (!list)
return null();
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
openedPos));
if (!mustMatchToken(TOK_RC, TokenStream::Operand,
[this, errorNumber, openedPos](TokenKind actual) {
this->reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED, openedPos);
}))
{
return null();
}
return finishLexicalScope(scope, list);
}
@ -4710,7 +4710,9 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
}
}
MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
if (!mustMatchToken(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL)) {
return null();
}
Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
@ -5078,9 +5080,13 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, ListNodeTy
} else {
MOZ_ASSERT(tt == TOK_MUL);
MUST_MATCH_TOKEN_OR(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR, false);
if (!mustMatchToken(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR)) {
return false;
}
MUST_MATCH_TOKEN_FUNC_OR(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME, false);
if (!mustMatchToken(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME)) {
return false;
}
NameNodeType importName = newName(context->names().star);
if (!importName)
@ -5188,9 +5194,13 @@ Parser<FullParseHandler>::importDeclaration()
return null();
}
MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_IMPORT_CLAUSE);
if (!mustMatchToken(TOK_FROM, JSMSG_FROM_AFTER_IMPORT_CLAUSE)) {
return null();
}
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
if (!mustMatchToken(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM)) {
return null();
}
}
NameNodeType moduleSpec = stringLiteral();
@ -5495,7 +5505,9 @@ Parser<ParseHandler>::exportFrom(uint32_t begin, Node specList)
if (!abortIfSyntaxParser())
return null();
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
if (!mustMatchToken(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM)) {
return null();
}
NameNodeType moduleSpec = stringLiteral();
if (!moduleSpec)
@ -5535,7 +5547,9 @@ Parser<ParseHandler>::exportBatch(uint32_t begin)
handler.addList(kid, exportSpec);
MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_EXPORT_STAR);
if (!mustMatchToken(TOK_FROM, JSMSG_FROM_AFTER_EXPORT_STAR)) {
return null();
}
return exportFrom(begin, kid);
}
@ -5600,8 +5614,11 @@ Parser<ParseHandler>::exportClause(uint32_t begin)
bool foundAs;
if (!tokenStream.matchToken(&foundAs, TOK_AS))
return null();
if (foundAs)
MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME);
if (foundAs) {
if (!mustMatchToken(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME)) {
return null();
}
}
NameNodeType exportName = newName(tokenStream.currentName());
if (!exportName)
@ -6105,7 +6122,9 @@ Parser<ParseHandler>::doWhileStatement(YieldHandling yieldHandling)
Node body = statement(yieldHandling);
if (!body)
return null();
MUST_MATCH_TOKEN_MOD(TOK_WHILE, TokenStream::Operand, JSMSG_WHILE_AFTER_DO);
if (!mustMatchToken(TOK_WHILE, TokenStream::Operand, JSMSG_WHILE_AFTER_DO)) {
return null();
}
Node cond = condition(InAllowed, yieldHandling);
if (!cond)
return null();
@ -6352,7 +6371,9 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
}
}
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_AFTER_FOR)) {
return null();
}
// PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
ParseNodeKind headKind;
@ -6408,7 +6429,9 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
// Look for an operand: |for (;| means we might have already examined
// this semicolon with that modifier.
MUST_MATCH_TOKEN_MOD(TOK_SEMI, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_INIT);
if (!mustMatchToken(TOK_SEMI, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_INIT)) {
return null();
}
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
@ -6426,7 +6449,9 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
mod = TokenStream::None;
}
MUST_MATCH_TOKEN_MOD(TOK_SEMI, mod, JSMSG_SEMI_AFTER_FOR_COND);
if (!mustMatchToken(TOK_SEMI, mod, JSMSG_SEMI_AFTER_FOR_COND)) {
return null();
}
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
@ -6442,7 +6467,9 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
mod = TokenStream::None;
}
MUST_MATCH_TOKEN_MOD(TOK_RP, mod, JSMSG_PAREN_AFTER_FOR_CTRL);
if (!mustMatchToken(TOK_RP, mod, JSMSG_PAREN_AFTER_FOR_CTRL)) {
return null();
}
TokenPos headPos(begin, pos().end);
forHead = handler.newForHead(init, test, update, headPos);
@ -6472,7 +6499,9 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
// Parser::declaration consumed everything up to the closing ')'. That
// token follows an {Assignment,}Expression, so the next token must be
// consumed as if an operator continued the expression, i.e. as None.
MUST_MATCH_TOKEN_MOD(TOK_RP, TokenStream::None, JSMSG_PAREN_AFTER_FOR_CTRL);
if (!mustMatchToken(TOK_RP, TokenStream::None, JSMSG_PAREN_AFTER_FOR_CTRL)) {
return null();
}
TokenPos headPos(begin, pos().end);
forHead = handler.newForInOrOfHead(headKind, target, iteratedExpr, headPos);
@ -6501,14 +6530,20 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_SWITCH));
uint32_t begin = pos().begin;
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH)) {
return null();
}
Node discriminant = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
if (!discriminant)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_SWITCH)) {
return null();
}
if (!mustMatchToken(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH)) {
return null();
}
ParseContext::Statement stmt(pc, StatementKind::Switch);
ParseContext::Scope scope(this);
@ -6550,7 +6585,9 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
return null();
}
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
if (!mustMatchToken(TOK_COLON, JSMSG_COLON_AFTER_CASE)) {
return null();
}
ListNodeType body = handler.newStatementList(pos());
if (!body)
@ -6904,11 +6941,15 @@ Parser<ParseHandler>::withStatement(YieldHandling yieldHandling)
return null();
}
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_BEFORE_WITH)) {
return null();
}
Node objectExpr = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
if (!objectExpr)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_WITH)) {
return null();
}
Node innerBlock;
{
@ -7045,7 +7086,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
LexicalScopeNodeType innerBlock;
{
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
if (!mustMatchToken(TOK_LC, JSMSG_CURLY_BEFORE_TRY)) {
return null();
}
uint32_t openedPos = pos().begin;
@ -7062,9 +7105,14 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!innerBlock)
return null();
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
JSMSG_CURLY_OPENED, openedPos));
if (!mustMatchToken(TOK_RC, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
JSMSG_CURLY_OPENED, openedPos);
}))
{
return null();
}
}
bool hasUnconditionalCatch = false;
@ -7111,7 +7159,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (omittedBinding) {
catchName = null();
} else {
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_BEFORE_CATCH)) {
return null();
}
if (!tokenStream.getToken(&tt))
return null();
@ -7153,9 +7203,13 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
return null();
}
#endif
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_CATCH)) {
return null();
}
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
if (!mustMatchToken(TOK_LC, JSMSG_CURLY_BEFORE_CATCH)) {
return null();
}
}
LexicalScopeNodeType catchBody = catchBlockStatement(yieldHandling, scope);
@ -7182,7 +7236,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
LexicalScopeNodeType finallyBlock = null();
if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
if (!mustMatchToken(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY)) {
return null();
}
uint32_t openedPos = pos().begin;
@ -7199,9 +7255,15 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!finallyBlock)
return null();
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
JSMSG_CURLY_OPENED, openedPos));
if (!mustMatchToken(TOK_RC, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
JSMSG_CURLY_OPENED, openedPos);
}))
{
return null();
}
} else {
tokenStream.ungetToken();
}
@ -7239,9 +7301,14 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
if (!list)
return null();
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
JSMSG_CURLY_OPENED, openedPos));
if (!mustMatchToken(TOK_RC, TokenStream::Operand,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
JSMSG_CURLY_OPENED, openedPos);
}))
{
return null();
}
// The catch parameter names are not bound in the body scope, so remove
// them before generating bindings.
@ -7356,7 +7423,9 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS);
if (!mustMatchToken(TOK_LC, JSMSG_CURLY_BEFORE_CLASS)) {
return null();
}
ListNodeType classMethods = handler.newClassMethodList(pos().begin);
if (!classMethods)
@ -8270,7 +8339,9 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
if (!thenExpr)
return null();
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
if (!mustMatchToken(TOK_COLON, JSMSG_COLON_IN_COND)) {
return null();
}
Node elseExpr = assignExpr(inHandling, yieldHandling, TripledotProhibited);
if (!elseExpr)
@ -8900,7 +8971,9 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
if (!comp)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_IN_PAREN)) {
return null();
}
uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
@ -8941,11 +9014,15 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
uint32_t begin = pos().begin;
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_AFTER_FOR)) {
return null();
}
// FIXME: Destructuring binding (bug 980828).
MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME);
if (!mustMatchToken(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME)) {
return null();
}
RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword));
if (!name)
return null();
@ -8969,7 +9046,9 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
if (!rhs)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_OF_ITERABLE);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_FOR_OF_ITERABLE)) {
return null();
}
TokenPos headPos(begin, pos().end);
@ -9014,11 +9093,15 @@ Parser<ParseHandler>::comprehensionIf(GeneratorKind comprehensionKind)
uint32_t begin = pos().begin;
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
if (!mustMatchToken(TOK_LP, JSMSG_PAREN_BEFORE_COND)) {
return null();
}
Node cond = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited);
if (!cond)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_COND)) {
return null();
}
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(cond)) {
@ -9098,7 +9181,9 @@ Parser<ParseHandler>::arrayComprehension(uint32_t begin)
if (!inner)
return null();
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
if (!mustMatchToken(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION)) {
return null();
}
ListNodeType comp = handler.newList(PNK_ARRAYCOMP, inner);
if (!comp)
@ -9216,7 +9301,9 @@ Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, bool* isSpread,
}
}
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_ARGS)) {
return null();
}
handler.setEndPosition(argsList, pos().end);
return argsList;
@ -9449,7 +9536,9 @@ Parser<ParseHandler>::memberElemAccess(
return null();
}
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
if (!mustMatchToken(TOK_RB, JSMSG_BRACKET_IN_INDEX)) {
return null();
}
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
error(JSMSG_BAD_SUPERPROP, "member");
@ -9923,9 +10012,14 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
}
}
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin));
if (!mustMatchToken(TOK_RB, modifier,
[this, begin](TokenKind actual) {
this->reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin);
}))
{
return null();
}
}
handler.setEndPosition(literal, pos().end);
return literal;
@ -10150,7 +10244,9 @@ Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling,
if (!assignNode)
return null();
MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
if (!mustMatchToken(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR)) {
return null();
}
return handler.newComputedName(assignNode, begin, pos().end);
}
@ -10362,9 +10458,14 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
}
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, openedPos));
if (!mustMatchToken(TOK_RC, TokenStream::None,
[this, openedPos](TokenKind actual) {
this->reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, openedPos);
}))
{
return null();
}
handler.setEndPosition(literal, pos().end);
return literal;
@ -10513,7 +10614,9 @@ Parser<ParseHandler>::importExpr(YieldHandling yieldHandling)
if (!arg)
return null();
MUST_MATCH_TOKEN_MOD(TOK_RP, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_AFTER_ARGS)) {
return null();
}
if (!context->compartment()->runtimeFromAnyThread()->moduleDynamicImportHook && !abortIfSyntaxParser()) {
return null();
@ -10581,7 +10684,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
Node expr = exprInParens(InAllowed, yieldHandling, TripledotAllowed, possibleError);
if (!expr)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
if (!mustMatchToken(TOK_RP, JSMSG_PAREN_IN_PAREN)) {
return null();
}
return handler.parenthesize(expr);
}

View file

@ -21,6 +21,7 @@
#include "frontend/NameCollections.h"
#include "frontend/SharedContext.h"
#include "frontend/SyntaxParseHandler.h"
#include "frontend/TokenStream.h"
namespace js {
@ -906,6 +907,8 @@ class ParserBase : public StrictModeGetter
template <typename ParseHandler>
class Parser final : public ParserBase, private JS::AutoGCRooter
{
protected:
using Modifier = TokenStream::Modifier;
private:
using Node = typename ParseHandler::Node;
@ -1086,6 +1089,71 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
*/
ListNodeType parse();
private:
/*
* Gets the next token and checks if it matches to the given `condition`.
* If it matches, returns true.
* If it doesn't match, calls `errorReport` to report the error, and
* returns false.
* If other error happens, it returns false but `errorReport` may not be
* called and other error will be thrown in that case.
*
* In any case, the already gotten token is not ungotten.
*
* The signature of `condition` is [...](TokenKind actual) -> bool, and
* the signature of `errorReport` is [...](TokenKind actual).
*/
template<typename ConditionT, typename ErrorReportT>
MOZ_MUST_USE bool mustMatchTokenInternal(ConditionT condition, Modifier modifier,
ErrorReportT errorReport);
public:
/*
* The following mustMatchToken variants follow the behavior and parameter
* types of mustMatchTokenInternal above.
*
* If modifier is omitted, `None` is used.
* If TokenKind is passed instead of `condition`, it checks if the next
* token is the passed token.
* If error number is passed instead of `errorReport`, it reports an
* error with the passed errorNumber.
*/
MOZ_MUST_USE bool mustMatchToken(TokenKind expected, Modifier modifier, JSErrNum errorNumber) {
return mustMatchTokenInternal([expected](TokenKind actual) {
return actual == expected;
},
modifier,
[this, errorNumber](TokenKind) {
this->error(errorNumber);
});
}
MOZ_MUST_USE bool mustMatchToken(TokenKind excpected, JSErrNum errorNumber) {
return mustMatchToken(excpected, TokenStream::None, errorNumber);
}
template<typename ConditionT>
MOZ_MUST_USE bool mustMatchToken(ConditionT condition, JSErrNum errorNumber) {
return mustMatchTokenInternal(condition, TokenStream::None,
[this, errorNumber](TokenKind) {
this->error(errorNumber);
});
}
template<typename ErrorReportT>
MOZ_MUST_USE bool mustMatchToken(TokenKind expected, Modifier modifier,
ErrorReportT errorReport) {
return mustMatchTokenInternal([expected](TokenKind actual) {
return actual == expected;
},
modifier, errorReport);
}
template<typename ErrorReportT>
MOZ_MUST_USE bool mustMatchToken(TokenKind expected, ErrorReportT errorReport) {
return mustMatchToken(expected, TokenStream::None, errorReport);
}
/*
* Allocate a new parsed object or function container from
* cx->tempLifoAlloc.