From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/frontend/FullParseHandler.h | 1195 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1195 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..d5dc32026b --- /dev/null +++ b/js/src/frontend/FullParseHandler.h @@ -0,0 +1,1195 @@ +/* -*- 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 // 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/ParserAtom.h" // TaggedParserAtomIndex +#include "frontend/SharedContext.h" +#include "frontend/Stencil.h" + +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; + + public: + /* new_ methods for creating parse nodes. These report OOM on context. */ + JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline) + + // FIXME: Use ListNode instead of ListNodeType as an alias (bug 1489008). + using Node = ParseNode*; + +#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \ + using longTypeName = typeName*; + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + + 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(); } + +#define DECLARE_AS(typeName, longTypeName, asMethodName) \ + static longTypeName asMethodName(Node node) { return &node->as(); } + FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) +#undef DECLARE_AS + + NameNodeType newName(TaggedParserAtomIndex name, const TokenPos& pos) { + return new_(ParseNodeKind::Name, name, pos); + } + + UnaryNodeType newComputedName(Node expr, uint32_t begin, uint32_t end) { + TokenPos pos(begin, end); + return new_(ParseNodeKind::ComputedName, pos, expr); + } + + UnaryNodeType newSyntheticComputedName(Node expr, uint32_t begin, + uint32_t end) { + TokenPos pos(begin, end); + UnaryNode* node = new_(ParseNodeKind::ComputedName, pos, expr); + if (!node) { + return nullptr; + } + node->setSyntheticComputedName(); + return node; + } + + NameNodeType newObjectLiteralPropertyName(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return new_(ParseNodeKind::ObjectPropertyName, atom, pos); + } + + NameNodeType newPrivateName(TaggedParserAtomIndex atom, const TokenPos& pos) { + return new_(ParseNodeKind::PrivateName, atom, pos); + } + + NumericLiteralType newNumber(double value, DecimalPoint decimalPoint, + const TokenPos& pos) { + return new_(value, decimalPoint, pos); + } + + BigIntLiteralType newBigInt(BigIntIndex index, bool isZero, + const TokenPos& pos) { + return new_(index, isZero, pos); + } + + BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) { + return new_(cond, pos); + } + + NameNodeType newStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return new_(ParseNodeKind::StringExpr, atom, pos); + } + + NameNodeType newTemplateStringLiteral(TaggedParserAtomIndex atom, + const TokenPos& pos) { + return new_(ParseNodeKind::TemplateStringExpr, atom, pos); + } + + CallSiteNodeType newCallSiteObject(uint32_t begin) { + CallSiteNode* callSiteObj = new_(begin); + if (!callSiteObj) { + return null(); + } + + ListNode* rawNodes = newArrayLiteral(callSiteObj->pn_pos.begin); + if (!rawNodes) { + return null(); + } + + 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()); + } + + ThisLiteralType newThisLiteral(const TokenPos& pos, Node thisName) { + return new_(pos, thisName); + } + + NullLiteralType newNullLiteral(const TokenPos& pos) { + return new_(pos); + } + + RawUndefinedLiteralType newRawUndefinedLiteral(const TokenPos& pos) { + return new_(pos); + } + + RegExpLiteralType newRegExp(RegExpIndex index, const TokenPos& pos) { + return new_(index, pos); + } + + ConditionalExpressionType newConditional(Node cond, Node thenExpr, + Node elseExpr) { + return new_(cond, thenExpr, elseExpr); + } + + UnaryNodeType 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); + } + + UnaryNodeType newTypeof(uint32_t begin, Node kid) { + ParseNodeKind pnk = kid->isKind(ParseNodeKind::Name) + ? ParseNodeKind::TypeOfNameExpr + : ParseNodeKind::TypeOfExpr; + return newUnary(pnk, begin, kid); + } + + UnaryNodeType newUnary(ParseNodeKind kind, uint32_t begin, Node kid) { + TokenPos pos(begin, kid->pn_pos.end); + return new_(kind, pos, kid); + } + + UnaryNodeType newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) { + TokenPos pos(begin, kid->pn_pos.end); + return new_(kind, pos, kid); + } + + UnaryNodeType newSpread(uint32_t begin, Node kid) { + TokenPos pos(begin, kid->pn_pos.end); + return new_(ParseNodeKind::Spread, pos, kid); + } + + private: + BinaryNodeType newBinary(ParseNodeKind kind, Node left, Node right) { + TokenPos pos(left->pn_pos.begin, right->pn_pos.end); + return new_(kind, pos, left, right); + } + + public: + Node appendOrCreateList(ParseNodeKind kind, Node left, Node right, + ParseContext* pc) { + return ParseNode::appendOrCreateList(kind, left, right, this, pc); + } + + // Expressions + + ListNodeType newArrayLiteral(uint32_t begin) { + return new_(ParseNodeKind::ArrayExpr, TokenPos(begin, begin + 1)); + } + + [[nodiscard]] bool addElision(ListNodeType literal, const TokenPos& pos) { + MOZ_ASSERT(literal->isKind(ParseNodeKind::ArrayExpr)); + + NullaryNode* elision = new_(ParseNodeKind::Elision, pos); + if (!elision) { + return 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 = newSpread(begin, inner); + if (!spread) { + return 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); + } + + CallNodeType newCall(Node callee, Node args, JSOp callOp) { + return new_(ParseNodeKind::CallExpr, callOp, callee, args); + } + + OptionalCallNodeType newOptionalCall(Node callee, Node args, JSOp callOp) { + return new_(ParseNodeKind::OptionalCallExpr, callOp, callee, + args); + } + + ListNodeType newArguments(const TokenPos& pos) { + return new_(ParseNodeKind::Arguments, pos); + } + + CallNodeType newSuperCall(Node callee, Node args, bool isSpread) { + return new_(ParseNodeKind::SuperCallExpr, + isSpread ? JSOp::SpreadSuperCall : JSOp::SuperCall, + callee, args); + } + + CallNodeType newTaggedTemplate(Node tag, Node args, JSOp callOp) { + return new_(ParseNodeKind::TaggedTemplateExpr, callOp, tag, args); + } + + ListNodeType newObjectLiteral(uint32_t begin) { + return new_(ParseNodeKind::ObjectExpr, + TokenPos(begin, begin + 1)); + } + +#ifdef ENABLE_RECORD_TUPLE + ListNodeType newRecordLiteral(uint32_t begin) { + return new_(ParseNodeKind::RecordExpr, + TokenPos(begin, begin + 1)); + } + + ListNodeType newTupleLiteral(uint32_t begin) { + return new_(ParseNodeKind::TupleExpr, TokenPos(begin, begin + 1)); + } +#endif + + ClassNodeType newClass(Node name, Node heritage, + LexicalScopeNodeType memberBlock, +#ifdef ENABLE_DECORATORS + ListNodeType decorators, +#endif + const TokenPos& pos) { + return new_(name, heritage, memberBlock, +#ifdef ENABLE_DECORATORS + decorators, +#endif + pos); + } + ListNodeType newClassMemberList(uint32_t begin) { + return new_(ParseNodeKind::ClassMemberList, + TokenPos(begin, begin + 1)); + } + ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) { + return new_(outer, inner, pos); + } + NewTargetNodeType newNewTarget(NullaryNodeType newHolder, + NullaryNodeType targetHolder, + NameNodeType newTargetName) { + return new_(newHolder, targetHolder, newTargetName); + } + NullaryNodeType newPosHolder(const TokenPos& pos) { + return new_(ParseNodeKind::PosHolder, pos); + } + UnaryNodeType newSuperBase(Node thisName, const TokenPos& pos) { + return new_(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 = newUnary(ParseNodeKind::MutateProto, begin, expr); + if (!mutation) { + return false; + } + addList(/* list = */ literal, /* kid = */ mutation); + return true; + } + + BinaryNodeType newPropertyDefinition(Node key, Node val) { + MOZ_ASSERT(isUsableAsObjectPropertyName(key)); + checkAndSetIsDirectRHSAnonFunction(val); + return new_(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 = newPropertyDefinition(key, val); + if (!propdef) { + return 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 = newBinary(ParseNodeKind::Shorthand, name, expr); + if (!propdef) { + return 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 = newSpread(begin, inner); + if (!spread) { + return 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 = + newObjectMethodOrPropertyDefinition(key, funNode, atype); + if (!propdef) { + return false; + } + + addList(/* list = */ literal, /* kid = */ propdef); + return true; + } + + [[nodiscard]] ClassMethod* newDefaultClassConstructor( + Node key, FunctionNodeType funNode) { + MOZ_ASSERT(isUsableAsObjectPropertyName(key)); + + checkAndSetIsDirectRHSAnonFunction(funNode); + + return new_( + ParseNodeKind::DefaultConstructor, key, funNode, AccessorType::None, + /* isStatic = */ false, /* initializeIfPrivate = */ nullptr +#ifdef ENABLE_DECORATORS + , + /* decorators = */ nullptr +#endif + ); + } + + [[nodiscard]] ClassMethod* 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 new_(ParseNodeKind::ClassMethod, key, funNode, atype, + isStatic, initializerIfPrivate.value() +#ifdef ENABLE_DECORATORS + , + decorators +#endif + ); + } + return new_(ParseNodeKind::ClassMethod, key, funNode, atype, + isStatic, /* initializeIfPrivate = */ nullptr +#ifdef ENABLE_DECORATORS + , + decorators +#endif + ); + } + + [[nodiscard]] ClassField* newClassFieldDefinition( + Node name, FunctionNodeType initializer, bool isStatic +#ifdef ENABLE_DECORATORS + , + ListNodeType decorators, bool hasAccessor +#endif + ) { + MOZ_ASSERT(isUsableAsObjectPropertyName(name)); + + return new_(name, initializer, isStatic +#if ENABLE_DECORATORS + , + decorators, hasAccessor +#endif + ); + } + + [[nodiscard]] StaticClassBlock* newStaticClassBlock(FunctionNodeType block) { + return new_(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; + } + + UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) { + TokenPos pos(begin, begin + 1); + return new_(ParseNodeKind::InitialYield, pos, gen); + } + + UnaryNodeType newYieldExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); + return new_(ParseNodeKind::YieldExpr, pos, value); + } + + UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value->pn_pos.end); + return new_(ParseNodeKind::YieldStarExpr, pos, value); + } + + UnaryNodeType newAwaitExpression(uint32_t begin, Node value) { + TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); + return new_(ParseNodeKind::AwaitExpr, pos, value); + } + + UnaryNodeType newOptionalChain(uint32_t begin, Node value) { + TokenPos pos(begin, value->pn_pos.end); + return new_(ParseNodeKind::OptionalChain, pos, value); + } + + // Statements + + ListNodeType newStatementList(const TokenPos& pos) { + return new_(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 = + new_(ParseNodeKind::Generator, yieldPos); + if (!makeGen) { + return false; + } + + ParseNode* genInit = + newAssignment(ParseNodeKind::AssignExpr, /* lhs = */ genName, + /* rhs = */ makeGen); + if (!genInit) { + return false; + } + + UnaryNode* initialYield = + newInitialYieldExpression(yieldPos.begin, genInit); + if (!initialYield) { + return false; + } + + stmtList->prepend(initialYield); + return true; + } + + BinaryNodeType newSetThis(Node thisName, Node value) { + return newBinary(ParseNodeKind::SetThis, thisName, value); + } + + NullaryNodeType newEmptyStatement(const TokenPos& pos) { + return new_(ParseNodeKind::EmptyStmt, pos); + } + + BinaryNodeType newImportAssertion(Node keyNode, Node valueNode) { + return newBinary(ParseNodeKind::ImportAssertion, keyNode, valueNode); + } + + BinaryNodeType newModuleRequest(Node moduleSpec, Node importAssertionList, + const TokenPos& pos) { + return new_(ParseNodeKind::ImportModuleRequest, pos, moduleSpec, + importAssertionList); + } + + BinaryNodeType newImportDeclaration(Node importSpecSet, Node moduleRequest, + const TokenPos& pos) { + return new_(ParseNodeKind::ImportDecl, pos, importSpecSet, + moduleRequest); + } + + BinaryNodeType newImportSpec(Node importNameNode, Node bindingName) { + return newBinary(ParseNodeKind::ImportSpec, importNameNode, bindingName); + } + + UnaryNodeType newImportNamespaceSpec(uint32_t begin, Node bindingName) { + return newUnary(ParseNodeKind::ImportNamespaceSpec, begin, bindingName); + } + + UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) { + return new_(ParseNodeKind::ExportStmt, pos, kid); + } + + BinaryNodeType newExportFromDeclaration(uint32_t begin, Node exportSpecSet, + Node moduleRequest) { + BinaryNode* decl = new_(ParseNodeKind::ExportFromStmt, + exportSpecSet, moduleRequest); + if (!decl) { + return nullptr; + } + decl->pn_pos.begin = begin; + return decl; + } + + BinaryNodeType newExportDefaultDeclaration(Node kid, Node maybeBinding, + const TokenPos& pos) { + if (maybeBinding) { + MOZ_ASSERT(maybeBinding->isKind(ParseNodeKind::Name)); + MOZ_ASSERT(!maybeBinding->isInParens()); + + checkAndSetIsDirectRHSAnonFunction(kid); + } + + return new_(ParseNodeKind::ExportDefaultStmt, pos, kid, + maybeBinding); + } + + BinaryNodeType newExportSpec(Node bindingName, Node exportName) { + return newBinary(ParseNodeKind::ExportSpec, bindingName, exportName); + } + + UnaryNodeType newExportNamespaceSpec(uint32_t begin, Node exportName) { + return newUnary(ParseNodeKind::ExportNamespaceSpec, begin, exportName); + } + + NullaryNodeType newExportBatchSpec(const TokenPos& pos) { + return new_(ParseNodeKind::ExportBatchSpecStmt, pos); + } + + BinaryNodeType newImportMeta(NullaryNodeType importHolder, + NullaryNodeType metaHolder) { + return new_(ParseNodeKind::ImportMetaExpr, importHolder, + metaHolder); + } + + BinaryNodeType newCallImport(NullaryNodeType importHolder, Node singleArg) { + return new_(ParseNodeKind::CallImportExpr, importHolder, + singleArg); + } + + BinaryNodeType newCallImportSpec(Node specifierArg, Node optionalArg) { + return new_(ParseNodeKind::CallImportSpec, specifierArg, + optionalArg); + } + + UnaryNodeType newExprStatement(Node expr, uint32_t end) { + MOZ_ASSERT(expr->pn_pos.end <= end); + return new_(ParseNodeKind::ExpressionStmt, + TokenPos(expr->pn_pos.begin, end), expr); + } + + TernaryNodeType newIfStatement(uint32_t begin, Node cond, Node thenBranch, + Node elseBranch) { + TernaryNode* node = + new_(ParseNodeKind::IfStmt, cond, thenBranch, elseBranch); + if (!node) { + return nullptr; + } + node->pn_pos.begin = begin; + return node; + } + + BinaryNodeType newDoWhileStatement(Node body, Node cond, + const TokenPos& pos) { + return new_(ParseNodeKind::DoWhileStmt, pos, body, cond); + } + + BinaryNodeType newWhileStatement(uint32_t begin, Node cond, Node body) { + TokenPos pos(begin, body->pn_pos.end); + return new_(ParseNodeKind::WhileStmt, pos, cond, body); + } + + ForNodeType newForStatement(uint32_t begin, TernaryNodeType forHead, + Node body, unsigned iflags) { + return new_(TokenPos(begin, body->pn_pos.end), forHead, body, + iflags); + } + + TernaryNodeType newForHead(Node init, Node test, Node update, + const TokenPos& pos) { + return new_(ParseNodeKind::ForHead, init, test, update, pos); + } + + TernaryNodeType newForInOrOfHead(ParseNodeKind kind, Node target, + Node iteratedExpr, const TokenPos& pos) { + MOZ_ASSERT(kind == ParseNodeKind::ForIn || kind == ParseNodeKind::ForOf); + return new_(kind, target, nullptr, iteratedExpr, pos); + } + + SwitchStatementType newSwitchStatement( + uint32_t begin, Node discriminant, + LexicalScopeNodeType lexicalForCaseList, bool hasDefault) { + return new_(begin, discriminant, lexicalForCaseList, + hasDefault); + } + + CaseClauseType newCaseOrDefault(uint32_t begin, Node expr, Node body) { + return new_(expr, body, begin); + } + + ContinueStatementType newContinueStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return new_(label, pos); + } + + BreakStatementType newBreakStatement(TaggedParserAtomIndex label, + const TokenPos& pos) { + return new_(label, pos); + } + + UnaryNodeType newReturnStatement(Node expr, const TokenPos& pos) { + MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); + return new_(ParseNodeKind::ReturnStmt, pos, expr); + } + + UnaryNodeType newExpressionBody(Node expr) { + return new_(ParseNodeKind::ReturnStmt, expr->pn_pos, expr); + } + + BinaryNodeType newWithStatement(uint32_t begin, Node expr, Node body) { + return new_(ParseNodeKind::WithStmt, + TokenPos(begin, body->pn_pos.end), expr, body); + } + + LabeledStatementType newLabeledStatement(TaggedParserAtomIndex label, + Node stmt, uint32_t begin) { + return new_(label, stmt, begin); + } + + UnaryNodeType newThrowStatement(Node expr, const TokenPos& pos) { + MOZ_ASSERT(pos.encloses(expr->pn_pos)); + return new_(ParseNodeKind::ThrowStmt, pos, expr); + } + + TernaryNodeType newTryStatement(uint32_t begin, Node body, + LexicalScopeNodeType catchScope, + Node finallyBlock) { + return new_(begin, body, catchScope, finallyBlock); + } + + DebuggerStatementType newDebuggerStatement(const TokenPos& pos) { + return new_(pos); + } + + NameNodeType newPropertyName(TaggedParserAtomIndex name, + const TokenPos& pos) { + return new_(ParseNodeKind::PropertyNameExpr, name, pos); + } + + PropertyAccessType newPropertyAccess(Node expr, NameNodeType key) { + return new_(expr, key, expr->pn_pos.begin, key->pn_pos.end); + } + + PropertyByValueType newPropertyByValue(Node lhs, Node index, uint32_t end) { + return new_(lhs, index, lhs->pn_pos.begin, end); + } + + OptionalPropertyAccessType newOptionalPropertyAccess(Node expr, + NameNodeType key) { + return new_(expr, key, expr->pn_pos.begin, + key->pn_pos.end); + } + + OptionalPropertyByValueType newOptionalPropertyByValue(Node lhs, Node index, + uint32_t end) { + return new_(lhs, index, lhs->pn_pos.begin, end); + } + + PrivateMemberAccessType newPrivateMemberAccess(Node lhs, + NameNodeType privateName, + uint32_t end) { + return new_(lhs, privateName, lhs->pn_pos.begin, end); + } + + OptionalPrivateMemberAccessType newOptionalPrivateMemberAccess( + Node lhs, NameNodeType privateName, uint32_t end) { + return new_(lhs, privateName, + lhs->pn_pos.begin, end); + } + + bool setupCatchScope(LexicalScopeNodeType lexicalScope, Node catchName, + Node catchBody) { + BinaryNode* catchClause; + if (catchName) { + catchClause = + new_(ParseNodeKind::Catch, catchName, catchBody); + } else { + catchClause = new_(ParseNodeKind::Catch, catchBody->pn_pos, + catchName, catchBody); + } + if (!catchClause) { + return false; + } + lexicalScope->setScopeBody(catchClause); + return true; + } + + [[nodiscard]] inline bool setLastFunctionFormalParameterDefault( + FunctionNodeType funNode, Node defaultValue); + + void checkAndSetIsDirectRHSAnonFunction(Node pn) { + if (IsAnonymousFunctionDefinition(pn)) { + pn->setDirectRHSAnonFunction(true); + } + } + + ParamsBodyNodeType newParamsBody(const TokenPos& pos) { + return new_(pos); + } + + FunctionNodeType newFunction(FunctionSyntaxKind syntaxKind, + const TokenPos& pos) { + return new_(syntaxKind, pos); + } + + BinaryNodeType newObjectMethodOrPropertyDefinition(Node key, Node value, + AccessorType atype) { + MOZ_ASSERT(isUsableAsObjectPropertyName(key)); + + return new_(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); + } + + ModuleNodeType newModule(const TokenPos& pos) { + return new_(pos); + } + + LexicalScopeNodeType newLexicalScope(LexicalScope::ParserData* bindings, + Node body, + ScopeKind kind = ScopeKind::Lexical) { + return new_(bindings, body, kind); + } + + ClassBodyScopeNodeType newClassBodyScope(ClassBodyScope::ParserData* bindings, + ListNodeType body) { + return new_(bindings, body); + } + + CallNodeType newNewExpression(uint32_t begin, Node ctor, Node args, + bool isSpread) { + return new_(ParseNodeKind::NewExpr, + isSpread ? JSOp::SpreadNew : JSOp::New, + TokenPos(begin, args->pn_pos.end), ctor, args); + } + + AssignmentNodeType 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 new_(kind, lhs, rhs); + } + + BinaryNodeType newInitExpr(Node lhs, Node rhs) { + TokenPos pos(lhs->pn_pos.begin, rhs->pn_pos.end); + return new_(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); + } + + AssignmentNodeType 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; + } + + ListNodeType newList(ParseNodeKind kind, const TokenPos& pos) { + auto* list = new_(kind, pos); + MOZ_ASSERT_IF(list, !list->is()); + MOZ_ASSERT_IF(list, !list->is()); + return list; + } + + ListNodeType newList(ParseNodeKind kind, Node kid) { + auto* list = new_(kind, kid); + MOZ_ASSERT_IF(list, !list->is()); + MOZ_ASSERT_IF(list, !list->is()); + return list; + } + + DeclarationListNodeType newDeclarationList(ParseNodeKind kind, + const TokenPos& pos) { + return new_(kind, pos); + } + + ListNodeType newCommaExpressionList(Node kid) { + return new_(ParseNodeKind::CommaExpr, kid); + } + + void addList(ListNodeType list, Node kid) { list->append(kid); } + + void setListHasNonConstInitializer(ListNodeType literal) { + literal->setHasNonConstInitializer(); + } + template + [[nodiscard]] NodeType parenthesize(NodeType node) { + node->setInParens(true); + return node; + } + 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 = newAssignment(ParseNodeKind::AssignExpr, arg, defaultValue); + if (!pn) { + return false; + } + + body->replaceLast(pn); + return true; +} + +} // namespace frontend +} // namespace js + +#endif /* frontend_FullParseHandler_h */ -- cgit v1.2.3