summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/SyntaxParseHandler.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/frontend/SyntaxParseHandler.h
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/frontend/SyntaxParseHandler.h')
-rw-r--r--js/src/frontend/SyntaxParseHandler.h733
1 files changed, 733 insertions, 0 deletions
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
new file mode 100644
index 0000000000..0c93376700
--- /dev/null
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -0,0 +1,733 @@
+/* -*- 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/Attributes.h"
+#include "mozilla/Maybe.h" // mozilla::Maybe
+
+#include <string.h>
+
+#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
+#include "frontend/NameAnalysisTypes.h" // PrivateNameKind
+#include "frontend/ParseNode.h"
+#include "frontend/TokenStream.h"
+#include "js/GCAnnotations.h"
+#include "vm/JSContext.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.
+ const ParserAtom* 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
+ NodePrivateElement,
+
+ // 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 isPropertyAccess(Node node) {
+ return node == NodeDottedProperty || node == NodeElement ||
+ node == NodePrivateElement;
+ }
+
+ bool isOptionalPropertyAccess(Node node) {
+ return node == NodeOptionalDottedProperty || node == NodeOptionalElement;
+ }
+
+ 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(JSContext* cx, LifoAlloc& alloc,
+ BaseScript* lazyOuterFunction)
+ : lastAtom(nullptr) {}
+
+ 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(const ParserName* name, const TokenPos& pos,
+ JSContext* cx) {
+ lastAtom = name;
+ if (name == cx->parserNames().arguments) {
+ return NodeArgumentsName;
+ }
+ if (pos.begin + strlen("async") == pos.end &&
+ name == cx->parserNames().async) {
+ return NodePotentialAsyncKeyword;
+ }
+ if (name == cx->parserNames().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(const ParserAtom* atom,
+ const TokenPos& pos) {
+ return NodeName;
+ }
+
+ NameNodeType newPrivateName(const ParserAtom* 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(const ParserAtom* atom, const TokenPos& pos) {
+ lastAtom = atom;
+ lastStringPos = pos;
+ return NodeUnparenthesizedString;
+ }
+
+ NameNodeType newTemplateStringLiteral(const ParserAtom* 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;
+ }
+
+ Node newElision() { 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;
+ }
+ MOZ_MUST_USE bool addElision(ListNodeType literal, const TokenPos& pos) {
+ return true;
+ }
+ MOZ_MUST_USE 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;
+ }
+ 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,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+
+ LexicalScopeNodeType newLexicalScope(Node body) {
+ return NodeLexicalDeclaration;
+ }
+
+ BinaryNodeType newNewTarget(NullaryNodeType newHolder,
+ NullaryNodeType targetHolder) {
+ return NodeGeneric;
+ }
+ NullaryNodeType newPosHolder(const TokenPos& pos) { return NodeGeneric; }
+ UnaryNodeType newSuperBase(Node thisName, const TokenPos& pos) {
+ return NodeSuperBase;
+ }
+
+ MOZ_MUST_USE 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) {}
+ MOZ_MUST_USE bool addPropertyDefinition(ListNodeType literal, Node key,
+ Node expr) {
+ return true;
+ }
+ MOZ_MUST_USE bool addShorthand(ListNodeType literal, NameNodeType name,
+ NameNodeType expr) {
+ return true;
+ }
+ MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin,
+ Node inner) {
+ return true;
+ }
+ MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node key,
+ FunctionNodeType funNode,
+ AccessorType atype) {
+ return true;
+ }
+ MOZ_MUST_USE Node newClassMethodDefinition(
+ Node key, FunctionNodeType funNode, AccessorType atype, bool isStatic,
+ mozilla::Maybe<FunctionNodeType> initializerIfPrivate) {
+ return NodeGeneric;
+ }
+ MOZ_MUST_USE Node newClassFieldDefinition(Node name,
+ FunctionNodeType initializer,
+ bool isStatic) {
+ return NodeGeneric;
+ }
+ MOZ_MUST_USE 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) {}
+ MOZ_MUST_USE bool prependInitialYield(ListNodeType stmtList, Node genName) {
+ return true;
+ }
+ NullaryNodeType newEmptyStatement(const TokenPos& pos) {
+ return NodeEmptyStatement;
+ }
+
+ UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportFromDeclaration(uint32_t begin, Node exportSpecSet,
+ Node moduleSpec) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportDefaultDeclaration(Node kid, Node maybeBinding,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BinaryNodeType newExportSpec(Node bindingName, 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 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(const ParserName* label,
+ const TokenPos& pos) {
+ return NodeGeneric;
+ }
+ BreakStatementType newBreakStatement(const ParserName* 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(const ParserName* 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(const ParserName* 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) {
+ if (isPrivateName(index)) {
+ return NodePrivateElement;
+ }
+ return NodeElement;
+ }
+
+ PropertyByValueType newOptionalPropertyByValue(Node lhs, Node index,
+ uint32_t end) {
+ return NodeOptionalElement;
+ }
+
+ MOZ_MUST_USE bool setupCatchScope(LexicalScopeNodeType lexicalScope,
+ Node catchName, Node catchBody) {
+ return true;
+ }
+
+ MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(
+ FunctionNodeType funNode, Node defaultValue) {
+ return true;
+ }
+
+ void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
+
+ 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,
+ ListNodeType 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);
+ return NodeGeneric;
+ }
+
+ ListNodeType newList(ParseNodeKind kind, Node kid) {
+ return newList(kind, TokenPos());
+ }
+
+ ListNodeType newDeclarationList(ParseNodeKind kind, const TokenPos& pos) {
+ if (kind == ParseNodeKind::VarStmt) {
+ return NodeVarDeclaration;
+ }
+ MOZ_ASSERT(kind == ParseNodeKind::LetDecl ||
+ kind == ParseNodeKind::ConstDecl);
+ return NodeLexicalDeclaration;
+ }
+
+ bool isDeclarationList(Node node) {
+ return node == NodeVarDeclaration || node == NodeLexicalDeclaration;
+ }
+
+ // This method should only be called from parsers using FullParseHandler.
+ Node singleBindingFromDeclaration(ListNodeType decl) = delete;
+
+ 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;
+ }
+
+ 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) {}
+ MOZ_MUST_USE 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>
+ MOZ_MUST_USE 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, JSContext* cx) {
+ return node == NodeArgumentsName;
+ }
+
+ bool isEvalName(Node node, JSContext* cx) { return node == NodeEvalName; }
+
+ bool isAsyncKeyword(Node node, JSContext* cx) {
+ return node == NodePotentialAsyncKeyword;
+ }
+
+ bool isPrivateName(Node node) { return node == NodePrivateName; }
+ bool isPrivateField(Node node) { return node == NodePrivateElement; }
+
+ const ParserName* 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 nullptr;
+ }
+ return lastAtom->asName();
+ }
+
+ const ParserAtom* isStringExprStatement(Node pn, TokenPos* pos) {
+ if (pn == NodeStringExprStatement) {
+ *pos = lastStringPos;
+ return lastAtom;
+ }
+ return nullptr;
+ }
+
+ bool canSkipLazyInnerFunctions() { return false; }
+ bool canSkipLazyClosedOverBindings() { return false; }
+ JSAtom* nextLazyClosedOverBinding() {
+ MOZ_CRASH(
+ "SyntaxParseHandler::canSkipLazyClosedOverBindings must return false");
+ }
+
+ void setPrivateNameKind(Node node, PrivateNameKind kind) {}
+};
+
+} // namespace frontend
+} // namespace js
+
+#endif /* frontend_SyntaxParseHandler_h */