From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/frontend/FullParseHandler.h | 1226 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1226 insertions(+) create mode 100644 js/src/frontend/FullParseHandler.h (limited to 'js/src/frontend/FullParseHandler.h') 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 // std::nullptr_t +#include + +#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 { + static const bool value = true; +}; + +#define DEFINE_UNUSED_ZERO(typeName) \ + template <> \ + struct mozilla::detail::UnusedZero { \ + 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(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; + +#define DECLARE_TYPE(typeName) \ + using typeName##Type = typeName*; \ + using typeName##Result = mozilla::Result; + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + + template + inline mozilla::Result newResult(Args&&... args) { + auto* node = new_(std::forward(args)...); + if (!node) { + return mozilla::Result(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(); \ + } + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) +#undef DECLARE_AS + + NameNodeResult newName(TaggedParserAtomIndex name, const TokenPos& pos) { + return newResult(ParseNodeKind::Name, name, pos); + } + + UnaryNodeResult newComputedName(Node expr, uint32_t begin, uint32_t end) { + TokenPos pos(begin, end); + return newResult(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(ParseNodeKind::ComputedName, pos, expr)); + node->setSyntheticComputedName(); + return node; + } + + NameNodeResult newObjectLiteralPropertyName(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return newResult(ParseNodeKind::ObjectPropertyName, atom, pos); + } + + NameNodeResult newPrivateName(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return newResult(ParseNodeKind::PrivateName, atom, pos); + } + + NumericLiteralResult newNumber(double value, DecimalPoint decimalPoint, + const TokenPos& pos) { + return newResult(value, decimalPoint, pos); + } + + BigIntLiteralResult newBigInt(BigIntIndex index, bool isZero, + const TokenPos& pos) { + return newResult(index, isZero, pos); + } + + BooleanLiteralResult newBooleanLiteral(bool cond, const TokenPos& pos) { + return newResult(cond, pos); + } + + NameNodeResult newStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return newResult(ParseNodeKind::StringExpr, atom, pos); + } + + NameNodeResult newTemplateStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return newResult(ParseNodeKind::TemplateStringExpr, atom, pos); + } + + CallSiteNodeResult newCallSiteObject(uint32_t begin) { + CallSiteNode* callSiteObj; + MOZ_TRY_VAR(callSiteObj, newResult(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(pos, thisName); + } + + NullLiteralResult newNullLiteral(const TokenPos& pos) { + return newResult(pos); + } + + RawUndefinedLiteralResult newRawUndefinedLiteral(const TokenPos& pos) { + return newResult(pos); + } + + RegExpLiteralResult newRegExp(RegExpIndex index, const TokenPos& pos) { + return newResult(index, pos); + } + + ConditionalExpressionResult newConditional(Node cond, Node thenExpr, + Node elseExpr) { + return newResult(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().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(kind, pos, kid); + } + + UnaryNodeResult newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) { + TokenPos pos(begin, kid->pn_pos.end); + return newResult(kind, pos, kid); + } + + UnaryNodeResult newSpread(uint32_t begin, Node kid) { + TokenPos pos(begin, kid->pn_pos.end); + return newResult(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(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(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(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(ParseNodeKind::CallExpr, callOp, callee, args); + } + + CallNodeResult newOptionalCall(Node callee, ListNodeType args, JSOp callOp) { + return newResult(ParseNodeKind::OptionalCallExpr, callOp, callee, + args); + } + + ListNodeResult newArguments(const TokenPos& pos) { + return newResult(ParseNodeKind::Arguments, pos); + } + + CallNodeResult newSuperCall(Node callee, ListNodeType args, bool isSpread) { + return newResult( + ParseNodeKind::SuperCallExpr, + isSpread ? JSOp::SpreadSuperCall : JSOp::SuperCall, callee, args); + } + + CallNodeResult newTaggedTemplate(Node tag, ListNodeType args, JSOp callOp) { + return newResult(ParseNodeKind::TaggedTemplateExpr, callOp, tag, + args); + } + + ListNodeResult newObjectLiteral(uint32_t begin) { + return newResult(ParseNodeKind::ObjectExpr, + TokenPos(begin, begin + 1)); + } + +#ifdef ENABLE_RECORD_TUPLE + ListNodeResult newRecordLiteral(uint32_t begin) { + return newResult(ParseNodeKind::RecordExpr, + TokenPos(begin, begin + 1)); + } + + ListNodeResult newTupleLiteral(uint32_t begin) { + return newResult(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(name, heritage, memberBlock, +#ifdef ENABLE_DECORATORS + decorators, addInitializerFunction, +#endif + pos); + } + ListNodeResult newClassMemberList(uint32_t begin) { + return newResult(ParseNodeKind::ClassMemberList, + TokenPos(begin, begin + 1)); + } + ClassNamesResult newClassNames(Node outer, Node inner, const TokenPos& pos) { + return newResult(outer, inner, pos); + } + NewTargetNodeResult newNewTarget(NullaryNodeType newHolder, + NullaryNodeType targetHolder, + NameNodeType newTargetName) { + return newResult(newHolder, targetHolder, newTargetName); + } + NullaryNodeResult newPosHolder(const TokenPos& pos) { + return newResult(ParseNodeKind::PosHolder, pos); + } + UnaryNodeResult newSuperBase(Node thisName, const TokenPos& pos) { + return newResult(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(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( + 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 initializerIfPrivate +#ifdef ENABLE_DECORATORS + , + ListNodeType decorators +#endif + ) { + MOZ_ASSERT(isUsableAsObjectPropertyName(key)); + + checkAndSetIsDirectRHSAnonFunction(funNode); + + if (initializerIfPrivate.isSome()) { + return newResult(ParseNodeKind::ClassMethod, key, funNode, + atype, isStatic, + initializerIfPrivate.value() +#ifdef ENABLE_DECORATORS + , + decorators +#endif + ); + } + return newResult(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(name, initializer, isStatic +#if ENABLE_DECORATORS + , + decorators, accessorGetterNode, + accessorSetterNode +#endif + ); + } + + [[nodiscard]] StaticClassBlockResult newStaticClassBlock( + FunctionNodeType block) { + return newResult(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().scopeBody()->is())); + + addList(/* list = */ memberList, /* kid = */ member); + return true; + } + + UnaryNodeResult newInitialYieldExpression(uint32_t begin, Node gen) { + TokenPos pos(begin, begin + 1); + return newResult(ParseNodeKind::InitialYield, pos, gen); + } + + UnaryNodeResult newYieldExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); + return newResult(ParseNodeKind::YieldExpr, pos, value); + } + + UnaryNodeResult newYieldStarExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value->pn_pos.end); + return newResult(ParseNodeKind::YieldStarExpr, pos, value); + } + + UnaryNodeResult newAwaitExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); + return newResult(ParseNodeKind::AwaitExpr, pos, value); + } + + UnaryNodeResult newOptionalChain(uint32_t begin, Node value) { + TokenPos pos(begin, value->pn_pos.end); + return newResult(ParseNodeKind::OptionalChain, pos, value); + } + + // Statements + + ListNodeResult newStatementList(const TokenPos& pos) { + return newResult(ParseNodeKind::StatementList, pos); + } + + [[nodiscard]] bool isFunctionStmt(Node stmt) { + while (stmt->isKind(ParseNodeKind::LabelStmt)) { + stmt = stmt->as().statement(); + } + return stmt->is(); + } + + 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(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(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(ParseNodeKind::ImportModuleRequest, pos, + moduleSpec, importAttributeList); + } + + BinaryNodeResult newImportDeclaration(Node importSpecSet, Node moduleRequest, + const TokenPos& pos) { + return newResult(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(ParseNodeKind::ExportStmt, pos, kid); + } + + BinaryNodeResult newExportFromDeclaration(uint32_t begin, Node exportSpecSet, + Node moduleRequest) { + BinaryNode* decl; + MOZ_TRY_VAR(decl, newResult(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(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(ParseNodeKind::ExportBatchSpecStmt, pos); + } + + BinaryNodeResult newImportMeta(NullaryNodeType importHolder, + NullaryNodeType metaHolder) { + return newResult(ParseNodeKind::ImportMetaExpr, importHolder, + metaHolder); + } + + BinaryNodeResult newCallImport(NullaryNodeType importHolder, Node singleArg) { + return newResult(ParseNodeKind::CallImportExpr, importHolder, + singleArg); + } + + BinaryNodeResult newCallImportSpec(Node specifierArg, Node optionalArg) { + return newResult(ParseNodeKind::CallImportSpec, specifierArg, + optionalArg); + } + + UnaryNodeResult newExprStatement(Node expr, uint32_t end) { + MOZ_ASSERT(expr->pn_pos.end <= end); + return newResult(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(ParseNodeKind::IfStmt, cond, + thenBranch, elseBranch)); + node->pn_pos.begin = begin; + return node; + } + + BinaryNodeResult newDoWhileStatement(Node body, Node cond, + const TokenPos& pos) { + return newResult(ParseNodeKind::DoWhileStmt, pos, body, cond); + } + + BinaryNodeResult newWhileStatement(uint32_t begin, Node cond, Node body) { + TokenPos pos(begin, body->pn_pos.end); + return newResult(ParseNodeKind::WhileStmt, pos, cond, body); + } + + ForNodeResult newForStatement(uint32_t begin, TernaryNodeType forHead, + Node body, unsigned iflags) { + return newResult(TokenPos(begin, body->pn_pos.end), forHead, body, + iflags); + } + + TernaryNodeResult newForHead(Node init, Node test, Node update, + const TokenPos& pos) { + return newResult(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(kind, target, nullptr, iteratedExpr, pos); + } + + SwitchStatementResult newSwitchStatement( + uint32_t begin, Node discriminant, + LexicalScopeNodeType lexicalForCaseList, bool hasDefault) { + return newResult(begin, discriminant, lexicalForCaseList, + hasDefault); + } + + CaseClauseResult newCaseOrDefault(uint32_t begin, Node expr, Node body) { + return newResult(expr, body, begin); + } + + ContinueStatementResult newContinueStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return newResult(label, pos); + } + + BreakStatementResult newBreakStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return newResult(label, pos); + } + + UnaryNodeResult newReturnStatement(Node expr, const TokenPos& pos) { + MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); + return newResult(ParseNodeKind::ReturnStmt, pos, expr); + } + + UnaryNodeResult newExpressionBody(Node expr) { + return newResult(ParseNodeKind::ReturnStmt, expr->pn_pos, expr); + } + + BinaryNodeResult newWithStatement(uint32_t begin, Node expr, Node body) { + return newResult(ParseNodeKind::WithStmt, + TokenPos(begin, body->pn_pos.end), expr, body); + } + + LabeledStatementResult newLabeledStatement(TaggedParserAtomIndex label, + Node stmt, uint32_t begin) { + return newResult(label, stmt, begin); + } + + UnaryNodeResult newThrowStatement(Node expr, const TokenPos& pos) { + MOZ_ASSERT(pos.encloses(expr->pn_pos)); + return newResult(ParseNodeKind::ThrowStmt, pos, expr); + } + + TernaryNodeResult newTryStatement(uint32_t begin, Node body, + LexicalScopeNodeType catchScope, + Node finallyBlock) { + return newResult(begin, body, catchScope, finallyBlock); + } + + DebuggerStatementResult newDebuggerStatement(const TokenPos& pos) { + return newResult(pos); + } + + NameNodeResult newPropertyName(TaggedParserAtomIndex name, + const TokenPos& pos) { + return newResult(ParseNodeKind::PropertyNameExpr, name, pos); + } + + PropertyAccessResult newPropertyAccess(Node expr, NameNodeType key) { + return newResult(expr, key, expr->pn_pos.begin, + key->pn_pos.end); + } + + PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) { + return newResult(lhs, index, lhs->pn_pos.begin, end); + } + + OptionalPropertyAccessResult newOptionalPropertyAccess(Node expr, + NameNodeType key) { + return newResult(expr, key, expr->pn_pos.begin, + key->pn_pos.end); + } + + OptionalPropertyByValueResult newOptionalPropertyByValue(Node lhs, Node index, + uint32_t end) { + return newResult(lhs, index, lhs->pn_pos.begin, + end); + } + + PrivateMemberAccessResult newPrivateMemberAccess(Node lhs, + NameNodeType privateName, + uint32_t end) { + return newResult(lhs, privateName, lhs->pn_pos.begin, + end); + } + + OptionalPrivateMemberAccessResult newOptionalPrivateMemberAccess( + Node lhs, NameNodeType privateName, uint32_t end) { + return newResult(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(ParseNodeKind::Catch, catchName, catchBody), + false); + } else { + MOZ_TRY_VAR_OR_RETURN( + catchClause, + newResult(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(pos); + } + + FunctionNodeResult newFunction(FunctionSyntaxKind syntaxKind, + const TokenPos& pos) { + return newResult(syntaxKind, pos); + } + + BinaryNodeResult newObjectMethodOrPropertyDefinition(Node key, Node value, + AccessorType atype) { + MOZ_ASSERT(isUsableAsObjectPropertyName(key)); + + return newResult(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(pos); + } + + LexicalScopeNodeResult newLexicalScope(LexicalScope::ParserData* bindings, + Node body, + ScopeKind kind = ScopeKind::Lexical) { + return newResult(bindings, body, kind); + } + + ClassBodyScopeNodeResult newClassBodyScope( + ClassBodyScope::ParserData* bindings, ListNodeType body) { + return newResult(bindings, body); + } + + CallNodeResult newNewExpression(uint32_t begin, Node ctor, ListNodeType args, + bool isSpread) { + return newResult(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(kind, lhs, rhs); + } + + BinaryNodeResult newInitExpr(Node lhs, Node rhs) { + TokenPos pos(lhs->pn_pos.begin, rhs->pn_pos.end); + return newResult(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(kind, pos); + MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is()); + MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is()); + return list; + } + + ListNodeResult newList(ParseNodeKind kind, Node kid) { + auto list = newResult(kind, kid); + MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is()); + MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is()); + return list; + } + + DeclarationListNodeResult newDeclarationList(ParseNodeKind kind, + const TokenPos& pos) { + return newResult(kind, pos); + } + + ListNodeResult newCommaExpressionList(Node kid) { + return newResult(ParseNodeKind::CommaExpr, kid); + } + + void addList(ListNodeType list, Node kid) { list->append(kid); } + + void setListHasNonConstInitializer(ListNodeType literal) { + literal->setHasNonConstInitializer(); + } + + // NOTE: This is infallible. + template + [[nodiscard]] NodeType parenthesize(NodeType node) { + node->setInParens(true); + return node; + } + + // NOTE: This is infallible. + template + [[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().atom() == + TaggedParserAtomIndex::WellKnown::arguments(); + } + + bool isEvalName(Node node) { + return node->isKind(ParseNodeKind::Name) && + node->as().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().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().kid()); + } + return node->is(); + } + + TaggedParserAtomIndex maybeDottedProperty(Node pn) { + return pn->is() ? pn->as().name() + : TaggedParserAtomIndex::null(); + } + TaggedParserAtomIndex isStringExprStatement(Node pn, TokenPos* pos) { + if (pn->is()) { + UnaryNode* unary = &pn->as(); + 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()); + node->as().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 */ -- cgit v1.2.3