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; return true;
case PNK_CALL_IMPORT: case PNK_CALL_IMPORT:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->is<BinaryNode>());
*answer = true; *answer = true;
return true; return true;

View file

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

View file

@ -21,6 +21,7 @@
#include "frontend/NameCollections.h" #include "frontend/NameCollections.h"
#include "frontend/SharedContext.h" #include "frontend/SharedContext.h"
#include "frontend/SyntaxParseHandler.h" #include "frontend/SyntaxParseHandler.h"
#include "frontend/TokenStream.h"
namespace js { namespace js {
@ -906,6 +907,8 @@ class ParserBase : public StrictModeGetter
template <typename ParseHandler> template <typename ParseHandler>
class Parser final : public ParserBase, private JS::AutoGCRooter class Parser final : public ParserBase, private JS::AutoGCRooter
{ {
protected:
using Modifier = TokenStream::Modifier;
private: private:
using Node = typename ParseHandler::Node; using Node = typename ParseHandler::Node;
@ -1086,6 +1089,71 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
*/ */
ListNodeType parse(); 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 * Allocate a new parsed object or function container from
* cx->tempLifoAlloc. * cx->tempLifoAlloc.