From bc895eba9bc36760c20de0016ab847168a1295c6 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 24 Apr 2023 06:06:27 -0500 Subject: [PATCH] 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) --- js/src/frontend/BytecodeEmitter.cpp | 2 +- js/src/frontend/Parser.cpp | 325 ++++++++++++++++++---------- js/src/frontend/Parser.h | 68 ++++++ 3 files changed, 284 insertions(+), 111 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index a6c7db32a8..78b134cf58 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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()); *answer = true; return true; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1a5d36e104..f012823a5e 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -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 static inline void PropagateTransitiveParseFlags(const T* inner, U* outer) @@ -611,6 +571,23 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } +template +template +bool +Parser::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::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::Node Parser::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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::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); } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8eb6a2f21b..44f4aaf108 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -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 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 + 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 + MOZ_MUST_USE bool mustMatchToken(ConditionT condition, JSErrNum errorNumber) { + return mustMatchTokenInternal(condition, TokenStream::None, + [this, errorNumber](TokenKind) { + this->error(errorNumber); + }); + } + + template + MOZ_MUST_USE bool mustMatchToken(TokenKind expected, Modifier modifier, + ErrorReportT errorReport) { + return mustMatchTokenInternal([expected](TokenKind actual) { + return actual == expected; + }, + modifier, errorReport); + } + + template + 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.