diff options
Diffstat (limited to 'js/src/frontend/SyntaxParseHandler.h')
-rw-r--r-- | js/src/frontend/SyntaxParseHandler.h | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h new file mode 100644 index 0000000000..aa06eaa246 --- /dev/null +++ b/js/src/frontend/SyntaxParseHandler.h @@ -0,0 +1,825 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef frontend_SyntaxParseHandler_h +#define frontend_SyntaxParseHandler_h + +#include "mozilla/Assertions.h" +#include "mozilla/Maybe.h" // mozilla::Maybe +#include "mozilla/Result.h" // mozilla::Result, mozilla::UnusedZero + +#include <string.h> + +#include "jstypes.h" + +#include "frontend/CompilationStencil.h" // CompilationState +#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind +#include "frontend/NameAnalysisTypes.h" // PrivateNameKind +#include "frontend/ParseNode.h" +#include "frontend/ParserAtom.h" // TaggedParserAtomIndex +#include "frontend/TokenStream.h" + +namespace js { +namespace frontend { +enum SyntaxParseHandlerNode { + NodeFailure = 0, + NodeGeneric, + NodeGetProp, + NodeStringExprStatement, + NodeReturn, + NodeBreak, + NodeThrow, + NodeEmptyStatement, + + NodeVarDeclaration, + NodeLexicalDeclaration, + + // A non-arrow function expression with block body, from bog-standard + // ECMAScript. + NodeFunctionExpression, + + NodeFunctionArrow, + NodeFunctionStatement, + + // This is needed for proper assignment-target handling. ES6 formally + // requires function calls *not* pass IsValidSimpleAssignmentTarget, + // but at last check there were still sites with |f() = 5| and similar + // in code not actually executed (or at least not executed enough to be + // noticed). + NodeFunctionCall, + + NodeOptionalFunctionCall, + + // Node representing normal names which don't require any special + // casing. + NodeName, + + // Nodes representing the names "arguments" and "eval". + NodeArgumentsName, + NodeEvalName, + + // Node representing the "async" name, which may actually be a + // contextual keyword. + NodePotentialAsyncKeyword, + + // Node representing private names. + NodePrivateName, + + NodeDottedProperty, + NodeOptionalDottedProperty, + NodeElement, + NodeOptionalElement, + // A distinct node for [PrivateName], to make detecting delete this.#x + // detectable in syntax parse + NodePrivateMemberAccess, + NodeOptionalPrivateMemberAccess, + + // Destructuring target patterns can't be parenthesized: |([a]) = [3];| + // must be a syntax error. (We can't use NodeGeneric instead of these + // because that would trigger invalid-left-hand-side ReferenceError + // semantics when SyntaxError semantics are desired.) + NodeParenthesizedArray, + NodeParenthesizedObject, + + // In rare cases a parenthesized |node| doesn't have the same semantics + // as |node|. Each such node has a special Node value, and we use a + // different Node value to represent the parenthesized form. See also + // is{Unp,P}arenthesized*(Node), parenthesize(Node), and the various + // functions that deal in NodeUnparenthesized* below. + + // Valuable for recognizing potential destructuring patterns. + NodeUnparenthesizedArray, + NodeUnparenthesizedObject, + + // The directive prologue at the start of a FunctionBody or ScriptBody + // is the longest sequence (possibly empty) of string literal + // expression statements at the start of a function. Thus we need this + // to treat |"use strict";| as a possible Use Strict Directive and + // |("use strict");| as a useless statement. + NodeUnparenthesizedString, + + // For destructuring patterns an assignment element with + // an initializer expression is not allowed be parenthesized. + // i.e. |{x = 1} = obj| + NodeUnparenthesizedAssignment, + + // This node is necessary to determine if the base operand in an + // exponentiation operation is an unparenthesized unary expression. + // We want to reject |-2 ** 3|, but still need to allow |(-2) ** 3|. + NodeUnparenthesizedUnary, + + // This node is necessary to determine if the LHS of a property access is + // super related. + NodeSuperBase +}; + +} // namespace frontend +} // namespace js + +template <> +struct mozilla::detail::UnusedZero<js::frontend::SyntaxParseHandlerNode> { + static const bool value = true; +}; + +namespace js { +namespace frontend { + +// Parse handler used when processing the syntax in a block of code, to generate +// the minimal information which is required to detect syntax errors and allow +// bytecode to be emitted for outer functions. +// +// When parsing, we start at the top level with a full parse, and when possible +// only check the syntax for inner functions, so that they can be lazily parsed +// into bytecode when/if they first run. Checking the syntax of a function is +// several times faster than doing a full parse/emit, and lazy parsing improves +// both performance and memory usage significantly when pages contain large +// amounts of code that never executes (which happens often). +class SyntaxParseHandler { + // Remember the last encountered name or string literal during syntax parses. + TaggedParserAtomIndex lastAtom; + TokenPos lastStringPos; + + public: + struct NodeError {}; + + using Node = SyntaxParseHandlerNode; + + using NodeResult = mozilla::Result<Node, NodeError>; + using NodeErrorResult = mozilla::GenericErrorResult<NodeError>; + +#define DECLARE_TYPE(typeName) \ + using typeName##Type = Node; \ + using typeName##Result = mozilla::Result<Node, NodeError>; + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + + using NullNode = Node; + + bool isNonArrowFunctionExpression(Node node) const { + return node == NodeFunctionExpression; + } + + bool isPropertyOrPrivateMemberAccess(Node node) { + return node == NodeDottedProperty || node == NodeElement || + node == NodePrivateMemberAccess; + } + + bool isOptionalPropertyOrPrivateMemberAccess(Node node) { + return node == NodeOptionalDottedProperty || node == NodeOptionalElement || + node == NodeOptionalPrivateMemberAccess; + } + + bool isFunctionCall(Node node) { + // Note: super() is a special form, *not* a function call. + return node == NodeFunctionCall; + } + + static bool isUnparenthesizedDestructuringPattern(Node node) { + return node == NodeUnparenthesizedArray || + node == NodeUnparenthesizedObject; + } + + static bool isParenthesizedDestructuringPattern(Node node) { + // Technically this isn't a destructuring target at all -- the grammar + // doesn't treat it as such. But we need to know when this happens to + // consider it a SyntaxError rather than an invalid-left-hand-side + // ReferenceError. + return node == NodeParenthesizedArray || node == NodeParenthesizedObject; + } + + public: + SyntaxParseHandler(FrontendContext* fc, CompilationState& compilationState) { + MOZ_ASSERT(!compilationState.input.isDelazifying()); + } + + static NullNode null() { return NodeFailure; } + static constexpr NodeErrorResult errorResult() { + return NodeErrorResult(NodeError()); + } + +#define DECLARE_AS(typeName) \ + static typeName##Type as##typeName(Node node) { return node; } + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) +#undef DECLARE_AS + + NameNodeResult newName(TaggedParserAtomIndex name, const TokenPos& pos) { + lastAtom = name; + if (name == TaggedParserAtomIndex::WellKnown::arguments()) { + return NodeArgumentsName; + } + if (pos.begin + strlen("async") == pos.end && + name == TaggedParserAtomIndex::WellKnown::async()) { + return NodePotentialAsyncKeyword; + } + if (name == TaggedParserAtomIndex::WellKnown::eval()) { + return NodeEvalName; + } + return NodeName; + } + + UnaryNodeResult newComputedName(Node expr, uint32_t start, uint32_t end) { + return NodeGeneric; + } + + UnaryNodeResult newSyntheticComputedName(Node expr, uint32_t start, + uint32_t end) { + return NodeGeneric; + } + + NameNodeResult newObjectLiteralPropertyName(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return NodeName; + } + + NameNodeResult newPrivateName(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return NodePrivateName; + } + + NumericLiteralResult newNumber(double value, DecimalPoint decimalPoint, + const TokenPos& pos) { + return NodeGeneric; + } + + BigIntLiteralResult newBigInt() { return NodeGeneric; } + + BooleanLiteralResult newBooleanLiteral(bool cond, const TokenPos& pos) { + return NodeGeneric; + } + + NameNodeResult newStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + lastAtom = atom; + lastStringPos = pos; + return NodeUnparenthesizedString; + } + + NameNodeResult newTemplateStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return NodeGeneric; + } + + CallSiteNodeResult newCallSiteObject(uint32_t begin) { return NodeGeneric; } + + void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode, + Node cookedNode) {} + + ThisLiteralResult newThisLiteral(const TokenPos& pos, Node thisName) { + return NodeGeneric; + } + NullLiteralResult newNullLiteral(const TokenPos& pos) { return NodeGeneric; } + RawUndefinedLiteralResult newRawUndefinedLiteral(const TokenPos& pos) { + return NodeGeneric; + } + + RegExpLiteralResult newRegExp(Node reobj, const TokenPos& pos) { + return NodeGeneric; + } + + ConditionalExpressionResult newConditional(Node cond, Node thenExpr, + Node elseExpr) { + return NodeGeneric; + } + + UnaryNodeResult newDelete(uint32_t begin, Node expr) { + return NodeUnparenthesizedUnary; + } + + UnaryNodeResult newTypeof(uint32_t begin, Node kid) { + return NodeUnparenthesizedUnary; + } + + UnaryNodeResult newUnary(ParseNodeKind kind, uint32_t begin, Node kid) { + return NodeUnparenthesizedUnary; + } + + UnaryNodeResult newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) { + return NodeGeneric; + } + + UnaryNodeResult newSpread(uint32_t begin, Node kid) { return NodeGeneric; } + + NodeResult appendOrCreateList(ParseNodeKind kind, Node left, Node right, + ParseContext* pc) { + return NodeGeneric; + } + + // Expressions + + ListNodeResult newArrayLiteral(uint32_t begin) { + return NodeUnparenthesizedArray; + } + [[nodiscard]] bool addElision(ListNodeType literal, const TokenPos& pos) { + return true; + } + [[nodiscard]] bool addSpreadElement(ListNodeType literal, uint32_t begin, + Node inner) { + return true; + } + void addArrayElement(ListNodeType literal, Node element) {} + + ListNodeResult newArguments(const TokenPos& pos) { return NodeGeneric; } + CallNodeResult newCall(Node callee, ListNodeType args, JSOp callOp) { + return NodeFunctionCall; + } + + CallNodeResult newOptionalCall(Node callee, ListNodeType args, JSOp callOp) { + return NodeOptionalFunctionCall; + } + + CallNodeResult newSuperCall(Node callee, ListNodeType args, bool isSpread) { + return NodeGeneric; + } + CallNodeResult newTaggedTemplate(Node tag, ListNodeType args, JSOp callOp) { + return NodeGeneric; + } + + ListNodeResult newObjectLiteral(uint32_t begin) { + return NodeUnparenthesizedObject; + } + +#ifdef ENABLE_RECORD_TUPLE + ListNodeResult newRecordLiteral(uint32_t begin) { return NodeGeneric; } + + ListNodeResult newTupleLiteral(uint32_t begin) { return NodeGeneric; } +#endif + + ListNodeResult newClassMemberList(uint32_t begin) { return NodeGeneric; } + ClassNamesResult newClassNames(Node outer, Node inner, const TokenPos& pos) { + return NodeGeneric; + } + ClassNodeResult newClass(Node name, Node heritage, Node methodBlock, +#ifdef ENABLE_DECORATORS + ListNodeType decorators, + FunctionNodeType addInitializerFunction, +#endif + const TokenPos& pos) { + return NodeGeneric; + } + + LexicalScopeNodeResult newLexicalScope(Node body) { + return NodeLexicalDeclaration; + } + + ClassBodyScopeNodeResult newClassBodyScope(Node body) { + return NodeLexicalDeclaration; + } + + NewTargetNodeResult newNewTarget(NullaryNodeType newHolder, + NullaryNodeType targetHolder, + NameNodeType newTargetName) { + return NodeGeneric; + } + NullaryNodeResult newPosHolder(const TokenPos& pos) { return NodeGeneric; } + UnaryNodeResult newSuperBase(Node thisName, const TokenPos& pos) { + return NodeSuperBase; + } + + [[nodiscard]] bool addPrototypeMutation(ListNodeType literal, uint32_t begin, + Node expr) { + return true; + } + BinaryNodeResult newPropertyDefinition(Node key, Node val) { + return NodeGeneric; + } + void addPropertyDefinition(ListNodeType literal, BinaryNodeType propdef) {} + [[nodiscard]] bool addPropertyDefinition(ListNodeType literal, Node key, + Node expr) { + return true; + } + [[nodiscard]] bool addShorthand(ListNodeType literal, NameNodeType name, + NameNodeType expr) { + return true; + } + [[nodiscard]] bool addSpreadProperty(ListNodeType literal, uint32_t begin, + Node inner) { + return true; + } + [[nodiscard]] bool addObjectMethodDefinition(ListNodeType literal, Node key, + FunctionNodeType funNode, + AccessorType atype) { + return true; + } + [[nodiscard]] NodeResult newDefaultClassConstructor( + Node key, FunctionNodeType funNode) { + return NodeGeneric; + } + [[nodiscard]] NodeResult newClassMethodDefinition( + Node key, FunctionNodeType funNode, AccessorType atype, bool isStatic, + mozilla::Maybe<FunctionNodeType> initializerIfPrivate +#ifdef ENABLE_DECORATORS + , + ListNodeType decorators +#endif + ) { + return NodeGeneric; + } + [[nodiscard]] NodeResult newClassFieldDefinition( + Node name, FunctionNodeType initializer, bool isStatic +#ifdef ENABLE_DECORATORS + , + ListNodeType decorators, ClassMethodType accessorGetterNode, + ClassMethodType accessorSetterNode +#endif + ) { + return NodeGeneric; + } + + [[nodiscard]] NodeResult newStaticClassBlock(FunctionNodeType block) { + return NodeGeneric; + } + + [[nodiscard]] bool addClassMemberDefinition(ListNodeType memberList, + Node member) { + return true; + } + UnaryNodeResult newYieldExpression(uint32_t begin, Node value) { + return NodeGeneric; + } + UnaryNodeResult newYieldStarExpression(uint32_t begin, Node value) { + return NodeGeneric; + } + UnaryNodeResult newAwaitExpression(uint32_t begin, Node value) { + return NodeUnparenthesizedUnary; + } + UnaryNodeResult newOptionalChain(uint32_t begin, Node value) { + return NodeGeneric; + } + + // Statements + + ListNodeResult newStatementList(const TokenPos& pos) { return NodeGeneric; } + void addStatementToList(ListNodeType list, Node stmt) {} + void setListEndPosition(ListNodeType list, const TokenPos& pos) {} + void addCaseStatementToList(ListNodeType list, CaseClauseType caseClause) {} + [[nodiscard]] bool prependInitialYield(ListNodeType stmtList, Node genName) { + return true; + } + NullaryNodeResult newEmptyStatement(const TokenPos& pos) { + return NodeEmptyStatement; + } + + BinaryNodeResult newImportAttribute(Node keyNode, Node valueNode) { + return NodeGeneric; + } + BinaryNodeResult newModuleRequest(Node moduleSpec, Node importAttributeList, + const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newImportDeclaration(Node importSpecSet, Node moduleRequest, + const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newImportSpec(Node importNameNode, Node bindingName) { + return NodeGeneric; + } + UnaryNodeResult newImportNamespaceSpec(uint32_t begin, Node bindingName) { + return NodeGeneric; + } + UnaryNodeResult newExportDeclaration(Node kid, const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newExportFromDeclaration(uint32_t begin, Node exportSpecSet, + Node moduleRequest) { + return NodeGeneric; + } + BinaryNodeResult newExportDefaultDeclaration(Node kid, Node maybeBinding, + const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newExportSpec(Node bindingName, Node exportName) { + return NodeGeneric; + } + UnaryNodeResult newExportNamespaceSpec(uint32_t begin, Node exportName) { + return NodeGeneric; + } + NullaryNodeResult newExportBatchSpec(const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newImportMeta(NullaryNodeType importHolder, + NullaryNodeType metaHolder) { + return NodeGeneric; + } + BinaryNodeResult newCallImport(NullaryNodeType importHolder, Node singleArg) { + return NodeGeneric; + } + BinaryNodeResult newCallImportSpec(Node specifierArg, Node optionalArg) { + return NodeGeneric; + } + + BinaryNodeResult newSetThis(Node thisName, Node value) { return value; } + + UnaryNodeResult newExprStatement(Node expr, uint32_t end) { + return expr == NodeUnparenthesizedString ? NodeStringExprStatement + : NodeGeneric; + } + + TernaryNodeResult newIfStatement(uint32_t begin, Node cond, Node thenBranch, + Node elseBranch) { + return NodeGeneric; + } + BinaryNodeResult newDoWhileStatement(Node body, Node cond, + const TokenPos& pos) { + return NodeGeneric; + } + BinaryNodeResult newWhileStatement(uint32_t begin, Node cond, Node body) { + return NodeGeneric; + } + SwitchStatementResult newSwitchStatement( + uint32_t begin, Node discriminant, + LexicalScopeNodeType lexicalForCaseList, bool hasDefault) { + return NodeGeneric; + } + CaseClauseResult newCaseOrDefault(uint32_t begin, Node expr, Node body) { + return NodeGeneric; + } + ContinueStatementResult newContinueStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return NodeGeneric; + } + BreakStatementResult newBreakStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return NodeBreak; + } + UnaryNodeResult newReturnStatement(Node expr, const TokenPos& pos) { + return NodeReturn; + } + UnaryNodeResult newExpressionBody(Node expr) { return NodeReturn; } + BinaryNodeResult newWithStatement(uint32_t begin, Node expr, Node body) { + return NodeGeneric; + } + + LabeledStatementResult newLabeledStatement(TaggedParserAtomIndex label, + Node stmt, uint32_t begin) { + return NodeGeneric; + } + + UnaryNodeResult newThrowStatement(Node expr, const TokenPos& pos) { + return NodeThrow; + } + TernaryNodeResult newTryStatement(uint32_t begin, Node body, + LexicalScopeNodeType catchScope, + Node finallyBlock) { + return NodeGeneric; + } + DebuggerStatementResult newDebuggerStatement(const TokenPos& pos) { + return NodeGeneric; + } + + NameNodeResult newPropertyName(TaggedParserAtomIndex name, + const TokenPos& pos) { + lastAtom = name; + return NodeGeneric; + } + + PropertyAccessResult newPropertyAccess(Node expr, NameNodeType key) { + return NodeDottedProperty; + } + + PropertyAccessResult newOptionalPropertyAccess(Node expr, NameNodeType key) { + return NodeOptionalDottedProperty; + } + + PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) { + MOZ_ASSERT(!isPrivateName(index)); + return NodeElement; + } + + PropertyByValueResult newOptionalPropertyByValue(Node lhs, Node index, + uint32_t end) { + return NodeOptionalElement; + } + + PrivateMemberAccessResult newPrivateMemberAccess(Node lhs, Node privateName, + uint32_t end) { + return NodePrivateMemberAccess; + } + + PrivateMemberAccessResult newOptionalPrivateMemberAccess(Node lhs, + Node privateName, + uint32_t end) { + return NodeOptionalPrivateMemberAccess; + } + + [[nodiscard]] bool setupCatchScope(LexicalScopeNodeType lexicalScope, + Node catchName, Node catchBody) { + return true; + } + + [[nodiscard]] bool setLastFunctionFormalParameterDefault( + FunctionNodeType funNode, Node defaultValue) { + return true; + } + + void checkAndSetIsDirectRHSAnonFunction(Node pn) {} + + ParamsBodyNodeResult newParamsBody(const TokenPos& pos) { + return NodeGeneric; + } + + FunctionNodeResult newFunction(FunctionSyntaxKind syntaxKind, + const TokenPos& pos) { + switch (syntaxKind) { + case FunctionSyntaxKind::Statement: + return NodeFunctionStatement; + case FunctionSyntaxKind::Arrow: + return NodeFunctionArrow; + default: + // All non-arrow function expressions are initially presumed to have + // block body. This will be overridden later *if* the function + // expression permissibly has an AssignmentExpression body. + return NodeFunctionExpression; + } + } + + void setFunctionFormalParametersAndBody(FunctionNodeType funNode, + ParamsBodyNodeType paramsBody) {} + void setFunctionBody(FunctionNodeType funNode, LexicalScopeNodeType body) {} + void setFunctionBox(FunctionNodeType funNode, FunctionBox* funbox) {} + void addFunctionFormalParameter(FunctionNodeType funNode, Node argpn) {} + + ForNodeResult newForStatement(uint32_t begin, TernaryNodeType forHead, + Node body, unsigned iflags) { + return NodeGeneric; + } + + TernaryNodeResult newForHead(Node init, Node test, Node update, + const TokenPos& pos) { + return NodeGeneric; + } + + TernaryNodeResult newForInOrOfHead(ParseNodeKind kind, Node target, + Node iteratedExpr, const TokenPos& pos) { + return NodeGeneric; + } + + AssignmentNodeResult finishInitializerAssignment(NameNodeType nameNode, + Node init) { + return NodeUnparenthesizedAssignment; + } + + void setBeginPosition(Node pn, Node oth) {} + void setBeginPosition(Node pn, uint32_t begin) {} + + void setEndPosition(Node pn, Node oth) {} + void setEndPosition(Node pn, uint32_t end) {} + + uint32_t getFunctionNameOffset(Node func, TokenStreamAnyChars& ts) { + // XXX This offset isn't relevant to the offending function name. But + // we may not *have* that function name around, because of how lazy + // parsing works -- the actual name could be outside + // |tokenStream.userbuf|'s observed region. So the current offset + // is the best we can do. + return ts.currentToken().pos.begin; + } + + ListNodeResult newList(ParseNodeKind kind, const TokenPos& pos) { + MOZ_ASSERT(kind != ParseNodeKind::VarStmt); + MOZ_ASSERT(kind != ParseNodeKind::LetDecl); + MOZ_ASSERT(kind != ParseNodeKind::ConstDecl); + MOZ_ASSERT(kind != ParseNodeKind::ParamsBody); + return NodeGeneric; + } + + ListNodeResult newList(ParseNodeKind kind, Node kid) { + return newList(kind, TokenPos()); + } + + DeclarationListNodeResult newDeclarationList(ParseNodeKind kind, + const TokenPos& pos) { + if (kind == ParseNodeKind::VarStmt) { + return NodeVarDeclaration; + } + MOZ_ASSERT(kind == ParseNodeKind::LetDecl || + kind == ParseNodeKind::ConstDecl); + return NodeLexicalDeclaration; + } + + ListNodeResult newCommaExpressionList(Node kid) { return NodeGeneric; } + + void addList(ListNodeType list, Node kid) { + MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedArray || + list == NodeUnparenthesizedObject || + list == NodeVarDeclaration || list == NodeLexicalDeclaration || + list == NodeFunctionCall); + } + + CallNodeResult newNewExpression(uint32_t begin, Node ctor, ListNodeType args, + bool isSpread) { + return NodeGeneric; + } + + AssignmentNodeResult newAssignment(ParseNodeKind kind, Node lhs, Node rhs) { + return kind == ParseNodeKind::AssignExpr ? NodeUnparenthesizedAssignment + : NodeGeneric; + } + + AssignmentNodeResult newInitExpr(Node lhs, Node rhs) { return NodeGeneric; } + + bool isUnparenthesizedAssignment(Node node) { + return node == NodeUnparenthesizedAssignment; + } + + bool isUnparenthesizedUnaryExpression(Node node) { + return node == NodeUnparenthesizedUnary; + } + + bool isReturnStatement(Node node) { return node == NodeReturn; } + + bool isStatementPermittedAfterReturnStatement(Node pn) { + return pn == NodeFunctionStatement || isNonArrowFunctionExpression(pn) || + pn == NodeVarDeclaration || pn == NodeBreak || pn == NodeThrow || + pn == NodeEmptyStatement; + } + + bool isSuperBase(Node pn) { return pn == NodeSuperBase; } + + void setListHasNonConstInitializer(ListNodeType literal) {} + + // NOTE: This is infallible. + [[nodiscard]] Node parenthesize(Node node) { + // A number of nodes have different behavior upon parenthesization, but + // only in some circumstances. Convert these nodes to special + // parenthesized forms. + if (node == NodeUnparenthesizedArray) { + return NodeParenthesizedArray; + } + if (node == NodeUnparenthesizedObject) { + return NodeParenthesizedObject; + } + + // Other nodes need not be recognizable after parenthesization; convert + // them to a generic node. + if (node == NodeUnparenthesizedString || + node == NodeUnparenthesizedAssignment || + node == NodeUnparenthesizedUnary) { + return NodeGeneric; + } + + // Convert parenthesized |async| to a normal name node. + if (node == NodePotentialAsyncKeyword) { + return NodeName; + } + + // In all other cases, the parenthesized form of |node| is equivalent + // to the unparenthesized form: return |node| unchanged. + return node; + } + + // NOTE: This is infallible. + template <typename NodeType> + [[nodiscard]] NodeType setLikelyIIFE(NodeType node) { + return node; // Remain in syntax-parse mode. + } + + bool isName(Node node) { + return node == NodeName || node == NodeArgumentsName || + node == NodeEvalName || node == NodePotentialAsyncKeyword; + } + + bool isArgumentsName(Node node) { return node == NodeArgumentsName; } + bool isEvalName(Node node) { return node == NodeEvalName; } + bool isAsyncKeyword(Node node) { return node == NodePotentialAsyncKeyword; } + + bool isPrivateName(Node node) { return node == NodePrivateName; } + bool isPrivateMemberAccess(Node node) { + return node == NodePrivateMemberAccess; + } + + TaggedParserAtomIndex maybeDottedProperty(Node node) { + // Note: |super.apply(...)| is a special form that calls an "apply" + // method retrieved from one value, but using a *different* value as + // |this|. It's not really eligible for the funapply/funcall + // optimizations as they're currently implemented (assuming a single + // value is used for both retrieval and |this|). + if (node != NodeDottedProperty && node != NodeOptionalDottedProperty) { + return TaggedParserAtomIndex::null(); + } + return lastAtom; + } + + TaggedParserAtomIndex isStringExprStatement(Node pn, TokenPos* pos) { + if (pn == NodeStringExprStatement) { + *pos = lastStringPos; + return lastAtom; + } + return TaggedParserAtomIndex::null(); + } + + bool reuseLazyInnerFunctions() { return false; } + bool reuseClosedOverBindings() { return false; } + TaggedParserAtomIndex nextLazyClosedOverBinding() { + MOZ_CRASH( + "SyntaxParseHandler::canSkipLazyClosedOverBindings must return false"); + } + + void setPrivateNameKind(Node node, PrivateNameKind kind) {} +}; + +} // namespace frontend +} // namespace js + +#endif /* frontend_SyntaxParseHandler_h */ |