Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / FullParseHandler.h
blobc15d66bd8bfa3f0d1e074f5fa6f1fce71e89789d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef frontend_FullParseHandler_h
8 #define frontend_FullParseHandler_h
10 #include "mozilla/Maybe.h" // mozilla::Maybe
11 #include "mozilla/Result.h" // mozilla::Result, mozilla::UnusedZero
12 #include "mozilla/Try.h" // MOZ_TRY*
14 #include <cstddef> // std::nullptr_t
15 #include <string.h>
17 #include "jstypes.h"
19 #include "frontend/CompilationStencil.h" // CompilationState
20 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
21 #include "frontend/NameAnalysisTypes.h" // PrivateNameKind
22 #include "frontend/ParseNode.h"
23 #include "frontend/Parser-macros.h" // MOZ_TRY_VAR_OR_RETURN
24 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
25 #include "frontend/SharedContext.h"
26 #include "frontend/Stencil.h"
28 template <>
29 struct mozilla::detail::UnusedZero<js::frontend::ParseNode*> {
30 static const bool value = true;
33 #define DEFINE_UNUSED_ZERO(typeName) \
34 template <> \
35 struct mozilla::detail::UnusedZero<js::frontend::typeName*> { \
36 static const bool value = true; \
38 FOR_EACH_PARSENODE_SUBCLASS(DEFINE_UNUSED_ZERO)
39 #undef DEFINE_UNUSED_ZERO
41 namespace js {
42 namespace frontend {
44 class TokenStreamAnyChars;
46 // Parse handler used when generating a full parse tree for all code which the
47 // parser encounters.
48 class FullParseHandler {
49 ParseNodeAllocator allocator;
51 ParseNode* allocParseNode(size_t size) {
52 return static_cast<ParseNode*>(allocator.allocNode(size));
55 // If this is a full parse to construct the bytecode for a function that
56 // was previously lazily parsed, we still don't want to full parse the
57 // inner functions. These members are used for this functionality:
59 // - reuseGCThings if ture it means that the following fields are valid.
60 // - gcThingsData holds an incomplete stencil-like copy of inner functions as
61 // well as atoms.
62 // - scriptData and scriptExtra_ hold information necessary to locate inner
63 // functions to skip over each.
64 // - lazyInnerFunctionIndex is used as we skip over inner functions
65 // (see skipLazyInnerFunction),
66 // - lazyClosedOverBindingIndex is used to synchronize binding computation
67 // with the scope traversal.
68 // (see propagateFreeNamesAndMarkClosedOverBindings),
69 const CompilationSyntaxParseCache& previousParseCache_;
71 size_t lazyInnerFunctionIndex;
72 size_t lazyClosedOverBindingIndex;
74 bool reuseGCThings;
76 /* new_ methods for creating parse nodes. These report OOM on context. */
77 JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
79 public:
80 using NodeError = ParseNodeError;
82 using Node = ParseNode*;
83 using NodeResult = ParseNodeResult;
84 using NodeErrorResult = mozilla::GenericErrorResult<NodeError>;
86 #define DECLARE_TYPE(typeName) \
87 using typeName##Type = typeName*; \
88 using typeName##Result = mozilla::Result<typeName*, NodeError>;
89 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
90 #undef DECLARE_TYPE
92 template <class T, typename... Args>
93 inline mozilla::Result<T*, NodeError> newResult(Args&&... args) {
94 auto* node = new_<T>(std::forward<Args>(args)...);
95 if (!node) {
96 return mozilla::Result<T*, NodeError>(NodeError());
98 return node;
101 using NullNode = std::nullptr_t;
103 bool isPropertyOrPrivateMemberAccess(Node node) {
104 return node->isKind(ParseNodeKind::DotExpr) ||
105 node->isKind(ParseNodeKind::ElemExpr) ||
106 node->isKind(ParseNodeKind::PrivateMemberExpr);
109 bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
110 return node->isKind(ParseNodeKind::OptionalDotExpr) ||
111 node->isKind(ParseNodeKind::OptionalElemExpr) ||
112 node->isKind(ParseNodeKind::PrivateMemberExpr);
115 bool isFunctionCall(Node node) {
116 // Note: super() is a special form, *not* a function call.
117 return node->isKind(ParseNodeKind::CallExpr);
120 static bool isUnparenthesizedDestructuringPattern(Node node) {
121 return !node->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
122 node->isKind(ParseNodeKind::ArrayExpr));
125 static bool isParenthesizedDestructuringPattern(Node node) {
126 // Technically this isn't a destructuring pattern at all -- the grammar
127 // doesn't treat it as such. But we need to know when this happens to
128 // consider it a SyntaxError rather than an invalid-left-hand-side
129 // ReferenceError.
130 return node->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
131 node->isKind(ParseNodeKind::ArrayExpr));
134 FullParseHandler(FrontendContext* fc, CompilationState& compilationState)
135 : allocator(fc, compilationState.parserAllocScope.alloc()),
136 previousParseCache_(compilationState.previousParseCache),
137 lazyInnerFunctionIndex(0),
138 lazyClosedOverBindingIndex(0),
139 reuseGCThings(compilationState.input.isDelazifying()) {}
141 static NullNode null() { return NullNode(); }
142 static constexpr NodeErrorResult errorResult() {
143 return NodeErrorResult(NodeError());
146 #define DECLARE_AS(typeName) \
147 static typeName##Type as##typeName(Node node) { \
148 return &node->as<typeName>(); \
150 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
151 #undef DECLARE_AS
153 NameNodeResult newName(TaggedParserAtomIndex name, const TokenPos& pos) {
154 return newResult<NameNode>(ParseNodeKind::Name, name, pos);
157 UnaryNodeResult newComputedName(Node expr, uint32_t begin, uint32_t end) {
158 TokenPos pos(begin, end);
159 return newResult<UnaryNode>(ParseNodeKind::ComputedName, pos, expr);
162 UnaryNodeResult newSyntheticComputedName(Node expr, uint32_t begin,
163 uint32_t end) {
164 TokenPos pos(begin, end);
165 UnaryNode* node;
166 MOZ_TRY_VAR(node,
167 newResult<UnaryNode>(ParseNodeKind::ComputedName, pos, expr));
168 node->setSyntheticComputedName();
169 return node;
172 NameNodeResult newObjectLiteralPropertyName(TaggedParserAtomIndex atom,
173 const TokenPos& pos) {
174 return newResult<NameNode>(ParseNodeKind::ObjectPropertyName, atom, pos);
177 NameNodeResult newPrivateName(TaggedParserAtomIndex atom,
178 const TokenPos& pos) {
179 return newResult<NameNode>(ParseNodeKind::PrivateName, atom, pos);
182 NumericLiteralResult newNumber(double value, DecimalPoint decimalPoint,
183 const TokenPos& pos) {
184 return newResult<NumericLiteral>(value, decimalPoint, pos);
187 BigIntLiteralResult newBigInt(BigIntIndex index, bool isZero,
188 const TokenPos& pos) {
189 return newResult<BigIntLiteral>(index, isZero, pos);
192 BooleanLiteralResult newBooleanLiteral(bool cond, const TokenPos& pos) {
193 return newResult<BooleanLiteral>(cond, pos);
196 NameNodeResult newStringLiteral(TaggedParserAtomIndex atom,
197 const TokenPos& pos) {
198 return newResult<NameNode>(ParseNodeKind::StringExpr, atom, pos);
201 NameNodeResult newTemplateStringLiteral(TaggedParserAtomIndex atom,
202 const TokenPos& pos) {
203 return newResult<NameNode>(ParseNodeKind::TemplateStringExpr, atom, pos);
206 CallSiteNodeResult newCallSiteObject(uint32_t begin) {
207 CallSiteNode* callSiteObj;
208 MOZ_TRY_VAR(callSiteObj, newResult<CallSiteNode>(begin));
210 ListNode* rawNodes;
211 MOZ_TRY_VAR(rawNodes, newArrayLiteral(callSiteObj->pn_pos.begin));
213 addArrayElement(callSiteObj, rawNodes);
215 return callSiteObj;
218 void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode,
219 Node cookedNode) {
220 MOZ_ASSERT(callSiteObj->isKind(ParseNodeKind::CallSiteObj));
221 MOZ_ASSERT(rawNode->isKind(ParseNodeKind::TemplateStringExpr));
222 MOZ_ASSERT(cookedNode->isKind(ParseNodeKind::TemplateStringExpr) ||
223 cookedNode->isKind(ParseNodeKind::RawUndefinedExpr));
225 addArrayElement(callSiteObj, cookedNode);
226 addArrayElement(callSiteObj->rawNodes(), rawNode);
229 * We don't know when the last noSubstTemplate will come in, and we
230 * don't want to deal with this outside this method
232 setEndPosition(callSiteObj, callSiteObj->rawNodes());
235 ThisLiteralResult newThisLiteral(const TokenPos& pos, Node thisName) {
236 return newResult<ThisLiteral>(pos, thisName);
239 NullLiteralResult newNullLiteral(const TokenPos& pos) {
240 return newResult<NullLiteral>(pos);
243 RawUndefinedLiteralResult newRawUndefinedLiteral(const TokenPos& pos) {
244 return newResult<RawUndefinedLiteral>(pos);
247 RegExpLiteralResult newRegExp(RegExpIndex index, const TokenPos& pos) {
248 return newResult<RegExpLiteral>(index, pos);
251 ConditionalExpressionResult newConditional(Node cond, Node thenExpr,
252 Node elseExpr) {
253 return newResult<ConditionalExpression>(cond, thenExpr, elseExpr);
256 UnaryNodeResult newDelete(uint32_t begin, Node expr) {
257 if (expr->isKind(ParseNodeKind::Name)) {
258 return newUnary(ParseNodeKind::DeleteNameExpr, begin, expr);
261 if (expr->isKind(ParseNodeKind::DotExpr)) {
262 return newUnary(ParseNodeKind::DeletePropExpr, begin, expr);
265 if (expr->isKind(ParseNodeKind::ElemExpr)) {
266 return newUnary(ParseNodeKind::DeleteElemExpr, begin, expr);
269 if (expr->isKind(ParseNodeKind::OptionalChain)) {
270 Node kid = expr->as<UnaryNode>().kid();
271 // Handle property deletion explicitly. OptionalCall is handled
272 // via DeleteExpr.
273 if (kid->isKind(ParseNodeKind::DotExpr) ||
274 kid->isKind(ParseNodeKind::OptionalDotExpr) ||
275 kid->isKind(ParseNodeKind::ElemExpr) ||
276 kid->isKind(ParseNodeKind::OptionalElemExpr)) {
277 return newUnary(ParseNodeKind::DeleteOptionalChainExpr, begin, kid);
281 return newUnary(ParseNodeKind::DeleteExpr, begin, expr);
284 UnaryNodeResult newTypeof(uint32_t begin, Node kid) {
285 ParseNodeKind pnk = kid->isKind(ParseNodeKind::Name)
286 ? ParseNodeKind::TypeOfNameExpr
287 : ParseNodeKind::TypeOfExpr;
288 return newUnary(pnk, begin, kid);
291 UnaryNodeResult newUnary(ParseNodeKind kind, uint32_t begin, Node kid) {
292 TokenPos pos(begin, kid->pn_pos.end);
293 return newResult<UnaryNode>(kind, pos, kid);
296 UnaryNodeResult newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) {
297 TokenPos pos(begin, kid->pn_pos.end);
298 return newResult<UnaryNode>(kind, pos, kid);
301 UnaryNodeResult newSpread(uint32_t begin, Node kid) {
302 TokenPos pos(begin, kid->pn_pos.end);
303 return newResult<UnaryNode>(ParseNodeKind::Spread, pos, kid);
306 private:
307 BinaryNodeResult newBinary(ParseNodeKind kind, Node left, Node right) {
308 TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
309 return newResult<BinaryNode>(kind, pos, left, right);
312 public:
313 NodeResult appendOrCreateList(ParseNodeKind kind, Node left, Node right,
314 ParseContext* pc) {
315 return ParseNode::appendOrCreateList(kind, left, right, this, pc);
318 // Expressions
320 ListNodeResult newArrayLiteral(uint32_t begin) {
321 return newResult<ListNode>(ParseNodeKind::ArrayExpr,
322 TokenPos(begin, begin + 1));
325 [[nodiscard]] bool addElision(ListNodeType literal, const TokenPos& pos) {
326 MOZ_ASSERT(literal->isKind(ParseNodeKind::ArrayExpr));
328 NullaryNode* elision;
329 MOZ_TRY_VAR_OR_RETURN(
330 elision, newResult<NullaryNode>(ParseNodeKind::Elision, pos), false);
331 addList(/* list = */ literal, /* kid = */ elision);
332 literal->setHasNonConstInitializer();
333 return true;
336 [[nodiscard]] bool addSpreadElement(ListNodeType literal, uint32_t begin,
337 Node inner) {
338 MOZ_ASSERT(
339 literal->isKind(ParseNodeKind::ArrayExpr) ||
340 IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::TupleExpr), false));
342 UnaryNodeType spread;
343 MOZ_TRY_VAR_OR_RETURN(spread, newSpread(begin, inner), false);
344 addList(/* list = */ literal, /* kid = */ spread);
345 literal->setHasNonConstInitializer();
346 return true;
349 void addArrayElement(ListNodeType literal, Node element) {
350 MOZ_ASSERT(
351 literal->isKind(ParseNodeKind::ArrayExpr) ||
352 literal->isKind(ParseNodeKind::CallSiteObj) ||
353 IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::TupleExpr), false));
354 if (!element->isConstant()) {
355 literal->setHasNonConstInitializer();
357 addList(/* list = */ literal, /* kid = */ element);
360 CallNodeResult newCall(Node callee, ListNodeType args, JSOp callOp) {
361 return newResult<CallNode>(ParseNodeKind::CallExpr, callOp, callee, args);
364 CallNodeResult newOptionalCall(Node callee, ListNodeType args, JSOp callOp) {
365 return newResult<CallNode>(ParseNodeKind::OptionalCallExpr, callOp, callee,
366 args);
369 ListNodeResult newArguments(const TokenPos& pos) {
370 return newResult<ListNode>(ParseNodeKind::Arguments, pos);
373 CallNodeResult newSuperCall(Node callee, ListNodeType args, bool isSpread) {
374 return newResult<CallNode>(
375 ParseNodeKind::SuperCallExpr,
376 isSpread ? JSOp::SpreadSuperCall : JSOp::SuperCall, callee, args);
379 CallNodeResult newTaggedTemplate(Node tag, ListNodeType args, JSOp callOp) {
380 return newResult<CallNode>(ParseNodeKind::TaggedTemplateExpr, callOp, tag,
381 args);
384 ListNodeResult newObjectLiteral(uint32_t begin) {
385 return newResult<ListNode>(ParseNodeKind::ObjectExpr,
386 TokenPos(begin, begin + 1));
389 #ifdef ENABLE_RECORD_TUPLE
390 ListNodeResult newRecordLiteral(uint32_t begin) {
391 return newResult<ListNode>(ParseNodeKind::RecordExpr,
392 TokenPos(begin, begin + 1));
395 ListNodeResult newTupleLiteral(uint32_t begin) {
396 return newResult<ListNode>(ParseNodeKind::TupleExpr,
397 TokenPos(begin, begin + 1));
399 #endif
401 ClassNodeResult newClass(Node name, Node heritage,
402 LexicalScopeNodeType memberBlock,
403 #ifdef ENABLE_DECORATORS
404 ListNodeType decorators,
405 #endif
406 const TokenPos& pos) {
407 return newResult<ClassNode>(name, heritage, memberBlock,
408 #ifdef ENABLE_DECORATORS
409 decorators,
410 #endif
411 pos);
413 ListNodeResult newClassMemberList(uint32_t begin) {
414 return newResult<ListNode>(ParseNodeKind::ClassMemberList,
415 TokenPos(begin, begin + 1));
417 ClassNamesResult newClassNames(Node outer, Node inner, const TokenPos& pos) {
418 return newResult<ClassNames>(outer, inner, pos);
420 NewTargetNodeResult newNewTarget(NullaryNodeType newHolder,
421 NullaryNodeType targetHolder,
422 NameNodeType newTargetName) {
423 return newResult<NewTargetNode>(newHolder, targetHolder, newTargetName);
425 NullaryNodeResult newPosHolder(const TokenPos& pos) {
426 return newResult<NullaryNode>(ParseNodeKind::PosHolder, pos);
428 UnaryNodeResult newSuperBase(Node thisName, const TokenPos& pos) {
429 return newResult<UnaryNode>(ParseNodeKind::SuperBase, pos, thisName);
431 [[nodiscard]] bool addPrototypeMutation(ListNodeType literal, uint32_t begin,
432 Node expr) {
433 MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
435 // Object literals with mutated [[Prototype]] are non-constant so that
436 // singleton objects will have Object.prototype as their [[Prototype]].
437 literal->setHasNonConstInitializer();
439 UnaryNode* mutation;
440 MOZ_TRY_VAR_OR_RETURN(
441 mutation, newUnary(ParseNodeKind::MutateProto, begin, expr), false);
442 addList(/* list = */ literal, /* kid = */ mutation);
443 return true;
446 BinaryNodeResult newPropertyDefinition(Node key, Node val) {
447 MOZ_ASSERT(isUsableAsObjectPropertyName(key));
448 checkAndSetIsDirectRHSAnonFunction(val);
449 return newResult<PropertyDefinition>(key, val, AccessorType::None);
452 void addPropertyDefinition(ListNodeType literal, BinaryNodeType propdef) {
453 MOZ_ASSERT(
454 literal->isKind(ParseNodeKind::ObjectExpr) ||
455 IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
456 MOZ_ASSERT(propdef->isKind(ParseNodeKind::PropertyDefinition));
458 if (!propdef->right()->isConstant()) {
459 literal->setHasNonConstInitializer();
462 addList(/* list = */ literal, /* kid = */ propdef);
465 [[nodiscard]] bool addPropertyDefinition(ListNodeType literal, Node key,
466 Node val) {
467 BinaryNode* propdef;
468 MOZ_TRY_VAR_OR_RETURN(propdef, newPropertyDefinition(key, val), false);
469 addPropertyDefinition(literal, propdef);
470 return true;
473 [[nodiscard]] bool addShorthand(ListNodeType literal, NameNodeType name,
474 NameNodeType expr) {
475 MOZ_ASSERT(
476 literal->isKind(ParseNodeKind::ObjectExpr) ||
477 IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
478 MOZ_ASSERT(name->isKind(ParseNodeKind::ObjectPropertyName));
479 MOZ_ASSERT(expr->isKind(ParseNodeKind::Name));
480 MOZ_ASSERT(name->atom() == expr->atom());
482 literal->setHasNonConstInitializer();
483 BinaryNode* propdef;
484 MOZ_TRY_VAR_OR_RETURN(
485 propdef, newBinary(ParseNodeKind::Shorthand, name, expr), false);
486 addList(/* list = */ literal, /* kid = */ propdef);
487 return true;
490 [[nodiscard]] bool addSpreadProperty(ListNodeType literal, uint32_t begin,
491 Node inner) {
492 MOZ_ASSERT(
493 literal->isKind(ParseNodeKind::ObjectExpr) ||
494 IF_RECORD_TUPLE(literal->isKind(ParseNodeKind::RecordExpr), false));
496 literal->setHasNonConstInitializer();
497 ParseNode* spread;
498 MOZ_TRY_VAR_OR_RETURN(spread, newSpread(begin, inner), false);
499 addList(/* list = */ literal, /* kid = */ spread);
500 return true;
503 [[nodiscard]] bool addObjectMethodDefinition(ListNodeType literal, Node key,
504 FunctionNodeType funNode,
505 AccessorType atype) {
506 literal->setHasNonConstInitializer();
508 checkAndSetIsDirectRHSAnonFunction(funNode);
510 ParseNode* propdef;
511 MOZ_TRY_VAR_OR_RETURN(
512 propdef, newObjectMethodOrPropertyDefinition(key, funNode, atype),
513 false);
514 addList(/* list = */ literal, /* kid = */ propdef);
515 return true;
518 [[nodiscard]] ClassMethodResult newDefaultClassConstructor(
519 Node key, FunctionNodeType funNode) {
520 MOZ_ASSERT(isUsableAsObjectPropertyName(key));
522 checkAndSetIsDirectRHSAnonFunction(funNode);
524 return newResult<ClassMethod>(
525 ParseNodeKind::DefaultConstructor, key, funNode, AccessorType::None,
526 /* isStatic = */ false, /* initializeIfPrivate = */ nullptr
527 #ifdef ENABLE_DECORATORS
529 /* decorators = */ nullptr
530 #endif
534 [[nodiscard]] ClassMethodResult newClassMethodDefinition(
535 Node key, FunctionNodeType funNode, AccessorType atype, bool isStatic,
536 mozilla::Maybe<FunctionNodeType> initializerIfPrivate
537 #ifdef ENABLE_DECORATORS
539 ListNodeType decorators
540 #endif
542 MOZ_ASSERT(isUsableAsObjectPropertyName(key));
544 checkAndSetIsDirectRHSAnonFunction(funNode);
546 if (initializerIfPrivate.isSome()) {
547 return newResult<ClassMethod>(ParseNodeKind::ClassMethod, key, funNode,
548 atype, isStatic,
549 initializerIfPrivate.value()
550 #ifdef ENABLE_DECORATORS
552 decorators
553 #endif
556 return newResult<ClassMethod>(ParseNodeKind::ClassMethod, key, funNode,
557 atype, isStatic,
558 /* initializeIfPrivate = */ nullptr
559 #ifdef ENABLE_DECORATORS
561 decorators
562 #endif
566 [[nodiscard]] ClassFieldResult newClassFieldDefinition(
567 Node name, FunctionNodeType initializer, bool isStatic
568 #ifdef ENABLE_DECORATORS
570 ListNodeType decorators, ClassMethodType accessorGetterNode,
571 ClassMethodType accessorSetterNode
572 #endif
574 MOZ_ASSERT(isUsableAsObjectPropertyName(name));
576 return newResult<ClassField>(name, initializer, isStatic
577 #if ENABLE_DECORATORS
579 decorators, accessorGetterNode,
580 accessorSetterNode
581 #endif
585 [[nodiscard]] StaticClassBlockResult newStaticClassBlock(
586 FunctionNodeType block) {
587 return newResult<StaticClassBlock>(block);
590 [[nodiscard]] bool addClassMemberDefinition(ListNodeType memberList,
591 Node member) {
592 MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
593 // Constructors can be surrounded by LexicalScopes.
594 MOZ_ASSERT(member->isKind(ParseNodeKind::DefaultConstructor) ||
595 member->isKind(ParseNodeKind::ClassMethod) ||
596 member->isKind(ParseNodeKind::ClassField) ||
597 member->isKind(ParseNodeKind::StaticClassBlock) ||
598 (member->isKind(ParseNodeKind::LexicalScope) &&
599 member->as<LexicalScopeNode>().scopeBody()->is<ClassMethod>()));
601 addList(/* list = */ memberList, /* kid = */ member);
602 return true;
605 UnaryNodeResult newInitialYieldExpression(uint32_t begin, Node gen) {
606 TokenPos pos(begin, begin + 1);
607 return newResult<UnaryNode>(ParseNodeKind::InitialYield, pos, gen);
610 UnaryNodeResult newYieldExpression(uint32_t begin, Node value) {
611 TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
612 return newResult<UnaryNode>(ParseNodeKind::YieldExpr, pos, value);
615 UnaryNodeResult newYieldStarExpression(uint32_t begin, Node value) {
616 TokenPos pos(begin, value->pn_pos.end);
617 return newResult<UnaryNode>(ParseNodeKind::YieldStarExpr, pos, value);
620 UnaryNodeResult newAwaitExpression(uint32_t begin, Node value) {
621 TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
622 return newResult<UnaryNode>(ParseNodeKind::AwaitExpr, pos, value);
625 UnaryNodeResult newOptionalChain(uint32_t begin, Node value) {
626 TokenPos pos(begin, value->pn_pos.end);
627 return newResult<UnaryNode>(ParseNodeKind::OptionalChain, pos, value);
630 // Statements
632 ListNodeResult newStatementList(const TokenPos& pos) {
633 return newResult<ListNode>(ParseNodeKind::StatementList, pos);
636 [[nodiscard]] bool isFunctionStmt(Node stmt) {
637 while (stmt->isKind(ParseNodeKind::LabelStmt)) {
638 stmt = stmt->as<LabeledStatement>().statement();
640 return stmt->is<FunctionNode>();
643 void addStatementToList(ListNodeType list, Node stmt) {
644 MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
646 addList(/* list = */ list, /* kid = */ stmt);
648 if (isFunctionStmt(stmt)) {
649 // Notify the emitter that the block contains body-level function
650 // definitions that should be processed before the rest of nodes.
651 list->setHasTopLevelFunctionDeclarations();
655 void setListEndPosition(ListNodeType list, const TokenPos& pos) {
656 MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
657 list->pn_pos.end = pos.end;
660 void addCaseStatementToList(ListNodeType list, CaseClauseType caseClause) {
661 MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
663 addList(/* list = */ list, /* kid = */ caseClause);
665 if (caseClause->statementList()->hasTopLevelFunctionDeclarations()) {
666 list->setHasTopLevelFunctionDeclarations();
670 [[nodiscard]] bool prependInitialYield(ListNodeType stmtList, Node genName) {
671 MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
673 TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
674 NullaryNode* makeGen;
675 MOZ_TRY_VAR_OR_RETURN(
676 makeGen, newResult<NullaryNode>(ParseNodeKind::Generator, yieldPos),
677 false);
679 ParseNode* genInit;
680 MOZ_TRY_VAR_OR_RETURN(
681 genInit,
682 newAssignment(ParseNodeKind::AssignExpr, /* lhs = */ genName,
683 /* rhs = */ makeGen),
684 false);
686 UnaryNode* initialYield;
687 MOZ_TRY_VAR_OR_RETURN(initialYield,
688 newInitialYieldExpression(yieldPos.begin, genInit),
689 false);
691 stmtList->prepend(initialYield);
692 return true;
695 BinaryNodeResult newSetThis(Node thisName, Node value) {
696 return newBinary(ParseNodeKind::SetThis, thisName, value);
699 NullaryNodeResult newEmptyStatement(const TokenPos& pos) {
700 return newResult<NullaryNode>(ParseNodeKind::EmptyStmt, pos);
703 BinaryNodeResult newImportAssertion(Node keyNode, Node valueNode) {
704 return newBinary(ParseNodeKind::ImportAssertion, keyNode, valueNode);
707 BinaryNodeResult newModuleRequest(Node moduleSpec, Node importAssertionList,
708 const TokenPos& pos) {
709 return newResult<BinaryNode>(ParseNodeKind::ImportModuleRequest, pos,
710 moduleSpec, importAssertionList);
713 BinaryNodeResult newImportDeclaration(Node importSpecSet, Node moduleRequest,
714 const TokenPos& pos) {
715 return newResult<BinaryNode>(ParseNodeKind::ImportDecl, pos, importSpecSet,
716 moduleRequest);
719 BinaryNodeResult newImportSpec(Node importNameNode, Node bindingName) {
720 return newBinary(ParseNodeKind::ImportSpec, importNameNode, bindingName);
723 UnaryNodeResult newImportNamespaceSpec(uint32_t begin, Node bindingName) {
724 return newUnary(ParseNodeKind::ImportNamespaceSpec, begin, bindingName);
727 UnaryNodeResult newExportDeclaration(Node kid, const TokenPos& pos) {
728 return newResult<UnaryNode>(ParseNodeKind::ExportStmt, pos, kid);
731 BinaryNodeResult newExportFromDeclaration(uint32_t begin, Node exportSpecSet,
732 Node moduleRequest) {
733 BinaryNode* decl;
734 MOZ_TRY_VAR(decl, newResult<BinaryNode>(ParseNodeKind::ExportFromStmt,
735 exportSpecSet, moduleRequest));
736 decl->pn_pos.begin = begin;
737 return decl;
740 BinaryNodeResult newExportDefaultDeclaration(Node kid, Node maybeBinding,
741 const TokenPos& pos) {
742 if (maybeBinding) {
743 MOZ_ASSERT(maybeBinding->isKind(ParseNodeKind::Name));
744 MOZ_ASSERT(!maybeBinding->isInParens());
746 checkAndSetIsDirectRHSAnonFunction(kid);
749 return newResult<BinaryNode>(ParseNodeKind::ExportDefaultStmt, pos, kid,
750 maybeBinding);
753 BinaryNodeResult newExportSpec(Node bindingName, Node exportName) {
754 return newBinary(ParseNodeKind::ExportSpec, bindingName, exportName);
757 UnaryNodeResult newExportNamespaceSpec(uint32_t begin, Node exportName) {
758 return newUnary(ParseNodeKind::ExportNamespaceSpec, begin, exportName);
761 NullaryNodeResult newExportBatchSpec(const TokenPos& pos) {
762 return newResult<NullaryNode>(ParseNodeKind::ExportBatchSpecStmt, pos);
765 BinaryNodeResult newImportMeta(NullaryNodeType importHolder,
766 NullaryNodeType metaHolder) {
767 return newResult<BinaryNode>(ParseNodeKind::ImportMetaExpr, importHolder,
768 metaHolder);
771 BinaryNodeResult newCallImport(NullaryNodeType importHolder, Node singleArg) {
772 return newResult<BinaryNode>(ParseNodeKind::CallImportExpr, importHolder,
773 singleArg);
776 BinaryNodeResult newCallImportSpec(Node specifierArg, Node optionalArg) {
777 return newResult<BinaryNode>(ParseNodeKind::CallImportSpec, specifierArg,
778 optionalArg);
781 UnaryNodeResult newExprStatement(Node expr, uint32_t end) {
782 MOZ_ASSERT(expr->pn_pos.end <= end);
783 return newResult<UnaryNode>(ParseNodeKind::ExpressionStmt,
784 TokenPos(expr->pn_pos.begin, end), expr);
787 TernaryNodeResult newIfStatement(uint32_t begin, Node cond, Node thenBranch,
788 Node elseBranch) {
789 TernaryNode* node;
790 MOZ_TRY_VAR(node, newResult<TernaryNode>(ParseNodeKind::IfStmt, cond,
791 thenBranch, elseBranch));
792 node->pn_pos.begin = begin;
793 return node;
796 BinaryNodeResult newDoWhileStatement(Node body, Node cond,
797 const TokenPos& pos) {
798 return newResult<BinaryNode>(ParseNodeKind::DoWhileStmt, pos, body, cond);
801 BinaryNodeResult newWhileStatement(uint32_t begin, Node cond, Node body) {
802 TokenPos pos(begin, body->pn_pos.end);
803 return newResult<BinaryNode>(ParseNodeKind::WhileStmt, pos, cond, body);
806 ForNodeResult newForStatement(uint32_t begin, TernaryNodeType forHead,
807 Node body, unsigned iflags) {
808 return newResult<ForNode>(TokenPos(begin, body->pn_pos.end), forHead, body,
809 iflags);
812 TernaryNodeResult newForHead(Node init, Node test, Node update,
813 const TokenPos& pos) {
814 return newResult<TernaryNode>(ParseNodeKind::ForHead, init, test, update,
815 pos);
818 TernaryNodeResult newForInOrOfHead(ParseNodeKind kind, Node target,
819 Node iteratedExpr, const TokenPos& pos) {
820 MOZ_ASSERT(kind == ParseNodeKind::ForIn || kind == ParseNodeKind::ForOf);
821 return newResult<TernaryNode>(kind, target, nullptr, iteratedExpr, pos);
824 SwitchStatementResult newSwitchStatement(
825 uint32_t begin, Node discriminant,
826 LexicalScopeNodeType lexicalForCaseList, bool hasDefault) {
827 return newResult<SwitchStatement>(begin, discriminant, lexicalForCaseList,
828 hasDefault);
831 CaseClauseResult newCaseOrDefault(uint32_t begin, Node expr, Node body) {
832 return newResult<CaseClause>(expr, body, begin);
835 ContinueStatementResult newContinueStatement(TaggedParserAtomIndex label,
836 const TokenPos& pos) {
837 return newResult<ContinueStatement>(label, pos);
840 BreakStatementResult newBreakStatement(TaggedParserAtomIndex label,
841 const TokenPos& pos) {
842 return newResult<BreakStatement>(label, pos);
845 UnaryNodeResult newReturnStatement(Node expr, const TokenPos& pos) {
846 MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
847 return newResult<UnaryNode>(ParseNodeKind::ReturnStmt, pos, expr);
850 UnaryNodeResult newExpressionBody(Node expr) {
851 return newResult<UnaryNode>(ParseNodeKind::ReturnStmt, expr->pn_pos, expr);
854 BinaryNodeResult newWithStatement(uint32_t begin, Node expr, Node body) {
855 return newResult<BinaryNode>(ParseNodeKind::WithStmt,
856 TokenPos(begin, body->pn_pos.end), expr, body);
859 LabeledStatementResult newLabeledStatement(TaggedParserAtomIndex label,
860 Node stmt, uint32_t begin) {
861 return newResult<LabeledStatement>(label, stmt, begin);
864 UnaryNodeResult newThrowStatement(Node expr, const TokenPos& pos) {
865 MOZ_ASSERT(pos.encloses(expr->pn_pos));
866 return newResult<UnaryNode>(ParseNodeKind::ThrowStmt, pos, expr);
869 TernaryNodeResult newTryStatement(uint32_t begin, Node body,
870 LexicalScopeNodeType catchScope,
871 Node finallyBlock) {
872 return newResult<TryNode>(begin, body, catchScope, finallyBlock);
875 DebuggerStatementResult newDebuggerStatement(const TokenPos& pos) {
876 return newResult<DebuggerStatement>(pos);
879 NameNodeResult newPropertyName(TaggedParserAtomIndex name,
880 const TokenPos& pos) {
881 return newResult<NameNode>(ParseNodeKind::PropertyNameExpr, name, pos);
884 PropertyAccessResult newPropertyAccess(Node expr, NameNodeType key) {
885 return newResult<PropertyAccess>(expr, key, expr->pn_pos.begin,
886 key->pn_pos.end);
889 PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) {
890 return newResult<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
893 OptionalPropertyAccessResult newOptionalPropertyAccess(Node expr,
894 NameNodeType key) {
895 return newResult<OptionalPropertyAccess>(expr, key, expr->pn_pos.begin,
896 key->pn_pos.end);
899 OptionalPropertyByValueResult newOptionalPropertyByValue(Node lhs, Node index,
900 uint32_t end) {
901 return newResult<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin,
902 end);
905 PrivateMemberAccessResult newPrivateMemberAccess(Node lhs,
906 NameNodeType privateName,
907 uint32_t end) {
908 return newResult<PrivateMemberAccess>(lhs, privateName, lhs->pn_pos.begin,
909 end);
912 OptionalPrivateMemberAccessResult newOptionalPrivateMemberAccess(
913 Node lhs, NameNodeType privateName, uint32_t end) {
914 return newResult<OptionalPrivateMemberAccess>(lhs, privateName,
915 lhs->pn_pos.begin, end);
918 bool setupCatchScope(LexicalScopeNodeType lexicalScope, Node catchName,
919 Node catchBody) {
920 BinaryNode* catchClause;
921 if (catchName) {
922 MOZ_TRY_VAR_OR_RETURN(
923 catchClause,
924 newResult<BinaryNode>(ParseNodeKind::Catch, catchName, catchBody),
925 false);
926 } else {
927 MOZ_TRY_VAR_OR_RETURN(
928 catchClause,
929 newResult<BinaryNode>(ParseNodeKind::Catch, catchBody->pn_pos,
930 catchName, catchBody),
931 false);
933 lexicalScope->setScopeBody(catchClause);
934 return true;
937 [[nodiscard]] inline bool setLastFunctionFormalParameterDefault(
938 FunctionNodeType funNode, Node defaultValue);
940 void checkAndSetIsDirectRHSAnonFunction(Node pn) {
941 if (IsAnonymousFunctionDefinition(pn)) {
942 pn->setDirectRHSAnonFunction(true);
946 ParamsBodyNodeResult newParamsBody(const TokenPos& pos) {
947 return newResult<ParamsBodyNode>(pos);
950 FunctionNodeResult newFunction(FunctionSyntaxKind syntaxKind,
951 const TokenPos& pos) {
952 return newResult<FunctionNode>(syntaxKind, pos);
955 BinaryNodeResult newObjectMethodOrPropertyDefinition(Node key, Node value,
956 AccessorType atype) {
957 MOZ_ASSERT(isUsableAsObjectPropertyName(key));
959 return newResult<PropertyDefinition>(key, value, atype);
962 void setFunctionFormalParametersAndBody(FunctionNodeType funNode,
963 ParamsBodyNodeType paramsBody) {
964 funNode->setBody(paramsBody);
966 void setFunctionBox(FunctionNodeType funNode, FunctionBox* funbox) {
967 funNode->setFunbox(funbox);
968 funbox->functionNode = funNode;
970 void addFunctionFormalParameter(FunctionNodeType funNode, Node argpn) {
971 addList(/* list = */ funNode->body(), /* kid = */ argpn);
973 void setFunctionBody(FunctionNodeType funNode, LexicalScopeNodeType body) {
974 addList(/* list = */ funNode->body(), /* kid = */ body);
977 ModuleNodeResult newModule(const TokenPos& pos) {
978 return newResult<ModuleNode>(pos);
981 LexicalScopeNodeResult newLexicalScope(LexicalScope::ParserData* bindings,
982 Node body,
983 ScopeKind kind = ScopeKind::Lexical) {
984 return newResult<LexicalScopeNode>(bindings, body, kind);
987 ClassBodyScopeNodeResult newClassBodyScope(
988 ClassBodyScope::ParserData* bindings, ListNodeType body) {
989 return newResult<ClassBodyScopeNode>(bindings, body);
992 CallNodeResult newNewExpression(uint32_t begin, Node ctor, ListNodeType args,
993 bool isSpread) {
994 return newResult<CallNode>(ParseNodeKind::NewExpr,
995 isSpread ? JSOp::SpreadNew : JSOp::New,
996 TokenPos(begin, args->pn_pos.end), ctor, args);
999 AssignmentNodeResult newAssignment(ParseNodeKind kind, Node lhs, Node rhs) {
1000 if ((kind == ParseNodeKind::AssignExpr ||
1001 kind == ParseNodeKind::CoalesceAssignExpr ||
1002 kind == ParseNodeKind::OrAssignExpr ||
1003 kind == ParseNodeKind::AndAssignExpr) &&
1004 lhs->isKind(ParseNodeKind::Name) && !lhs->isInParens()) {
1005 checkAndSetIsDirectRHSAnonFunction(rhs);
1008 return newResult<AssignmentNode>(kind, lhs, rhs);
1011 BinaryNodeResult newInitExpr(Node lhs, Node rhs) {
1012 TokenPos pos(lhs->pn_pos.begin, rhs->pn_pos.end);
1013 return newResult<BinaryNode>(ParseNodeKind::InitExpr, pos, lhs, rhs);
1016 bool isUnparenthesizedAssignment(Node node) {
1017 if ((node->isKind(ParseNodeKind::AssignExpr)) && !node->isInParens()) {
1018 return true;
1021 return false;
1024 bool isUnparenthesizedUnaryExpression(Node node) {
1025 if (!node->isInParens()) {
1026 ParseNodeKind kind = node->getKind();
1027 return kind == ParseNodeKind::VoidExpr ||
1028 kind == ParseNodeKind::NotExpr ||
1029 kind == ParseNodeKind::BitNotExpr ||
1030 kind == ParseNodeKind::PosExpr || kind == ParseNodeKind::NegExpr ||
1031 kind == ParseNodeKind::AwaitExpr || IsTypeofKind(kind) ||
1032 IsDeleteKind(kind);
1034 return false;
1037 bool isReturnStatement(Node node) {
1038 return node->isKind(ParseNodeKind::ReturnStmt);
1041 bool isStatementPermittedAfterReturnStatement(Node node) {
1042 ParseNodeKind kind = node->getKind();
1043 return kind == ParseNodeKind::Function || kind == ParseNodeKind::VarStmt ||
1044 kind == ParseNodeKind::BreakStmt ||
1045 kind == ParseNodeKind::ThrowStmt || kind == ParseNodeKind::EmptyStmt;
1048 bool isSuperBase(Node node) { return node->isKind(ParseNodeKind::SuperBase); }
1050 bool isUsableAsObjectPropertyName(Node node) {
1051 return node->isKind(ParseNodeKind::NumberExpr) ||
1052 node->isKind(ParseNodeKind::BigIntExpr) ||
1053 node->isKind(ParseNodeKind::ObjectPropertyName) ||
1054 node->isKind(ParseNodeKind::StringExpr) ||
1055 node->isKind(ParseNodeKind::ComputedName) ||
1056 node->isKind(ParseNodeKind::PrivateName);
1059 AssignmentNodeResult finishInitializerAssignment(NameNodeType nameNode,
1060 Node init) {
1061 MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
1062 MOZ_ASSERT(!nameNode->isInParens());
1064 checkAndSetIsDirectRHSAnonFunction(init);
1066 return newAssignment(ParseNodeKind::AssignExpr, nameNode, init);
1069 void setBeginPosition(Node pn, Node oth) {
1070 setBeginPosition(pn, oth->pn_pos.begin);
1072 void setBeginPosition(Node pn, uint32_t begin) {
1073 pn->pn_pos.begin = begin;
1074 MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
1077 void setEndPosition(Node pn, Node oth) {
1078 setEndPosition(pn, oth->pn_pos.end);
1080 void setEndPosition(Node pn, uint32_t end) {
1081 pn->pn_pos.end = end;
1082 MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
1085 uint32_t getFunctionNameOffset(Node func, TokenStreamAnyChars& ts) {
1086 return func->pn_pos.begin;
1089 ListNodeResult newList(ParseNodeKind kind, const TokenPos& pos) {
1090 auto list = newResult<ListNode>(kind, pos);
1091 MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<DeclarationListNode>());
1092 MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<ParamsBodyNode>());
1093 return list;
1096 ListNodeResult newList(ParseNodeKind kind, Node kid) {
1097 auto list = newResult<ListNode>(kind, kid);
1098 MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<DeclarationListNode>());
1099 MOZ_ASSERT_IF(list.isOk(), !list.unwrap()->is<ParamsBodyNode>());
1100 return list;
1103 DeclarationListNodeResult newDeclarationList(ParseNodeKind kind,
1104 const TokenPos& pos) {
1105 return newResult<DeclarationListNode>(kind, pos);
1108 ListNodeResult newCommaExpressionList(Node kid) {
1109 return newResult<ListNode>(ParseNodeKind::CommaExpr, kid);
1112 void addList(ListNodeType list, Node kid) { list->append(kid); }
1114 void setListHasNonConstInitializer(ListNodeType literal) {
1115 literal->setHasNonConstInitializer();
1118 // NOTE: This is infallible.
1119 template <typename NodeType>
1120 [[nodiscard]] NodeType parenthesize(NodeType node) {
1121 node->setInParens(true);
1122 return node;
1125 // NOTE: This is infallible.
1126 template <typename NodeType>
1127 [[nodiscard]] NodeType setLikelyIIFE(NodeType node) {
1128 return parenthesize(node);
1131 bool isName(Node node) { return node->isKind(ParseNodeKind::Name); }
1133 bool isArgumentsName(Node node) {
1134 return node->isKind(ParseNodeKind::Name) &&
1135 node->as<NameNode>().atom() ==
1136 TaggedParserAtomIndex::WellKnown::arguments();
1139 bool isEvalName(Node node) {
1140 return node->isKind(ParseNodeKind::Name) &&
1141 node->as<NameNode>().atom() ==
1142 TaggedParserAtomIndex::WellKnown::eval();
1145 bool isAsyncKeyword(Node node) {
1146 return node->isKind(ParseNodeKind::Name) &&
1147 node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
1148 node->as<NameNode>().atom() ==
1149 TaggedParserAtomIndex::WellKnown::async();
1152 bool isPrivateName(Node node) {
1153 return node->isKind(ParseNodeKind::PrivateName);
1156 bool isPrivateMemberAccess(Node node) {
1157 if (node->isKind(ParseNodeKind::OptionalChain)) {
1158 return isPrivateMemberAccess(node->as<UnaryNode>().kid());
1160 return node->is<PrivateMemberAccessBase>();
1163 TaggedParserAtomIndex maybeDottedProperty(Node pn) {
1164 return pn->is<PropertyAccessBase>() ? pn->as<PropertyAccessBase>().name()
1165 : TaggedParserAtomIndex::null();
1167 TaggedParserAtomIndex isStringExprStatement(Node pn, TokenPos* pos) {
1168 if (pn->is<UnaryNode>()) {
1169 UnaryNode* unary = &pn->as<UnaryNode>();
1170 if (auto atom = unary->isStringExprStatement()) {
1171 *pos = unary->kid()->pn_pos;
1172 return atom;
1175 return TaggedParserAtomIndex::null();
1178 bool reuseLazyInnerFunctions() { return reuseGCThings; }
1179 bool reuseClosedOverBindings() { return reuseGCThings; }
1180 bool reuseRegexpSyntaxParse() { return reuseGCThings; }
1181 void nextLazyInnerFunction() { lazyInnerFunctionIndex++; }
1182 TaggedParserAtomIndex nextLazyClosedOverBinding() {
1183 // Trailing nullptrs were elided in PerHandlerParser::finishFunction().
1184 auto closedOverBindings = previousParseCache_.closedOverBindings();
1185 if (lazyClosedOverBindingIndex >= closedOverBindings.Length()) {
1186 return TaggedParserAtomIndex::null();
1189 return closedOverBindings[lazyClosedOverBindingIndex++];
1191 const ScriptStencil& cachedScriptData() const {
1192 // lazyInnerFunctionIndex is incremented with nextLazyInnferFunction before
1193 // reading the content, thus we need -1 to access the element that we just
1194 // skipped.
1195 return previousParseCache_.scriptData(lazyInnerFunctionIndex - 1);
1197 const ScriptStencilExtra& cachedScriptExtra() const {
1198 // lazyInnerFunctionIndex is incremented with nextLazyInnferFunction before
1199 // reading the content, thus we need -1 to access the element that we just
1200 // skipped.
1201 return previousParseCache_.scriptExtra(lazyInnerFunctionIndex - 1);
1204 void setPrivateNameKind(Node node, PrivateNameKind kind) {
1205 MOZ_ASSERT(node->is<NameNode>());
1206 node->as<NameNode>().setPrivateNameKind(kind);
1210 inline bool FullParseHandler::setLastFunctionFormalParameterDefault(
1211 FunctionNodeType funNode, Node defaultValue) {
1212 ParamsBodyNode* body = funNode->body();
1213 ParseNode* arg = body->last();
1214 ParseNode* pn;
1215 MOZ_TRY_VAR_OR_RETURN(
1216 pn, newAssignment(ParseNodeKind::AssignExpr, arg, defaultValue), false);
1218 body->replaceLast(pn);
1219 return true;
1222 } // namespace frontend
1223 } // namespace js
1225 #endif /* frontend_FullParseHandler_h */