summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/FullParseHandler.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/frontend/FullParseHandler.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/frontend/FullParseHandler.h')
-rw-r--r--js/src/frontend/FullParseHandler.h1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
new file mode 100644
index 0000000000..384d16b7d8
--- /dev/null
+++ b/js/src/frontend/FullParseHandler.h
@@ -0,0 +1,1226 @@
+/* -*- 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_FullParseHandler_h
+#define frontend_FullParseHandler_h
+
+#include "mozilla/Maybe.h" // mozilla::Maybe
+#include "mozilla/Result.h" // mozilla::Result, mozilla::UnusedZero
+#include "mozilla/Try.h" // MOZ_TRY*
+
+#include <cstddef> // std::nullptr_t
+#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/Parser-macros.h" // MOZ_TRY_VAR_OR_RETURN
+#include "frontend/ParserAtom.h" // TaggedParserAtomIndex
+#include "frontend/SharedContext.h"
+#include "frontend/Stencil.h"
+
+template <>
+struct mozilla::detail::UnusedZero<js::frontend::ParseNode*> {
+ static const bool value = true;
+};
+
+#define DEFINE_UNUSED_ZERO(typeName) \
+ template <> \
+ struct mozilla::detail::UnusedZero<js::frontend::typeName*> { \
+ static const bool value = true; \
+ };
+FOR_EACH_PARSENODE_SUBCLASS(DEFINE_UNUSED_ZERO)
+#undef DEFINE_UNUSED_ZERO
+
+namespace js {
+namespace frontend {
+
+class TokenStreamAnyChars;
+
+// Parse handler used when generating a full parse tree for all code which the
+// parser encounters.
+class FullParseHandler {
+ ParseNodeAllocator allocator;
+
+ ParseNode* allocParseNode(size_t size) {
+ return static_cast<ParseNode*>(allocator.allocNode(size));
+ }
+
+ // If this is a full parse to construct the bytecode for a function that
+ // was previously lazily parsed, we still don't want to full parse the
+ // inner functions. These members are used for this functionality:
+ //
+ // - reuseGCThings if ture it means that the following fields are valid.
+ // - gcThingsData holds an incomplete stencil-like copy of inner functions as
+ // well as atoms.
+ // - scriptData and scriptExtra_ hold information necessary to locate inner
+ // functions to skip over each.
+ // - lazyInnerFunctionIndex is used as we skip over inner functions
+ // (see skipLazyInnerFunction),
+ // - lazyClosedOverBindingIndex is used to synchronize binding computation
+ // with the scope traversal.
+ // (see propagateFreeNamesAndMarkClosedOverBindings),
+ const CompilationSyntaxParseCache& previousParseCache_;
+
+ size_t lazyInnerFunctionIndex;
+ size_t lazyClosedOverBindingIndex;
+
+ bool reuseGCThings;
+
+ /* new_ methods for creating parse nodes. These report OOM on context. */
+ JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
+
+ public:
+ using NodeError = ParseNodeError;
+
+ using Node = ParseNode*;
+ using NodeResult = ParseNodeResult;
+ using NodeErrorResult = mozilla::GenericErrorResult<NodeError>;
+
+#define DECLARE_TYPE(typeName) \
+ using typeName##Type = typeName*; \
+ using typeName##Result = mozilla::Result<typeName*, NodeError>;
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
+#undef DECLARE_TYPE
+
+ template <class T, typename... Args>
+ inline mozilla::Result<T*, NodeError> newResult(Args&&... args) {
+ auto* node = new_<T>(std::forward<Args>(args)...);
+ if (!node) {
+ return mozilla::Result<T*, NodeError>(NodeError());
+ }
+ return node;
+ }
+
+ using NullNode = std::nullptr_t;
+
+ bool isPropertyOrPrivateMemberAccess(Node node) {
+ return node->isKind(ParseNodeKind::DotExpr) ||
+ node->isKind(ParseNodeKind::ElemExpr) ||
+ node->isKind(ParseNodeKind::PrivateMemberExpr);
+ }
+
+ bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
+ return node->isKind(ParseNodeKind::OptionalDotExpr) ||
+ node->isKind(ParseNodeKind::OptionalElemExpr) ||
+ node->isKind(ParseNodeKind::PrivateMemberExpr);
+ }
+
+ bool isFunctionCall(Node node) {
+ // Note: super() is a special form, *not* a function call.
+ return node->isKind(ParseNodeKind::CallExpr);
+ }
+
+ static bool isUnparenthesizedDestructuringPattern(Node node) {
+ return !node->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
+ node->isKind(ParseNodeKind::ArrayExpr));
+ }
+
+ static bool isParenthesizedDestructuringPattern(Node node) {
+ // Technically this isn't a destructuring pattern 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->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
+ node->isKind(ParseNodeKind::ArrayExpr));
+ }
+
+ FullParseHandler(FrontendContext* fc, CompilationState& compilationState)
+ : allocator(fc, compilationState.parserAllocScope.alloc()),
+ previousParseCache_(compilationState.previousParseCache),
+ lazyInnerFunctionIndex(0),
+ lazyClosedOverBindingIndex(0),
+ reuseGCThings(compilationState.input.isDelazifying()) {}
+
+ static NullNode null() { return NullNode(); }
+ static constexpr NodeErrorResult errorResult() {
+ return NodeErrorResult(NodeError());
+ }
+
+#define DECLARE_AS(typeName) \
+ static typeName##Type as##typeName(Node node) { \
+ return &node->as<typeName>(); \
+ }
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
+#undef DECLARE_AS
+
+ NameNodeResult newName(TaggedParserAtomIndex name, const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::Name, name, pos);
+ }
+
+ UnaryNodeResult newComputedName(Node expr, uint32_t begin, uint32_t end) {
+ TokenPos pos(begin, end);
+ return newResult<UnaryNode>(ParseNodeKind::ComputedName, pos, expr);
+ }
+
+ UnaryNodeResult newSyntheticComputedName(Node expr, uint32_t begin,
+ uint32_t end) {
+ TokenPos pos(begin, end);
+ UnaryNode* node;
+ MOZ_TRY_VAR(node,
+ newResult<UnaryNode>(ParseNodeKind::ComputedName, pos, expr));
+ node->setSyntheticComputedName();
+ return node;
+ }
+
+ NameNodeResult newObjectLiteralPropertyName(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::ObjectPropertyName, atom, pos);
+ }
+
+ NameNodeResult newPrivateName(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::PrivateName, atom, pos);
+ }
+
+ NumericLiteralResult newNumber(double value, DecimalPoint decimalPoint,
+ const TokenPos& pos) {
+ return newResult<NumericLiteral>(value, decimalPoint, pos);
+ }
+
+ BigIntLiteralResult newBigInt(BigIntIndex index, bool isZero,
+ const TokenPos& pos) {
+ return newResult<BigIntLiteral>(index, isZero, pos);
+ }
+
+ BooleanLiteralResult newBooleanLiteral(bool cond, const TokenPos& pos) {
+ return newResult<BooleanLiteral>(cond, pos);
+ }
+
+ NameNodeResult newStringLiteral(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::StringExpr, atom, pos);
+ }
+
+ NameNodeResult newTemplateStringLiteral(TaggedParserAtomIndex atom,
+ const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::TemplateStringExpr, atom, pos);
+ }
+
+ CallSiteNodeResult newCallSiteObject(uint32_t begin) {
+ CallSiteNode* callSiteObj;
+ MOZ_TRY_VAR(callSiteObj, newResult<CallSiteNode>(begin));
+
+ ListNode* rawNodes;
+ MOZ_TRY_VAR(rawNodes, newArrayLiteral(callSiteObj->pn_pos.begin));
+
+ addArrayElement(callSiteObj, rawNodes);
+
+ return callSiteObj;
+ }
+
+ void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode,
+ Node cookedNode) {
+ MOZ_ASSERT(callSiteObj->isKind(ParseNodeKind::CallSiteObj));
+ MOZ_ASSERT(rawNode->isKind(ParseNodeKind::TemplateStringExpr));
+ MOZ_ASSERT(cookedNode->isKind(ParseNodeKind::TemplateStringExpr) ||
+ cookedNode->isKind(ParseNodeKind::RawUndefinedExpr));
+
+ addArrayElement(callSiteObj, cookedNode);
+ addArrayElement(callSiteObj->rawNodes(), rawNode);
+
+ /*
+ * We don't know when the last noSubstTemplate will come in, and we
+ * don't want to deal with this outside this method
+ */
+ setEndPosition(callSiteObj, callSiteObj->rawNodes());
+ }
+
+ ThisLiteralResult newThisLiteral(const TokenPos& pos, Node thisName) {
+ return newResult<ThisLiteral>(pos, thisName);
+ }
+
+ NullLiteralResult newNullLiteral(const TokenPos& pos) {
+ return newResult<NullLiteral>(pos);
+ }
+
+ RawUndefinedLiteralResult newRawUndefinedLiteral(const TokenPos& pos) {
+ return newResult<RawUndefinedLiteral>(pos);
+ }
+
+ RegExpLiteralResult newRegExp(RegExpIndex index, const TokenPos& pos) {
+ return newResult<RegExpLiteral>(index, pos);
+ }
+
+ ConditionalExpressionResult newConditional(Node cond, Node thenExpr,
+ Node elseExpr) {
+ return newResult<ConditionalExpression>(cond, thenExpr, elseExpr);
+ }
+
+ UnaryNodeResult newDelete(uint32_t begin, Node expr) {
+ if (expr->isKind(ParseNodeKind::Name)) {
+ return newUnary(ParseNodeKind::DeleteNameExpr, begin, expr);
+ }
+
+ if (expr->isKind(ParseNodeKind::DotExpr)) {
+ return newUnary(ParseNodeKind::DeletePropExpr, begin, expr);
+ }
+
+ if (expr->isKind(ParseNodeKind::ElemExpr)) {
+ return newUnary(ParseNodeKind::DeleteElemExpr, begin, expr);
+ }
+
+ if (expr->isKind(ParseNodeKind::OptionalChain)) {
+ Node kid = expr->as<UnaryNode>().kid();
+ // Handle property deletion explicitly. OptionalCall is handled
+ // via DeleteExpr.
+ if (kid->isKind(ParseNodeKind::DotExpr) ||
+ kid->isKind(ParseNodeKind::OptionalDotExpr) ||
+ kid->isKind(ParseNodeKind::ElemExpr) ||
+ kid->isKind(ParseNodeKind::OptionalElemExpr)) {
+ return newUnary(ParseNodeKind::DeleteOptionalChainExpr, begin, kid);
+ }
+ }
+
+ return newUnary(ParseNodeKind::DeleteExpr, begin, expr);
+ }
+
+ UnaryNodeResult newTypeof(uint32_t begin, Node kid) {
+ ParseNodeKind pnk = kid->isKind(ParseNodeKind::Name)
+ ? ParseNodeKind::TypeOfNameExpr
+ : ParseNodeKind::TypeOfExpr;
+ return newUnary(pnk, begin, kid);
+ }
+
+ UnaryNodeResult newUnary(ParseNodeKind kind, uint32_t begin, Node kid) {
+ TokenPos pos(begin, kid->pn_pos.end);
+ return newResult<UnaryNode>(kind, pos, kid);
+ }
+
+ UnaryNodeResult newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) {
+ TokenPos pos(begin, kid->pn_pos.end);
+ return newResult<UnaryNode>(kind, pos, kid);
+ }
+
+ UnaryNodeResult newSpread(uint32_t begin, Node kid) {
+ TokenPos pos(begin, kid->pn_pos.end);
+ return newResult<UnaryNode>(ParseNodeKind::Spread, pos, kid);
+ }
+
+ private:
+ BinaryNodeResult newBinary(ParseNodeKind kind, Node left, Node right) {
+ TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
+ return newResult<BinaryNode>(kind, pos, left, right);
+ }
+
+ public:
+ NodeResult appendOrCreateList(ParseNodeKind kind, Node left, Node right,
+ ParseContext* pc) {
+ return ParseNode::appendOrCreateList(kind, left, right, this, pc);
+ }
+
+ // Expressions
+
+ ListNodeResult newArrayLiteral(uint32_t begin) {
+ return newResult<ListNode>(ParseNodeKind::ArrayExpr,
+ TokenPos(begin, begin + 1));
+ }
+
+ [[nodiscard]] bool addElision(ListNodeType literal, const TokenPos& pos) {
+ MOZ_ASSERT(literal->isKind(ParseNodeKind::ArrayExpr));
+
+ NullaryNode* elision;
+ MOZ_TRY_VAR_OR_RETURN(
+ elision, newResult<NullaryNode>(ParseNodeKind::Elision, pos), false);
+ addList(/* list = */ literal, /* kid = */ elision);
+ literal->setHasNonConstInitializer();
+ return true;
+ }
+
+ [[nodiscard]] bool addSpreadElement(ListNodeType literal, uint32_t begin,
+ Node inner) {
+ MOZ_ASSERT(
+ literal->isKind(ParseNodeKind::ArrayExpr) ||
+ IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::TupleExpr), false));
+
+ UnaryNodeType spread;
+ MOZ_TRY_VAR_OR_RETURN(spread, newSpread(begin, inner), false);
+ addList(/* list = */ literal, /* kid = */ spread);
+ literal->setHasNonConstInitializer();
+ return true;
+ }
+
+ void addArrayElement(ListNodeType literal, Node element) {
+ MOZ_ASSERT(
+ literal->isKind(ParseNodeKind::ArrayExpr) ||
+ literal->isKind(ParseNodeKind::CallSiteObj) ||
+ IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::TupleExpr), false));
+ if (!element->isConstant()) {
+ literal->setHasNonConstInitializer();
+ }
+ addList(/* list = */ literal, /* kid = */ element);
+ }
+
+ CallNodeResult newCall(Node callee, ListNodeType args, JSOp callOp) {
+ return newResult<CallNode>(ParseNodeKind::CallExpr, callOp, callee, args);
+ }
+
+ CallNodeResult newOptionalCall(Node callee, ListNodeType args, JSOp callOp) {
+ return newResult<CallNode>(ParseNodeKind::OptionalCallExpr, callOp, callee,
+ args);
+ }
+
+ ListNodeResult newArguments(const TokenPos& pos) {
+ return newResult<ListNode>(ParseNodeKind::Arguments, pos);
+ }
+
+ CallNodeResult newSuperCall(Node callee, ListNodeType args, bool isSpread) {
+ return newResult<CallNode>(
+ ParseNodeKind::SuperCallExpr,
+ isSpread ? JSOp::SpreadSuperCall : JSOp::SuperCall, callee, args);
+ }
+
+ CallNodeResult newTaggedTemplate(Node tag, ListNodeType args, JSOp callOp) {
+ return newResult<CallNode>(ParseNodeKind::TaggedTemplateExpr, callOp, tag,
+ args);
+ }
+
+ ListNodeResult newObjectLiteral(uint32_t begin) {
+ return newResult<ListNode>(ParseNodeKind::ObjectExpr,
+ TokenPos(begin, begin + 1));
+ }
+
+#ifdef ENABLE_RECORD_TUPLE
+ ListNodeResult newRecordLiteral(uint32_t begin) {
+ return newResult<ListNode>(ParseNodeKind::RecordExpr,
+ TokenPos(begin, begin + 1));
+ }
+
+ ListNodeResult newTupleLiteral(uint32_t begin) {
+ return newResult<ListNode>(ParseNodeKind::TupleExpr,
+ TokenPos(begin, begin + 1));
+ }
+#endif
+
+ ClassNodeResult newClass(Node name, Node heritage,
+ LexicalScopeNodeType memberBlock,
+#ifdef ENABLE_DECORATORS
+ ListNodeType decorators,
+ FunctionNodeType addInitializerFunction,
+#endif
+ const TokenPos& pos) {
+ return newResult<ClassNode>(name, heritage, memberBlock,
+#ifdef ENABLE_DECORATORS
+ decorators, addInitializerFunction,
+#endif
+ pos);
+ }
+ ListNodeResult newClassMemberList(uint32_t begin) {
+ return newResult<ListNode>(ParseNodeKind::ClassMemberList,
+ TokenPos(begin, begin + 1));
+ }
+ ClassNamesResult newClassNames(Node outer, Node inner, const TokenPos& pos) {
+ return newResult<ClassNames>(outer, inner, pos);
+ }
+ NewTargetNodeResult newNewTarget(NullaryNodeType newHolder,
+ NullaryNodeType targetHolder,
+ NameNodeType newTargetName) {
+ return newResult<NewTargetNode>(newHolder, targetHolder, newTargetName);
+ }
+ NullaryNodeResult newPosHolder(const TokenPos& pos) {
+ return newResult<NullaryNode>(ParseNodeKind::PosHolder, pos);
+ }
+ UnaryNodeResult newSuperBase(Node thisName, const TokenPos& pos) {
+ return newResult<UnaryNode>(ParseNodeKind::SuperBase, pos, thisName);
+ }
+ [[nodiscard]] bool addPrototypeMutation(ListNodeType literal, uint32_t begin,
+ Node expr) {
+ MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
+
+ // Object literals with mutated [[Prototype]] are non-constant so that
+ // singleton objects will have Object.prototype as their [[Prototype]].
+ literal->setHasNonConstInitializer();
+
+ UnaryNode* mutation;
+ MOZ_TRY_VAR_OR_RETURN(
+ mutation, newUnary(ParseNodeKind::MutateProto, begin, expr), false);
+ addList(/* list = */ literal, /* kid = */ mutation);
+ return true;
+ }
+
+ BinaryNodeResult newPropertyDefinition(Node key, Node val) {
+ MOZ_ASSERT(isUsableAsObjectPropertyName(key));
+ checkAndSetIsDirectRHSAnonFunction(val);
+ return newResult<PropertyDefinition>(key, val, AccessorType::None);
+ }
+
+ void addPropertyDefinition(ListNodeType literal, BinaryNodeType propdef) {
+ MOZ_ASSERT(
+ literal->isKind(ParseNodeKind::ObjectExpr) ||
+ IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
+ MOZ_ASSERT(propdef->isKind(ParseNodeKind::PropertyDefinition));
+
+ if (!propdef->right()->isConstant()) {
+ literal->setHasNonConstInitializer();
+ }
+
+ addList(/* list = */ literal, /* kid = */ propdef);
+ }
+
+ [[nodiscard]] bool addPropertyDefinition(ListNodeType literal, Node key,
+ Node val) {
+ BinaryNode* propdef;
+ MOZ_TRY_VAR_OR_RETURN(propdef, newPropertyDefinition(key, val), false);
+ addPropertyDefinition(literal, propdef);
+ return true;
+ }
+
+ [[nodiscard]] bool addShorthand(ListNodeType literal, NameNodeType name,
+ NameNodeType expr) {
+ MOZ_ASSERT(
+ literal->isKind(ParseNodeKind::ObjectExpr) ||
+ IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
+ MOZ_ASSERT(name->isKind(ParseNodeKind::ObjectPropertyName));
+ MOZ_ASSERT(expr->isKind(ParseNodeKind::Name));
+ MOZ_ASSERT(name->atom() == expr->atom());
+
+ literal->setHasNonConstInitializer();
+ BinaryNode* propdef;
+ MOZ_TRY_VAR_OR_RETURN(
+ propdef, newBinary(ParseNodeKind::Shorthand, name, expr), false);
+ addList(/* list = */ literal, /* kid = */ propdef);
+ return true;
+ }
+
+ [[nodiscard]] bool addSpreadProperty(ListNodeType literal, uint32_t begin,
+ Node inner) {
+ MOZ_ASSERT(
+ literal->isKind(ParseNodeKind::ObjectExpr) ||
+ IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
+
+ literal->setHasNonConstInitializer();
+ ParseNode* spread;
+ MOZ_TRY_VAR_OR_RETURN(spread, newSpread(begin, inner), false);
+ addList(/* list = */ literal, /* kid = */ spread);
+ return true;
+ }
+
+ [[nodiscard]] bool addObjectMethodDefinition(ListNodeType literal, Node key,
+ FunctionNodeType funNode,
+ AccessorType atype) {
+ literal->setHasNonConstInitializer();
+
+ checkAndSetIsDirectRHSAnonFunction(funNode);
+
+ ParseNode* propdef;
+ MOZ_TRY_VAR_OR_RETURN(
+ propdef, newObjectMethodOrPropertyDefinition(key, funNode, atype),
+ false);
+ addList(/* list = */ literal, /* kid = */ propdef);
+ return true;
+ }
+
+ [[nodiscard]] ClassMethodResult newDefaultClassConstructor(
+ Node key, FunctionNodeType funNode) {
+ MOZ_ASSERT(isUsableAsObjectPropertyName(key));
+
+ checkAndSetIsDirectRHSAnonFunction(funNode);
+
+ return newResult<ClassMethod>(
+ ParseNodeKind::DefaultConstructor, key, funNode, AccessorType::None,
+ /* isStatic = */ false, /* initializeIfPrivate = */ nullptr
+#ifdef ENABLE_DECORATORS
+ ,
+ /* decorators = */ nullptr
+#endif
+ );
+ }
+
+ [[nodiscard]] ClassMethodResult newClassMethodDefinition(
+ Node key, FunctionNodeType funNode, AccessorType atype, bool isStatic,
+ mozilla::Maybe<FunctionNodeType> initializerIfPrivate
+#ifdef ENABLE_DECORATORS
+ ,
+ ListNodeType decorators
+#endif
+ ) {
+ MOZ_ASSERT(isUsableAsObjectPropertyName(key));
+
+ checkAndSetIsDirectRHSAnonFunction(funNode);
+
+ if (initializerIfPrivate.isSome()) {
+ return newResult<ClassMethod>(ParseNodeKind::ClassMethod, key, funNode,
+ atype, isStatic,
+ initializerIfPrivate.value()
+#ifdef ENABLE_DECORATORS
+ ,
+ decorators
+#endif
+ );
+ }
+ return newResult<ClassMethod>(ParseNodeKind::ClassMethod, key, funNode,
+ atype, isStatic,
+ /* initializeIfPrivate = */ nullptr
+#ifdef ENABLE_DECORATORS
+ ,
+ decorators
+#endif
+ );
+ }
+
+ [[nodiscard]] ClassFieldResult newClassFieldDefinition(
+ Node name, FunctionNodeType initializer, bool isStatic
+#ifdef ENABLE_DECORATORS
+ ,
+ ListNodeType decorators, ClassMethodType accessorGetterNode,
+ ClassMethodType accessorSetterNode
+#endif
+ ) {
+ MOZ_ASSERT(isUsableAsObjectPropertyName(name));
+
+ return newResult<ClassField>(name, initializer, isStatic
+#if ENABLE_DECORATORS
+ ,
+ decorators, accessorGetterNode,
+ accessorSetterNode
+#endif
+ );
+ }
+
+ [[nodiscard]] StaticClassBlockResult newStaticClassBlock(
+ FunctionNodeType block) {
+ return newResult<StaticClassBlock>(block);
+ }
+
+ [[nodiscard]] bool addClassMemberDefinition(ListNodeType memberList,
+ Node member) {
+ MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
+ // Constructors can be surrounded by LexicalScopes.
+ MOZ_ASSERT(member->isKind(ParseNodeKind::DefaultConstructor) ||
+ member->isKind(ParseNodeKind::ClassMethod) ||
+ member->isKind(ParseNodeKind::ClassField) ||
+ member->isKind(ParseNodeKind::StaticClassBlock) ||
+ (member->isKind(ParseNodeKind::LexicalScope) &&
+ member->as<LexicalScopeNode>().scopeBody()->is<ClassMethod>()));
+
+ addList(/* list = */ memberList, /* kid = */ member);
+ return true;
+ }
+
+ UnaryNodeResult newInitialYieldExpression(uint32_t begin, Node gen) {
+ TokenPos pos(begin, begin + 1);
+ return newResult<UnaryNode>(ParseNodeKind::InitialYield, pos, gen);
+ }
+
+ UnaryNodeResult newYieldExpression(uint32_t begin, Node value) {
+ TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
+ return newResult<UnaryNode>(ParseNodeKind::YieldExpr, pos, value);
+ }
+
+ UnaryNodeResult newYieldStarExpression(uint32_t begin, Node value) {
+ TokenPos pos(begin, value->pn_pos.end);
+ return newResult<UnaryNode>(ParseNodeKind::YieldStarExpr, pos, value);
+ }
+
+ UnaryNodeResult newAwaitExpression(uint32_t begin, Node value) {
+ TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
+ return newResult<UnaryNode>(ParseNodeKind::AwaitExpr, pos, value);
+ }
+
+ UnaryNodeResult newOptionalChain(uint32_t begin, Node value) {
+ TokenPos pos(begin, value->pn_pos.end);
+ return newResult<UnaryNode>(ParseNodeKind::OptionalChain, pos, value);
+ }
+
+ // Statements
+
+ ListNodeResult newStatementList(const TokenPos& pos) {
+ return newResult<ListNode>(ParseNodeKind::StatementList, pos);
+ }
+
+ [[nodiscard]] bool isFunctionStmt(Node stmt) {
+ while (stmt->isKind(ParseNodeKind::LabelStmt)) {
+ stmt = stmt->as<LabeledStatement>().statement();
+ }
+ return stmt->is<FunctionNode>();
+ }
+
+ void addStatementToList(ListNodeType list, Node stmt) {
+ MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
+
+ addList(/* list = */ list, /* kid = */ stmt);
+
+ if (isFunctionStmt(stmt)) {
+ // Notify the emitter that the block contains body-level function
+ // definitions that should be processed before the rest of nodes.
+ list->setHasTopLevelFunctionDeclarations();
+ }
+ }
+
+ void setListEndPosition(ListNodeType list, const TokenPos& pos) {
+ MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
+ list->pn_pos.end = pos.end;
+ }
+
+ void addCaseStatementToList(ListNodeType list, CaseClauseType caseClause) {
+ MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
+
+ addList(/* list = */ list, /* kid = */ caseClause);
+
+ if (caseClause->statementList()->hasTopLevelFunctionDeclarations()) {
+ list->setHasTopLevelFunctionDeclarations();
+ }
+ }
+
+ [[nodiscard]] bool prependInitialYield(ListNodeType stmtList, Node genName) {
+ MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
+
+ TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
+ NullaryNode* makeGen;
+ MOZ_TRY_VAR_OR_RETURN(
+ makeGen, newResult<NullaryNode>(ParseNodeKind::Generator, yieldPos),
+ false);
+
+ ParseNode* genInit;
+ MOZ_TRY_VAR_OR_RETURN(
+ genInit,
+ newAssignment(ParseNodeKind::AssignExpr, /* lhs = */ genName,
+ /* rhs = */ makeGen),
+ false);
+
+ UnaryNode* initialYield;
+ MOZ_TRY_VAR_OR_RETURN(initialYield,
+ newInitialYieldExpression(yieldPos.begin, genInit),
+ false);
+
+ stmtList->prepend(initialYield);
+ return true;
+ }
+
+ BinaryNodeResult newSetThis(Node thisName, Node value) {
+ return newBinary(ParseNodeKind::SetThis, thisName, value);
+ }
+
+ NullaryNodeResult newEmptyStatement(const TokenPos& pos) {
+ return newResult<NullaryNode>(ParseNodeKind::EmptyStmt, pos);
+ }
+
+ BinaryNodeResult newImportAttribute(Node keyNode, Node valueNode) {
+ return newBinary(ParseNodeKind::ImportAttribute, keyNode, valueNode);
+ }
+
+ BinaryNodeResult newModuleRequest(Node moduleSpec, Node importAttributeList,
+ const TokenPos& pos) {
+ return newResult<BinaryNode>(ParseNodeKind::ImportModuleRequest, pos,
+ moduleSpec, importAttributeList);
+ }
+
+ BinaryNodeResult newImportDeclaration(Node importSpecSet, Node moduleRequest,
+ const TokenPos& pos) {
+ return newResult<BinaryNode>(ParseNodeKind::ImportDecl, pos, importSpecSet,
+ moduleRequest);
+ }
+
+ BinaryNodeResult newImportSpec(Node importNameNode, Node bindingName) {
+ return newBinary(ParseNodeKind::ImportSpec, importNameNode, bindingName);
+ }
+
+ UnaryNodeResult newImportNamespaceSpec(uint32_t begin, Node bindingName) {
+ return newUnary(ParseNodeKind::ImportNamespaceSpec, begin, bindingName);
+ }
+
+ UnaryNodeResult newExportDeclaration(Node kid, const TokenPos& pos) {
+ return newResult<UnaryNode>(ParseNodeKind::ExportStmt, pos, kid);
+ }
+
+ BinaryNodeResult newExportFromDeclaration(uint32_t begin, Node exportSpecSet,
+ Node moduleRequest) {
+ BinaryNode* decl;
+ MOZ_TRY_VAR(decl, newResult<BinaryNode>(ParseNodeKind::ExportFromStmt,
+ exportSpecSet, moduleRequest));
+ decl->pn_pos.begin = begin;
+ return decl;
+ }
+
+ BinaryNodeResult newExportDefaultDeclaration(Node kid, Node maybeBinding,
+ const TokenPos& pos) {
+ if (maybeBinding) {
+ MOZ_ASSERT(maybeBinding->isKind(ParseNodeKind::Name));
+ MOZ_ASSERT(!maybeBinding->isInParens());
+
+ checkAndSetIsDirectRHSAnonFunction(kid);
+ }
+
+ return newResult<BinaryNode>(ParseNodeKind::ExportDefaultStmt, pos, kid,
+ maybeBinding);
+ }
+
+ BinaryNodeResult newExportSpec(Node bindingName, Node exportName) {
+ return newBinary(ParseNodeKind::ExportSpec, bindingName, exportName);
+ }
+
+ UnaryNodeResult newExportNamespaceSpec(uint32_t begin, Node exportName) {
+ return newUnary(ParseNodeKind::ExportNamespaceSpec, begin, exportName);
+ }
+
+ NullaryNodeResult newExportBatchSpec(const TokenPos& pos) {
+ return newResult<NullaryNode>(ParseNodeKind::ExportBatchSpecStmt, pos);
+ }
+
+ BinaryNodeResult newImportMeta(NullaryNodeType importHolder,
+ NullaryNodeType metaHolder) {
+ return newResult<BinaryNode>(ParseNodeKind::ImportMetaExpr, importHolder,
+ metaHolder);
+ }
+
+ BinaryNodeResult newCallImport(NullaryNodeType importHolder, Node singleArg) {
+ return newResult<BinaryNode>(ParseNodeKind::CallImportExpr, importHolder,
+ singleArg);
+ }
+
+ BinaryNodeResult newCallImportSpec(Node specifierArg, Node optionalArg) {
+ return newResult<BinaryNode>(ParseNodeKind::CallImportSpec, specifierArg,
+ optionalArg);
+ }
+
+ UnaryNodeResult newExprStatement(Node expr, uint32_t end) {
+ MOZ_ASSERT(expr->pn_pos.end <= end);
+ return newResult<UnaryNode>(ParseNodeKind::ExpressionStmt,
+ TokenPos(expr->pn_pos.begin, end), expr);
+ }
+
+ TernaryNodeResult newIfStatement(uint32_t begin, Node cond, Node thenBranch,
+ Node elseBranch) {
+ TernaryNode* node;
+ MOZ_TRY_VAR(node, newResult<TernaryNode>(ParseNodeKind::IfStmt, cond,
+ thenBranch, elseBranch));
+ node->pn_pos.begin = begin;
+ return node;
+ }
+
+ BinaryNodeResult newDoWhileStatement(Node body, Node cond,
+ const TokenPos& pos) {
+ return newResult<BinaryNode>(ParseNodeKind::DoWhileStmt, pos, body, cond);
+ }
+
+ BinaryNodeResult newWhileStatement(uint32_t begin, Node cond, Node body) {
+ TokenPos pos(begin, body->pn_pos.end);
+ return newResult<BinaryNode>(ParseNodeKind::WhileStmt, pos, cond, body);
+ }
+
+ ForNodeResult newForStatement(uint32_t begin, TernaryNodeType forHead,
+ Node body, unsigned iflags) {
+ return newResult<ForNode>(TokenPos(begin, body->pn_pos.end), forHead, body,
+ iflags);
+ }
+
+ TernaryNodeResult newForHead(Node init, Node test, Node update,
+ const TokenPos& pos) {
+ return newResult<TernaryNode>(ParseNodeKind::ForHead, init, test, update,
+ pos);
+ }
+
+ TernaryNodeResult newForInOrOfHead(ParseNodeKind kind, Node target,
+ Node iteratedExpr, const TokenPos& pos) {
+ MOZ_ASSERT(kind == ParseNodeKind::ForIn || kind == ParseNodeKind::ForOf);
+ return newResult<TernaryNode>(kind, target, nullptr, iteratedExpr, pos);
+ }
+
+ SwitchStatementResult newSwitchStatement(
+ uint32_t begin, Node discriminant,
+ LexicalScopeNodeType lexicalForCaseList, bool hasDefault) {
+ return newResult<SwitchStatement>(begin, discriminant, lexicalForCaseList,
+ hasDefault);
+ }
+
+ CaseClauseResult newCaseOrDefault(uint32_t begin, Node expr, Node body) {
+ return newResult<CaseClause>(expr, body, begin);
+ }
+
+ ContinueStatementResult newContinueStatement(TaggedParserAtomIndex label,
+ const TokenPos& pos) {
+ return newResult<ContinueStatement>(label, pos);
+ }
+
+ BreakStatementResult newBreakStatement(TaggedParserAtomIndex label,
+ const TokenPos& pos) {
+ return newResult<BreakStatement>(label, pos);
+ }
+
+ UnaryNodeResult newReturnStatement(Node expr, const TokenPos& pos) {
+ MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
+ return newResult<UnaryNode>(ParseNodeKind::ReturnStmt, pos, expr);
+ }
+
+ UnaryNodeResult newExpressionBody(Node expr) {
+ return newResult<UnaryNode>(ParseNodeKind::ReturnStmt, expr->pn_pos, expr);
+ }
+
+ BinaryNodeResult newWithStatement(uint32_t begin, Node expr, Node body) {
+ return newResult<BinaryNode>(ParseNodeKind::WithStmt,
+ TokenPos(begin, body->pn_pos.end), expr, body);
+ }
+
+ LabeledStatementResult newLabeledStatement(TaggedParserAtomIndex label,
+ Node stmt, uint32_t begin) {
+ return newResult<LabeledStatement>(label, stmt, begin);
+ }
+
+ UnaryNodeResult newThrowStatement(Node expr, const TokenPos& pos) {
+ MOZ_ASSERT(pos.encloses(expr->pn_pos));
+ return newResult<UnaryNode>(ParseNodeKind::ThrowStmt, pos, expr);
+ }
+
+ TernaryNodeResult newTryStatement(uint32_t begin, Node body,
+ LexicalScopeNodeType catchScope,
+ Node finallyBlock) {
+ return newResult<TryNode>(begin, body, catchScope, finallyBlock);
+ }
+
+ DebuggerStatementResult newDebuggerStatement(const TokenPos& pos) {
+ return newResult<DebuggerStatement>(pos);
+ }
+
+ NameNodeResult newPropertyName(TaggedParserAtomIndex name,
+ const TokenPos& pos) {
+ return newResult<NameNode>(ParseNodeKind::PropertyNameExpr, name, pos);
+ }
+
+ PropertyAccessResult newPropertyAccess(Node expr, NameNodeType key) {
+ return newResult<PropertyAccess>(expr, key, expr->pn_pos.begin,
+ key->pn_pos.end);
+ }
+
+ PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) {
+ return newResult<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
+ }
+
+ OptionalPropertyAccessResult newOptionalPropertyAccess(Node expr,
+ NameNodeType key) {
+ return newResult<OptionalPropertyAccess>(expr, key, expr->pn_pos.begin,
+ key->pn_pos.end);
+ }
+
+ OptionalPropertyByValueResult newOptionalPropertyByValue(Node lhs, Node index,
+ uint32_t end) {
+ return newResult<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin,
+ end);
+ }
+
+ PrivateMemberAccessResult newPrivateMemberAccess(Node lhs,
+ NameNodeType privateName,
+ uint32_t end) {
+ return newResult<PrivateMemberAccess>(lhs, privateName, lhs->pn_pos.begin,
+ end);
+ }
+
+ OptionalPrivateMemberAccessResult newOptionalPrivateMemberAccess(
+ Node lhs, NameNodeType privateName, uint32_t end) {
+ return newResult<OptionalPrivateMemberAccess>(lhs, privateName,
+ lhs->pn_pos.begin, end);
+ }
+
+ bool setupCatchScope(LexicalScopeNodeType lexicalScope, Node catchName,
+ Node catchBody) {
+ BinaryNode* catchClause;
+ if (catchName) {
+ MOZ_TRY_VAR_OR_RETURN(
+ catchClause,
+ newResult<BinaryNode>(ParseNodeKind::Catch, catchName, catchBody),
+ false);
+ } else {
+ MOZ_TRY_VAR_OR_RETURN(
+ catchClause,
+ newResult<BinaryNode>(ParseNodeKind::Catch, catchBody->pn_pos,
+ catchName, catchBody),
+ false);
+ }
+ lexicalScope->setScopeBody(catchClause);
+ return true;
+ }
+
+ [[nodiscard]] inline bool setLastFunctionFormalParameterDefault(
+ FunctionNodeType funNode, Node defaultValue);
+
+ void checkAndSetIsDirectRHSAnonFunction(Node pn) {
+ if (IsAnonymousFunctionDefinition(pn)) {
+ pn->setDirectRHSAnonFunction(true);
+ }
+ }
+
+ ParamsBodyNodeResult newParamsBody(const TokenPos& pos) {
+ return newResult<ParamsBodyNode>(pos);
+ }
+
+ FunctionNodeResult newFunction(FunctionSyntaxKind syntaxKind,
+ const TokenPos& pos) {
+ return newResult<FunctionNode>(syntaxKind, pos);
+ }
+
+ BinaryNodeResult newObjectMethodOrPropertyDefinition(Node key, Node value,
+ AccessorType atype) {
+ MOZ_ASSERT(isUsableAsObjectPropertyName(key));
+
+ return newResult<PropertyDefinition>(key, value, atype);
+ }
+
+ void setFunctionFormalParametersAndBody(FunctionNodeType funNode,
+ ParamsBodyNodeType paramsBody) {
+ funNode->setBody(paramsBody);
+ }
+ void setFunctionBox(FunctionNodeType funNode, FunctionBox* funbox) {
+ funNode->setFunbox(funbox);
+ funbox->functionNode = funNode;
+ }
+ void addFunctionFormalParameter(FunctionNodeType funNode, Node argpn) {
+ addList(/* list = */ funNode->body(), /* kid = */ argpn);
+ }
+ void setFunctionBody(FunctionNodeType funNode, LexicalScopeNodeType body) {
+ addList(/* list = */ funNode->body(), /* kid = */ body);
+ }
+
+ ModuleNodeResult newModule(const TokenPos& pos) {
+ return newResult<ModuleNode>(pos);
+ }
+
+ LexicalScopeNodeResult newLexicalScope(LexicalScope::ParserData* bindings,
+ Node body,
+ ScopeKind kind = ScopeKind::Lexical) {
+ return newResult<LexicalScopeNode>(bindings, body, kind);
+ }
+
+ ClassBodyScopeNodeResult newClassBodyScope(
+ ClassBodyScope::ParserData* bindings, ListNodeType body) {
+ return newResult<ClassBodyScopeNode>(bindings, body);
+ }
+
+ CallNodeResult newNewExpression(uint32_t begin, Node ctor, ListNodeType args,
+ bool isSpread) {
+ return newResult<CallNode>(ParseNodeKind::NewExpr,
+ isSpread ? JSOp::SpreadNew : JSOp::New,
+ TokenPos(begin, args->pn_pos.end), ctor, args);
+ }
+
+ AssignmentNodeResult newAssignment(ParseNodeKind kind, Node lhs, Node rhs) {
+ if ((kind == ParseNodeKind::AssignExpr ||
+ kind == ParseNodeKind::CoalesceAssignExpr ||
+ kind == ParseNodeKind::OrAssignExpr ||
+ kind == ParseNodeKind::AndAssignExpr) &&
+ lhs->isKind(ParseNodeKind::Name) && !lhs->isInParens()) {
+ checkAndSetIsDirectRHSAnonFunction(rhs);
+ }
+
+ return newResult<AssignmentNode>(kind, lhs, rhs);
+ }
+
+ BinaryNodeResult newInitExpr(Node lhs, Node rhs) {
+ TokenPos pos(lhs->pn_pos.begin, rhs->pn_pos.end);
+ return newResult<BinaryNode>(ParseNodeKind::InitExpr, pos, lhs, rhs);
+ }
+
+ bool isUnparenthesizedAssignment(Node node) {
+ if ((node->isKind(ParseNodeKind::AssignExpr)) && !node->isInParens()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool isUnparenthesizedUnaryExpression(Node node) {
+ if (!node->isInParens()) {
+ ParseNodeKind kind = node->getKind();
+ return kind == ParseNodeKind::VoidExpr ||
+ kind == ParseNodeKind::NotExpr ||
+ kind == ParseNodeKind::BitNotExpr ||
+ kind == ParseNodeKind::PosExpr || kind == ParseNodeKind::NegExpr ||
+ kind == ParseNodeKind::AwaitExpr || IsTypeofKind(kind) ||
+ IsDeleteKind(kind);
+ }
+ return false;
+ }
+
+ bool isReturnStatement(Node node) {
+ return node->isKind(ParseNodeKind::ReturnStmt);
+ }
+
+ bool isStatementPermittedAfterReturnStatement(Node node) {
+ ParseNodeKind kind = node->getKind();
+ return kind == ParseNodeKind::Function || kind == ParseNodeKind::VarStmt ||
+ kind == ParseNodeKind::BreakStmt ||
+ kind == ParseNodeKind::ThrowStmt || kind == ParseNodeKind::EmptyStmt;
+ }
+
+ bool isSuperBase(Node node) { return node->isKind(ParseNodeKind::SuperBase); }
+
+ bool isUsableAsObjectPropertyName(Node node) {
+ return node->isKind(ParseNodeKind::NumberExpr) ||
+ node->isKind(ParseNodeKind::BigIntExpr) ||
+ node->isKind(ParseNodeKind::ObjectPropertyName) ||
+ node->isKind(ParseNodeKind::StringExpr) ||
+ node->isKind(ParseNodeKind::ComputedName) ||
+ node->isKind(ParseNodeKind::PrivateName);
+ }
+
+ AssignmentNodeResult finishInitializerAssignment(NameNodeType nameNode,
+ Node init) {
+ MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
+ MOZ_ASSERT(!nameNode->isInParens());
+
+ checkAndSetIsDirectRHSAnonFunction(init);
+
+ return newAssignment(ParseNodeKind::AssignExpr, nameNode, init);
+ }
+
+ void setBeginPosition(Node pn, Node oth) {
+ setBeginPosition(pn, oth->pn_pos.begin);
+ }
+ void setBeginPosition(Node pn, uint32_t begin) {
+ pn->pn_pos.begin = begin;
+ MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
+ }
+
+ void setEndPosition(Node pn, Node oth) {
+ setEndPosition(pn, oth->pn_pos.end);
+ }
+ void setEndPosition(Node pn, uint32_t end) {
+ pn->pn_pos.end = end;
+ MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
+ }
+
+ uint32_t getFunctionNameOffset(Node func, TokenStreamAnyChars& ts) {
+ return func->pn_pos.begin;
+ }
+
+ ListNodeResult newList(ParseNodeKind kind, const TokenPos& pos) {
+ auto list = newResult<ListNode>(kind, pos);
+ MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<DeclarationListNode>());
+ MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<ParamsBodyNode>());
+ return list;
+ }
+
+ ListNodeResult newList(ParseNodeKind kind, Node kid) {
+ auto list = newResult<ListNode>(kind, kid);
+ MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<DeclarationListNode>());
+ MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<ParamsBodyNode>());
+ return list;
+ }
+
+ DeclarationListNodeResult newDeclarationList(ParseNodeKind kind,
+ const TokenPos& pos) {
+ return newResult<DeclarationListNode>(kind, pos);
+ }
+
+ ListNodeResult newCommaExpressionList(Node kid) {
+ return newResult<ListNode>(ParseNodeKind::CommaExpr, kid);
+ }
+
+ void addList(ListNodeType list, Node kid) { list->append(kid); }
+
+ void setListHasNonConstInitializer(ListNodeType literal) {
+ literal->setHasNonConstInitializer();
+ }
+
+ // NOTE: This is infallible.
+ template <typename NodeType>
+ [[nodiscard]] NodeType parenthesize(NodeType node) {
+ node->setInParens(true);
+ return node;
+ }
+
+ // NOTE: This is infallible.
+ template <typename NodeType>
+ [[nodiscard]] NodeType setLikelyIIFE(NodeType node) {
+ return parenthesize(node);
+ }
+
+ bool isName(Node node) { return node->isKind(ParseNodeKind::Name); }
+
+ bool isArgumentsName(Node node) {
+ return node->isKind(ParseNodeKind::Name) &&
+ node->as<NameNode>().atom() ==
+ TaggedParserAtomIndex::WellKnown::arguments();
+ }
+
+ bool isEvalName(Node node) {
+ return node->isKind(ParseNodeKind::Name) &&
+ node->as<NameNode>().atom() ==
+ TaggedParserAtomIndex::WellKnown::eval();
+ }
+
+ bool isAsyncKeyword(Node node) {
+ return node->isKind(ParseNodeKind::Name) &&
+ node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
+ node->as<NameNode>().atom() ==
+ TaggedParserAtomIndex::WellKnown::async();
+ }
+
+ bool isPrivateName(Node node) {
+ return node->isKind(ParseNodeKind::PrivateName);
+ }
+
+ bool isPrivateMemberAccess(Node node) {
+ if (node->isKind(ParseNodeKind::OptionalChain)) {
+ return isPrivateMemberAccess(node->as<UnaryNode>().kid());
+ }
+ return node->is<PrivateMemberAccessBase>();
+ }
+
+ TaggedParserAtomIndex maybeDottedProperty(Node pn) {
+ return pn->is<PropertyAccessBase>() ? pn->as<PropertyAccessBase>().name()
+ : TaggedParserAtomIndex::null();
+ }
+ TaggedParserAtomIndex isStringExprStatement(Node pn, TokenPos* pos) {
+ if (pn->is<UnaryNode>()) {
+ UnaryNode* unary = &pn->as<UnaryNode>();
+ if (auto atom = unary->isStringExprStatement()) {
+ *pos = unary->kid()->pn_pos;
+ return atom;
+ }
+ }
+ return TaggedParserAtomIndex::null();
+ }
+
+ bool reuseLazyInnerFunctions() { return reuseGCThings; }
+ bool reuseClosedOverBindings() { return reuseGCThings; }
+ bool reuseRegexpSyntaxParse() { return reuseGCThings; }
+ void nextLazyInnerFunction() { lazyInnerFunctionIndex++; }
+ TaggedParserAtomIndex nextLazyClosedOverBinding() {
+ // Trailing nullptrs were elided in PerHandlerParser::finishFunction().
+ auto closedOverBindings = previousParseCache_.closedOverBindings();
+ if (lazyClosedOverBindingIndex >= closedOverBindings.Length()) {
+ return TaggedParserAtomIndex::null();
+ }
+
+ return closedOverBindings[lazyClosedOverBindingIndex++];
+ }
+ const ScriptStencil& cachedScriptData() const {
+ // lazyInnerFunctionIndex is incremented with nextLazyInnferFunction before
+ // reading the content, thus we need -1 to access the element that we just
+ // skipped.
+ return previousParseCache_.scriptData(lazyInnerFunctionIndex - 1);
+ }
+ const ScriptStencilExtra& cachedScriptExtra() const {
+ // lazyInnerFunctionIndex is incremented with nextLazyInnferFunction before
+ // reading the content, thus we need -1 to access the element that we just
+ // skipped.
+ return previousParseCache_.scriptExtra(lazyInnerFunctionIndex - 1);
+ }
+
+ void setPrivateNameKind(Node node, PrivateNameKind kind) {
+ MOZ_ASSERT(node->is<NameNode>());
+ node->as<NameNode>().setPrivateNameKind(kind);
+ }
+};
+
+inline bool FullParseHandler::setLastFunctionFormalParameterDefault(
+ FunctionNodeType funNode, Node defaultValue) {
+ ParamsBodyNode* body = funNode->body();
+ ParseNode* arg = body->last();
+ ParseNode* pn;
+ MOZ_TRY_VAR_OR_RETURN(
+ pn, newAssignment(ParseNodeKind::AssignExpr, arg, defaultValue), false);
+
+ body->replaceLast(pn);
+ return true;
+}
+
+} // namespace frontend
+} // namespace js
+
+#endif /* frontend_FullParseHandler_h */