summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/SyntaxParseHandler.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/frontend/SyntaxParseHandler.h797
1 files changed, 797 insertions, 0 deletions
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
new file mode 100644
index 0000000000..d56591e463
--- /dev/null
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -0,0 +1,797 @@
+/* -*- 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 <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 {
+
+// 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:
+ enum Node {
+ 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
+ };
+
+#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \
+ using longTypeName = Node;
+ 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; }
+
+#define DECLARE_AS(typeName, longTypeName, asMethodName) \
+ static longTypeName asMethodName(Node node) { return node; }
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
+#undef DECLARE_AS
+
+ NameNodeType 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;
+ }
+
+ UnaryNodeType newComputedName(Node expr, uint32_t start, uint32_t end) {
+ return NodeGeneric;
+ }
+
+ UnaryNodeType newSyntheticComputedName(Node expr, uint32_t start,
+ uint32_t end) {
+ return NodeGeneric;
+ }
+
+ NameNodeType newObjectLiteralPropertyName(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return NodeName;
+ }
+
+ NameNodeType newPrivateName(TaggedParserAtomIndex atom, const TokenPos& pos) {
+ return NodePrivateName;
+ }
+
+ NumericLiteralType newNumber(double value, DecimalPoint decimalPoint,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ BigIntLiteralType newBigInt() { return NodeGeneric; }
+
+ BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ NameNodeType newStringLiteral(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ lastAtom = atom;
+ lastStringPos = pos;
+ return NodeUnparenthesizedString;
+ }
+
+ NameNodeType newTemplateStringLiteral(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ CallSiteNodeType newCallSiteObject(uint32_t begin) { return NodeGeneric; }
+
+ void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode,
+ Node cookedNode) {}
+
+ ThisLiteralType newThisLiteral(const TokenPos& pos, Node thisName) {
+ return NodeGeneric;
+ }
+ NullLiteralType newNullLiteral(const TokenPos& pos) { return NodeGeneric; }
+ RawUndefinedLiteralType newRawUndefinedLiteral(const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ RegExpLiteralType newRegExp(Node reobj, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ ConditionalExpressionType newConditional(Node cond, Node thenExpr,
+ Node elseExpr) {
+ return NodeGeneric;
+ }
+
+ UnaryNodeType newDelete(uint32_t begin, Node expr) {
+ return NodeUnparenthesizedUnary;
+ }
+
+ UnaryNodeType newTypeof(uint32_t begin, Node kid) {
+ return NodeUnparenthesizedUnary;
+ }
+
+ UnaryNodeType newUnary(ParseNodeKind kind, uint32_t begin, Node kid) {
+ return NodeUnparenthesizedUnary;
+ }
+
+ UnaryNodeType newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) {
+ return NodeGeneric;
+ }
+
+ UnaryNodeType newSpread(uint32_t begin, Node kid) { return NodeGeneric; }
+
+ Node appendOrCreateList(ParseNodeKind kind, Node left, Node right,
+ ParseContext* pc) {
+ return NodeGeneric;
+ }
+
+ // Expressions
+
+ ListNodeType 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) {}
+
+ ListNodeType newArguments(const TokenPos& pos) { return NodeGeneric; }
+ CallNodeType newCall(Node callee, Node args, JSOp callOp) {
+ return NodeFunctionCall;
+ }
+
+ CallNodeType newOptionalCall(Node callee, Node args, JSOp callOp) {
+ return NodeOptionalFunctionCall;
+ }
+
+ CallNodeType newSuperCall(Node callee, Node args, bool isSpread) {
+ return NodeGeneric;
+ }
+ CallNodeType newTaggedTemplate(Node tag, Node args, JSOp callOp) {
+ return NodeGeneric;
+ }
+
+ ListNodeType newObjectLiteral(uint32_t begin) {
+ return NodeUnparenthesizedObject;
+ }
+
+#ifdef ENABLE_RECORD_TUPLE
+ ListNodeType newRecordLiteral(uint32_t begin) { return NodeGeneric; }
+
+ ListNodeType newTupleLiteral(uint32_t begin) { return NodeGeneric; }
+#endif
+
+ ListNodeType newClassMemberList(uint32_t begin) { return NodeGeneric; }
+ ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ ClassNodeType newClass(Node name, Node heritage, Node methodBlock,
+#ifdef ENABLE_DECORATORS
+ ListNodeType decorators,
+#endif
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ LexicalScopeNodeType newLexicalScope(Node body) {
+ return NodeLexicalDeclaration;
+ }
+
+ ClassBodyScopeNodeType newClassBodyScope(Node body) {
+ return NodeLexicalDeclaration;
+ }
+
+ NewTargetNodeType newNewTarget(NullaryNodeType newHolder,
+ NullaryNodeType targetHolder,
+ NameNodeType newTargetName) {
+ return NodeGeneric;
+ }
+ NullaryNodeType newPosHolder(const TokenPos& pos) { return NodeGeneric; }
+ UnaryNodeType newSuperBase(Node thisName, const TokenPos& pos) {
+ return NodeSuperBase;
+ }
+
+ [[nodiscard]] bool addPrototypeMutation(ListNodeType literal, uint32_t begin,
+ Node expr) {
+ return true;
+ }
+ BinaryNodeType 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]] Node newDefaultClassConstructor(Node key,
+ FunctionNodeType funNode) {
+ return NodeGeneric;
+ }
+ [[nodiscard]] Node newClassMethodDefinition(
+ Node key, FunctionNodeType funNode, AccessorType atype, bool isStatic,
+ mozilla::Maybe<FunctionNodeType> initializerIfPrivate
+#ifdef ENABLE_DECORATORS
+ ,
+ ListNodeType decorators
+#endif
+ ) {
+ return NodeGeneric;
+ }
+ [[nodiscard]] Node newClassFieldDefinition(Node name,
+ FunctionNodeType initializer,
+ bool isStatic
+#ifdef ENABLE_DECORATORS
+ ,
+ ListNodeType decorators,
+ bool hasAccessor
+#endif
+ ) {
+ return NodeGeneric;
+ }
+
+ [[nodiscard]] Node newStaticClassBlock(FunctionNodeType block) {
+ return NodeGeneric;
+ }
+
+ [[nodiscard]] bool addClassMemberDefinition(ListNodeType memberList,
+ Node member) {
+ return true;
+ }
+ UnaryNodeType newYieldExpression(uint32_t begin, Node value) {
+ return NodeGeneric;
+ }
+ UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) {
+ return NodeGeneric;
+ }
+ UnaryNodeType newAwaitExpression(uint32_t begin, Node value) {
+ return NodeUnparenthesizedUnary;
+ }
+ UnaryNodeType newOptionalChain(uint32_t begin, Node value) {
+ return NodeGeneric;
+ }
+
+ // Statements
+
+ ListNodeType 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;
+ }
+ NullaryNodeType newEmptyStatement(const TokenPos& pos) {
+ return NodeEmptyStatement;
+ }
+
+ BinaryNodeType newImportAssertion(Node keyNode, Node valueNode) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newModuleRequest(Node moduleSpec, Node importAssertionList,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newImportDeclaration(Node importSpecSet, Node moduleRequest,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newImportSpec(Node importNameNode, Node bindingName) {
+ return NodeGeneric;
+ }
+ UnaryNodeType newImportNamespaceSpec(uint32_t begin, Node bindingName) {
+ return NodeGeneric;
+ }
+ UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportFromDeclaration(uint32_t begin, Node exportSpecSet,
+ Node moduleRequest) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportDefaultDeclaration(Node kid, Node maybeBinding,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportSpec(Node bindingName, Node exportName) {
+ return NodeGeneric;
+ }
+ UnaryNodeType newExportNamespaceSpec(uint32_t begin, Node exportName) {
+ return NodeGeneric;
+ }
+ NullaryNodeType newExportBatchSpec(const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newImportMeta(NullaryNodeType importHolder,
+ NullaryNodeType metaHolder) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newCallImport(NullaryNodeType importHolder, Node singleArg) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newCallImportSpec(Node specifierArg, Node optionalArg) {
+ return NodeGeneric;
+ }
+
+ BinaryNodeType newSetThis(Node thisName, Node value) { return value; }
+
+ UnaryNodeType newExprStatement(Node expr, uint32_t end) {
+ return expr == NodeUnparenthesizedString ? NodeStringExprStatement
+ : NodeGeneric;
+ }
+
+ TernaryNodeType newIfStatement(uint32_t begin, Node cond, Node thenBranch,
+ Node elseBranch) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newDoWhileStatement(Node body, Node cond,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newWhileStatement(uint32_t begin, Node cond, Node body) {
+ return NodeGeneric;
+ }
+ SwitchStatementType newSwitchStatement(
+ uint32_t begin, Node discriminant,
+ LexicalScopeNodeType lexicalForCaseList, bool hasDefault) {
+ return NodeGeneric;
+ }
+ CaseClauseType newCaseOrDefault(uint32_t begin, Node expr, Node body) {
+ return NodeGeneric;
+ }
+ ContinueStatementType newContinueStatement(TaggedParserAtomIndex label,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BreakStatementType newBreakStatement(TaggedParserAtomIndex label,
+ const TokenPos& pos) {
+ return NodeBreak;
+ }
+ UnaryNodeType newReturnStatement(Node expr, const TokenPos& pos) {
+ return NodeReturn;
+ }
+ UnaryNodeType newExpressionBody(Node expr) { return NodeReturn; }
+ BinaryNodeType newWithStatement(uint32_t begin, Node expr, Node body) {
+ return NodeGeneric;
+ }
+
+ LabeledStatementType newLabeledStatement(TaggedParserAtomIndex label,
+ Node stmt, uint32_t begin) {
+ return NodeGeneric;
+ }
+
+ UnaryNodeType newThrowStatement(Node expr, const TokenPos& pos) {
+ return NodeThrow;
+ }
+ TernaryNodeType newTryStatement(uint32_t begin, Node body,
+ LexicalScopeNodeType catchScope,
+ Node finallyBlock) {
+ return NodeGeneric;
+ }
+ DebuggerStatementType newDebuggerStatement(const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ NameNodeType newPropertyName(TaggedParserAtomIndex name,
+ const TokenPos& pos) {
+ lastAtom = name;
+ return NodeGeneric;
+ }
+
+ PropertyAccessType newPropertyAccess(Node expr, NameNodeType key) {
+ return NodeDottedProperty;
+ }
+
+ PropertyAccessType newOptionalPropertyAccess(Node expr, NameNodeType key) {
+ return NodeOptionalDottedProperty;
+ }
+
+ PropertyByValueType newPropertyByValue(Node lhs, Node index, uint32_t end) {
+ MOZ_ASSERT(!isPrivateName(index));
+ return NodeElement;
+ }
+
+ PropertyByValueType newOptionalPropertyByValue(Node lhs, Node index,
+ uint32_t end) {
+ return NodeOptionalElement;
+ }
+
+ PrivateMemberAccessType newPrivateMemberAccess(Node lhs, Node privateName,
+ uint32_t end) {
+ return NodePrivateMemberAccess;
+ }
+
+ PrivateMemberAccessType 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) {}
+
+ ParamsBodyNodeType newParamsBody(const TokenPos& pos) { return NodeGeneric; }
+
+ FunctionNodeType 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) {}
+
+ ForNodeType newForStatement(uint32_t begin, TernaryNodeType forHead,
+ Node body, unsigned iflags) {
+ return NodeGeneric;
+ }
+
+ TernaryNodeType newForHead(Node init, Node test, Node update,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ TernaryNodeType newForInOrOfHead(ParseNodeKind kind, Node target,
+ Node iteratedExpr, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ AssignmentNodeType 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;
+ }
+
+ ListNodeType 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;
+ }
+
+ ListNodeType newList(ParseNodeKind kind, Node kid) {
+ return newList(kind, TokenPos());
+ }
+
+ DeclarationListNodeType newDeclarationList(ParseNodeKind kind,
+ const TokenPos& pos) {
+ if (kind == ParseNodeKind::VarStmt) {
+ return NodeVarDeclaration;
+ }
+ MOZ_ASSERT(kind == ParseNodeKind::LetDecl ||
+ kind == ParseNodeKind::ConstDecl);
+ return NodeLexicalDeclaration;
+ }
+
+ ListNodeType 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);
+ }
+
+ CallNodeType newNewExpression(uint32_t begin, Node ctor, Node args,
+ bool isSpread) {
+ return NodeGeneric;
+ }
+
+ AssignmentNodeType newAssignment(ParseNodeKind kind, Node lhs, Node rhs) {
+ return kind == ParseNodeKind::AssignExpr ? NodeUnparenthesizedAssignment
+ : NodeGeneric;
+ }
+
+ AssignmentNodeType 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) {}
+ [[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;
+ }
+ 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 */