Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / ParseNode.h
blob3fe5c0a2eca07ace91aecbbedd5ef412c58beb77
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_ParseNode_h
8 #define frontend_ParseNode_h
10 #include "mozilla/Assertions.h"
12 #include <iterator>
13 #include <stddef.h>
14 #include <stdint.h>
16 #include "jstypes.h" // js::Bit
18 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
19 #include "frontend/NameAnalysisTypes.h" // PrivateNameKind
20 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
21 #include "frontend/Stencil.h" // BigIntStencil
22 #include "frontend/Token.h"
23 #include "js/TypeDecls.h"
24 #include "vm/Opcodes.h"
25 #include "vm/Scope.h"
26 #include "vm/ScopeKind.h"
28 // [SMDOC] ParseNode tree lifetime information
30 // - All the `ParseNode` instances MUST BE explicitly allocated in the context's
31 // `LifoAlloc`. This is typically implemented by the `FullParseHandler` or it
32 // can be reimplemented with a custom `new_`.
34 // - The tree is bulk-deallocated when the parser is deallocated. Consequently,
35 // references to a subtree MUST NOT exist once the parser has been
36 // deallocated.
38 // - This bulk-deallocation DOES NOT run destructors.
40 // - Instances of `LexicalScope::ParserData` and `ClassBodyScope::ParserData`
41 // MUST BE allocated as instances of `ParseNode`, in the same `LifoAlloc`.
42 // They are bulk-deallocated alongside the rest of the tree.
44 struct JSContext;
46 namespace js {
48 class JS_PUBLIC_API GenericPrinter;
49 class LifoAlloc;
50 class RegExpObject;
52 namespace frontend {
54 class ParserAtomsTable;
55 class ParserBase;
56 class ParseContext;
57 struct ExtensibleCompilationStencil;
58 class ParserSharedBase;
59 class FullParseHandler;
61 class FunctionBox;
63 #define FOR_EACH_PARSE_NODE_KIND(F) \
64 F(EmptyStmt, NullaryNode) \
65 F(ExpressionStmt, UnaryNode) \
66 F(CommaExpr, ListNode) \
67 F(ConditionalExpr, ConditionalExpression) \
68 F(PropertyDefinition, PropertyDefinition) \
69 F(Shorthand, BinaryNode) \
70 F(PosExpr, UnaryNode) \
71 F(NegExpr, UnaryNode) \
72 F(PreIncrementExpr, UnaryNode) \
73 F(PostIncrementExpr, UnaryNode) \
74 F(PreDecrementExpr, UnaryNode) \
75 F(PostDecrementExpr, UnaryNode) \
76 F(PropertyNameExpr, NameNode) \
77 F(DotExpr, PropertyAccess) \
78 F(ElemExpr, PropertyByValue) \
79 F(PrivateMemberExpr, PrivateMemberAccess) \
80 F(OptionalDotExpr, OptionalPropertyAccess) \
81 F(OptionalChain, UnaryNode) \
82 F(OptionalElemExpr, OptionalPropertyByValue) \
83 F(OptionalPrivateMemberExpr, OptionalPrivateMemberAccess) \
84 F(OptionalCallExpr, CallNode) \
85 F(ArrayExpr, ListNode) \
86 F(Elision, NullaryNode) \
87 F(StatementList, ListNode) \
88 F(LabelStmt, LabeledStatement) \
89 F(ObjectExpr, ListNode) \
90 F(CallExpr, CallNode) \
91 F(Arguments, ListNode) \
92 F(Name, NameNode) \
93 F(ObjectPropertyName, NameNode) \
94 F(PrivateName, NameNode) \
95 F(ComputedName, UnaryNode) \
96 F(NumberExpr, NumericLiteral) \
97 F(BigIntExpr, BigIntLiteral) \
98 F(StringExpr, NameNode) \
99 F(TemplateStringListExpr, ListNode) \
100 F(TemplateStringExpr, NameNode) \
101 F(TaggedTemplateExpr, CallNode) \
102 F(CallSiteObj, CallSiteNode) \
103 F(RegExpExpr, RegExpLiteral) \
104 F(TrueExpr, BooleanLiteral) \
105 F(FalseExpr, BooleanLiteral) \
106 F(NullExpr, NullLiteral) \
107 F(RawUndefinedExpr, RawUndefinedLiteral) \
108 F(ThisExpr, UnaryNode) \
109 IF_RECORD_TUPLE(F(RecordExpr, ListNode)) \
110 IF_RECORD_TUPLE(F(TupleExpr, ListNode)) \
111 F(Function, FunctionNode) \
112 F(Module, ModuleNode) \
113 F(IfStmt, TernaryNode) \
114 F(SwitchStmt, SwitchStatement) \
115 F(Case, CaseClause) \
116 F(WhileStmt, BinaryNode) \
117 F(DoWhileStmt, BinaryNode) \
118 F(ForStmt, ForNode) \
119 F(BreakStmt, BreakStatement) \
120 F(ContinueStmt, ContinueStatement) \
121 F(VarStmt, DeclarationListNode) \
122 F(ConstDecl, DeclarationListNode) \
123 F(WithStmt, BinaryNode) \
124 F(ReturnStmt, UnaryNode) \
125 F(NewExpr, CallNode) \
126 IF_DECORATORS(F(DecoratorList, ListNode)) \
127 /* Delete operations. These must be sequential. */ \
128 F(DeleteNameExpr, UnaryNode) \
129 F(DeletePropExpr, UnaryNode) \
130 F(DeleteElemExpr, UnaryNode) \
131 F(DeleteOptionalChainExpr, UnaryNode) \
132 F(DeleteExpr, UnaryNode) \
133 F(TryStmt, TernaryNode) \
134 F(Catch, BinaryNode) \
135 F(ThrowStmt, UnaryNode) \
136 F(DebuggerStmt, DebuggerStatement) \
137 F(Generator, NullaryNode) \
138 F(InitialYield, UnaryNode) \
139 F(YieldExpr, UnaryNode) \
140 F(YieldStarExpr, UnaryNode) \
141 F(LexicalScope, LexicalScopeNode) \
142 F(LetDecl, DeclarationListNode) \
143 F(ImportDecl, BinaryNode) \
144 F(ImportSpecList, ListNode) \
145 F(ImportSpec, BinaryNode) \
146 F(ImportNamespaceSpec, UnaryNode) \
147 F(ImportAssertionList, ListNode) \
148 F(ImportAssertion, BinaryNode) \
149 F(ImportModuleRequest, BinaryNode) \
150 F(ExportStmt, UnaryNode) \
151 F(ExportFromStmt, BinaryNode) \
152 F(ExportDefaultStmt, BinaryNode) \
153 F(ExportSpecList, ListNode) \
154 F(ExportSpec, BinaryNode) \
155 F(ExportNamespaceSpec, UnaryNode) \
156 F(ExportBatchSpecStmt, NullaryNode) \
157 F(ForIn, TernaryNode) \
158 F(ForOf, TernaryNode) \
159 F(ForHead, TernaryNode) \
160 F(ParamsBody, ParamsBodyNode) \
161 F(Spread, UnaryNode) \
162 F(MutateProto, UnaryNode) \
163 F(ClassDecl, ClassNode) \
164 F(DefaultConstructor, ClassMethod) \
165 F(ClassBodyScope, ClassBodyScopeNode) \
166 F(ClassMethod, ClassMethod) \
167 F(StaticClassBlock, StaticClassBlock) \
168 F(ClassField, ClassField) \
169 F(ClassMemberList, ListNode) \
170 F(ClassNames, ClassNames) \
171 F(NewTargetExpr, NewTargetNode) \
172 F(PosHolder, NullaryNode) \
173 F(SuperBase, UnaryNode) \
174 F(SuperCallExpr, CallNode) \
175 F(SetThis, BinaryNode) \
176 F(ImportMetaExpr, BinaryNode) \
177 F(CallImportExpr, BinaryNode) \
178 F(CallImportSpec, BinaryNode) \
179 F(InitExpr, BinaryNode) \
181 /* Unary operators. */ \
182 F(TypeOfNameExpr, UnaryNode) \
183 F(TypeOfExpr, UnaryNode) \
184 F(VoidExpr, UnaryNode) \
185 F(NotExpr, UnaryNode) \
186 F(BitNotExpr, UnaryNode) \
187 F(AwaitExpr, UnaryNode) \
189 /* \
190 * Binary operators. \
191 * This list must be kept in the same order in several places: \
192 * - The binary operators in ParseNode.h \
193 * - the binary operators in TokenKind.h \
194 * - the precedence list in Parser.cpp \
195 * - the JSOp code list in BytecodeEmitter.cpp \
196 */ \
197 F(CoalesceExpr, ListNode) \
198 F(OrExpr, ListNode) \
199 F(AndExpr, ListNode) \
200 F(BitOrExpr, ListNode) \
201 F(BitXorExpr, ListNode) \
202 F(BitAndExpr, ListNode) \
203 F(StrictEqExpr, ListNode) \
204 F(EqExpr, ListNode) \
205 F(StrictNeExpr, ListNode) \
206 F(NeExpr, ListNode) \
207 F(LtExpr, ListNode) \
208 F(LeExpr, ListNode) \
209 F(GtExpr, ListNode) \
210 F(GeExpr, ListNode) \
211 F(InstanceOfExpr, ListNode) \
212 F(InExpr, ListNode) \
213 F(PrivateInExpr, ListNode) \
214 F(LshExpr, ListNode) \
215 F(RshExpr, ListNode) \
216 F(UrshExpr, ListNode) \
217 F(AddExpr, ListNode) \
218 F(SubExpr, ListNode) \
219 F(MulExpr, ListNode) \
220 F(DivExpr, ListNode) \
221 F(ModExpr, ListNode) \
222 F(PowExpr, ListNode) \
224 /* Assignment operators (= += -= etc.). */ \
225 /* AssignmentNode::test assumes all these are consecutive. */ \
226 F(AssignExpr, AssignmentNode) \
227 F(AddAssignExpr, AssignmentNode) \
228 F(SubAssignExpr, AssignmentNode) \
229 F(CoalesceAssignExpr, AssignmentNode) \
230 F(OrAssignExpr, AssignmentNode) \
231 F(AndAssignExpr, AssignmentNode) \
232 F(BitOrAssignExpr, AssignmentNode) \
233 F(BitXorAssignExpr, AssignmentNode) \
234 F(BitAndAssignExpr, AssignmentNode) \
235 F(LshAssignExpr, AssignmentNode) \
236 F(RshAssignExpr, AssignmentNode) \
237 F(UrshAssignExpr, AssignmentNode) \
238 F(MulAssignExpr, AssignmentNode) \
239 F(DivAssignExpr, AssignmentNode) \
240 F(ModAssignExpr, AssignmentNode) \
241 F(PowAssignExpr, AssignmentNode)
244 * Parsing builds a tree of nodes that directs code generation. This tree is
245 * not a concrete syntax tree in all respects (for example, || and && are left
246 * associative, but (A && B && C) translates into the right-associated tree
247 * <A && <B && C>> so that code generation can emit a left-associative branch
248 * around <B && C> when A is false). Nodes are labeled by kind.
250 * The long comment after this enum block describes the kinds in detail.
252 enum class ParseNodeKind : uint16_t {
253 // These constants start at 1001, the better to catch
254 LastUnused = 1000,
255 #define EMIT_ENUM(name, _type) name,
256 FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
257 #undef EMIT_ENUM
258 Limit,
259 Start = LastUnused + 1,
260 BinOpFirst = ParseNodeKind::CoalesceExpr,
261 BinOpLast = ParseNodeKind::PowExpr,
262 AssignmentStart = ParseNodeKind::AssignExpr,
263 AssignmentLast = ParseNodeKind::PowAssignExpr,
266 inline bool IsDeleteKind(ParseNodeKind kind) {
267 return ParseNodeKind::DeleteNameExpr <= kind &&
268 kind <= ParseNodeKind::DeleteExpr;
271 inline bool IsTypeofKind(ParseNodeKind kind) {
272 return ParseNodeKind::TypeOfNameExpr <= kind &&
273 kind <= ParseNodeKind::TypeOfExpr;
277 * <Definitions>
278 * Function (FunctionNode)
279 * funbox: ptr to js::FunctionBox
280 * body: ParamsBody or null for lazily-parsed function
281 * syntaxKind: the syntax of the function
282 * ParamsBody (ListNode)
283 * head: list of formal parameters with
284 * * Name node with non-empty name for SingleNameBinding without
285 * Initializer
286 * * AssignExpr node for SingleNameBinding with Initializer
287 * * Name node with empty name for destructuring
288 * expr: Array or Object for BindingPattern without
289 * Initializer, Assign for BindingPattern with
290 * Initializer
291 * followed by:
292 * * LexicalScopeNode
293 * count: number of formal parameters + 1
294 * Spread (UnaryNode)
295 * kid: expression being spread
296 * ClassDecl (ClassNode)
297 * kid1: ClassNames for class name. can be null for anonymous class.
298 * kid2: expression after `extends`. null if no expression
299 * kid3: either of
300 * * ClassMemberList, if anonymous class
301 * * LexicalScopeNode which contains ClassMemberList as scopeBody,
302 * if named class
303 * ClassNames (ClassNames)
304 * left: Name node for outer binding, or null if the class is an expression
305 * that doesn't create an outer binding
306 * right: Name node for inner binding
307 * ClassMemberList (ListNode)
308 * head: list of N ClassMethod, ClassField or StaticClassBlock nodes
309 * count: N >= 0
310 * DefaultConstructor (ClassMethod)
311 * name: propertyName
312 * method: methodDefinition
313 * ClassMethod (ClassMethod)
314 * name: propertyName
315 * method: methodDefinition
316 * initializerIfPrivate: initializer to stamp private method onto instance
317 * Module (ModuleNode)
318 * body: statement list of the module
320 * <Statements>
321 * StatementList (ListNode)
322 * head: list of N statements
323 * count: N >= 0
324 * IfStmt (TernaryNode)
325 * kid1: cond
326 * kid2: then
327 * kid3: else or null
328 * SwitchStmt (SwitchStatement)
329 * left: discriminant
330 * right: LexicalScope node that contains the list of Case nodes, with at
331 * most one default node.
332 * hasDefault: true if there's a default case
333 * Case (CaseClause)
334 * left: case-expression if CaseClause, or null if DefaultClause
335 * right: StatementList node for this case's statements
336 * WhileStmt (BinaryNode)
337 * left: cond
338 * right: body
339 * DoWhileStmt (BinaryNode)
340 * left: body
341 * right: cond
342 * ForStmt (ForNode)
343 * left: one of
344 * * ForIn: for (x in y) ...
345 * * ForOf: for (x of x) ...
346 * * ForHead: for (;;) ...
347 * right: body
348 * ForIn (TernaryNode)
349 * kid1: declaration or expression to left of 'in'
350 * kid2: null
351 * kid3: object expr to right of 'in'
352 * ForOf (TernaryNode)
353 * kid1: declaration or expression to left of 'of'
354 * kid2: null
355 * kid3: expr to right of 'of'
356 * ForHead (TernaryNode)
357 * kid1: init expr before first ';' or nullptr
358 * kid2: cond expr before second ';' or nullptr
359 * kid3: update expr after second ';' or nullptr
360 * ThrowStmt (UnaryNode)
361 * kid: thrown exception
362 * TryStmt (TernaryNode)
363 * kid1: try block
364 * kid2: null or LexicalScope for catch-block with scopeBody pointing to a
365 * Catch node
366 * kid3: null or finally block
367 * Catch (BinaryNode)
368 * left: Name, Array, or Object catch var node
369 * (Array or Object if destructuring),
370 * or null if optional catch binding
371 * right: catch block statements
372 * BreakStmt (BreakStatement)
373 * label: label or null
374 * ContinueStmt (ContinueStatement)
375 * label: label or null
376 * WithStmt (BinaryNode)
377 * left: head expr
378 * right: body
379 * VarStmt, LetDecl, ConstDecl (DeclarationListNode)
380 * head: list of N Name or AssignExpr nodes
381 * each name node has either
382 * atom: variable name
383 * expr: initializer or null
384 * or
385 * atom: variable name
386 * each assignment node has
387 * left: pattern
388 * right: initializer
389 * count: N > 0
390 * ReturnStmt (UnaryNode)
391 * kid: returned expression, or null if none
392 * ExpressionStmt (UnaryNode)
393 * kid: expr
394 * EmptyStmt (NullaryNode)
395 * (no fields)
396 * LabelStmt (LabeledStatement)
397 * atom: label
398 * expr: labeled statement
399 * ImportDecl (BinaryNode)
400 * left: ImportSpecList import specifiers
401 * right: String module specifier
402 * ImportSpecList (ListNode)
403 * head: list of N ImportSpec nodes
404 * count: N >= 0 (N = 0 for `import {} from ...`)
405 * ImportSpec (BinaryNode)
406 * left: import name
407 * right: local binding name
408 * ImportNamespaceSpec (UnaryNode)
409 * kid: local binding name
410 * ExportStmt (UnaryNode)
411 * kid: declaration expression
412 * ExportFromStmt (BinaryNode)
413 * left: ExportSpecList export specifiers
414 * right: String module specifier
415 * ExportSpecList (ListNode)
416 * head: list of N ExportSpec nodes
417 * count: N >= 0 (N = 0 for `export {}`)
418 * ExportSpec (BinaryNode)
419 * left: local binding name
420 * right: export name
421 * ExportNamespaceSpec (UnaryNode)
422 * kid: export name
423 * ExportDefaultStmt (BinaryNode)
424 * left: export default declaration or expression
425 * right: Name node for assignment
427 * <Expressions>
428 * The `Expr` suffix is used for nodes that can appear anywhere an expression
429 * could appear. It is not used on a few weird kinds like Arguments and
430 * CallSiteObj that are always the child node of an expression node, but which
431 * can't stand alone.
433 * All left-associated binary trees of the same type are optimized into lists
434 * to avoid recursion when processing expression chains.
436 * CommaExpr (ListNode)
437 * head: list of N comma-separated exprs
438 * count: N >= 2
439 * AssignExpr (BinaryNode)
440 * left: target of assignment
441 * right: value to assign
442 * AddAssignExpr, SubAssignExpr, CoalesceAssignExpr, OrAssignExpr,
443 * AndAssignExpr, BitOrAssignExpr, BitXorAssignExpr, BitAndAssignExpr,
444 * LshAssignExpr, RshAssignExpr, UrshAssignExpr, MulAssignExpr, DivAssignExpr,
445 * ModAssignExpr, PowAssignExpr (AssignmentNode)
446 * left: target of assignment
447 * right: value to assign
448 * ConditionalExpr (ConditionalExpression)
449 * (cond ? thenExpr : elseExpr)
450 * kid1: cond
451 * kid2: thenExpr
452 * kid3: elseExpr
453 * CoalesceExpr, OrExpr, AndExpr, BitOrExpr, BitXorExpr,
454 * BitAndExpr, StrictEqExpr, EqExpr, StrictNeExpr, NeExpr, LtExpr, LeExpr,
455 * GtExpr, GeExpr, InstanceOfExpr, InExpr, LshExpr, RshExpr, UrshExpr, AddExpr,
456 * SubExpr, MulExpr, DivExpr, ModExpr, PowExpr (ListNode)
457 * head: list of N subexpressions
458 * All of these operators are left-associative except Pow which is
459 * right-associative, but still forms a list (see comments in
460 * ParseNode::appendOrCreateList).
461 * count: N >= 2
462 * PosExpr, NegExpr, VoidExpr, NotExpr, BitNotExpr, TypeOfNameExpr,
463 * TypeOfExpr (UnaryNode)
464 * kid: unary expr
465 * PreIncrementExpr, PostIncrementExpr, PreDecrementExpr,
466 * PostDecrementExpr (UnaryNode)
467 * kid: member expr
468 * NewExpr (BinaryNode)
469 * left: ctor expression on the left of the '('
470 * right: Arguments
471 * DecoratorList (ListNode)
472 * head: list of N nodes, each item is one of:
473 * * NameNode (DecoratorMemberExpression)
474 * * CallNode (DecoratorCallExpression)
475 * * Node (DecoratorParenthesizedExpression)
476 * count: N > 0
477 * DeleteNameExpr, DeletePropExpr, DeleteElemExpr, DeleteExpr (UnaryNode)
478 * kid: expression that's evaluated, then the overall delete evaluates to
479 * true; can't be a kind for a more-specific ParseNodeKind::Delete*
480 * unless constant folding (or a similar parse tree manipulation) has
481 * occurred
482 * * DeleteNameExpr: Name expr
483 * * DeletePropExpr: Dot expr
484 * * DeleteElemExpr: Elem expr
485 * * DeleteOptionalChainExpr: Member expr
486 * * DeleteExpr: Member expr
487 * DeleteOptionalChainExpr (UnaryNode)
488 * kid: expression that's evaluated, then the overall delete evaluates to
489 * true; If constant folding occurs, Elem expr may become Dot expr.
490 * OptionalElemExpr does not get folded into OptionalDot.
491 * OptionalChain (UnaryNode)
492 * kid: expression that is evaluated as a chain. An Optional chain contains
493 * one or more optional nodes. It's first node (kid) is always an
494 * optional node, for example: an OptionalElemExpr, OptionalDotExpr, or
495 * OptionalCall. An OptionalChain will shortcircuit and return
496 * Undefined without evaluating the rest of the expression if any of the
497 * optional nodes it contains are nullish. An optionalChain also can
498 * contain nodes such as DotExpr, ElemExpr, NameExpr CallExpr, etc.
499 * These are evaluated normally.
500 * * OptionalDotExpr: Dot expr with jump
501 * * OptionalElemExpr: Elem expr with jump
502 * * OptionalCallExpr: Call expr with jump
503 * * DotExpr: Dot expr without jump
504 * * ElemExpr: Elem expr without jump
505 * * CallExpr: Call expr without jump
506 * PropertyNameExpr (NameNode)
507 * atom: property name being accessed
508 * privateNameKind: kind of the name if private
509 * DotExpr (PropertyAccess)
510 * left: Member expr to left of '.'
511 * right: PropertyName to right of '.'
512 * OptionalDotExpr (OptionalPropertyAccess)
513 * left: Member expr to left of '.', short circuits back to OptionalChain
514 * if nullish.
515 * right: PropertyName to right of '.'
516 * ElemExpr (PropertyByValue)
517 * left: Member expr to left of '['
518 * right: expr between '[' and ']'
519 * OptionalElemExpr (OptionalPropertyByValue)
520 * left: Member expr to left of '[', short circuits back to OptionalChain
521 * if nullish.
522 * right: expr between '[' and ']'
523 * CallExpr (BinaryNode)
524 * left: callee expression on the left of the '('
525 * right: Arguments
526 * OptionalCallExpr (BinaryNode)
527 * left: callee expression on the left of the '(', short circuits back to
528 * OptionalChain if nullish.
529 * right: Arguments
530 * Arguments (ListNode)
531 * head: list of arg1, arg2, ... argN
532 * count: N >= 0
533 * ArrayExpr (ListNode)
534 * head: list of N array element expressions
535 * holes ([,,]) are represented by Elision nodes,
536 * spread elements ([...X]) are represented by Spread nodes
537 * count: N >= 0
538 * ObjectExpr (ListNode)
539 * head: list of N nodes, each item is one of:
540 * * MutateProto
541 * * PropertyDefinition
542 * * Shorthand
543 * * Spread
544 * count: N >= 0
545 * PropertyDefinition (PropertyDefinition)
546 * key-value pair in object initializer or destructuring lhs
547 * left: property id
548 * right: value
549 * Shorthand (BinaryNode)
550 * Same fields as PropertyDefinition. This is used for object literal
551 * properties using shorthand ({x}).
552 * ComputedName (UnaryNode)
553 * ES6 ComputedPropertyName.
554 * kid: the AssignmentExpression inside the square brackets
555 * Name (NameNode)
556 * atom: name, or object atom
557 * StringExpr (NameNode)
558 * atom: string
559 * TemplateStringListExpr (ListNode)
560 * head: list of alternating expr and template strings
561 * TemplateString [, expression, TemplateString]+
562 * there's at least one expression. If the template literal contains
563 * no ${}-delimited expression, it's parsed as a single TemplateString
564 * TemplateStringExpr (NameNode)
565 * atom: template string atom
566 * TaggedTemplateExpr (BinaryNode)
567 * left: tag expression
568 * right: Arguments, with the first being the call site object, then
569 * arg1, arg2, ... argN
570 * CallSiteObj (CallSiteNode)
571 * head: an Array of raw TemplateString, then corresponding cooked
572 * TemplateString nodes
573 * Array [, cooked TemplateString]+
574 * where the Array is
575 * [raw TemplateString]+
576 * RegExpExpr (RegExpLiteral)
577 * regexp: RegExp model object
578 * NumberExpr (NumericLiteral)
579 * value: double value of numeric literal
580 * BigIntExpr (BigIntLiteral)
581 * stencil: script compilation struct that has |bigIntData| vector
582 * index: index into the script compilation's |bigIntData| vector
583 * TrueExpr, FalseExpr (BooleanLiteral)
584 * NullExpr (NullLiteral)
585 * RawUndefinedExpr (RawUndefinedLiteral)
587 * ThisExpr (UnaryNode)
588 * kid: '.this' Name if function `this`, else nullptr
589 * SuperBase (UnaryNode)
590 * kid: '.this' Name
591 * SuperCallExpr (BinaryNode)
592 * left: SuperBase
593 * right: Arguments
594 * SetThis (BinaryNode)
595 * left: '.this' Name
596 * right: SuperCall
598 * LexicalScope (LexicalScopeNode)
599 * scopeBindings: scope bindings
600 * scopeBody: scope body
601 * Generator (NullaryNode)
602 * InitialYield (UnaryNode)
603 * kid: generator object
604 * YieldExpr, YieldStarExpr, AwaitExpr (UnaryNode)
605 * kid: expr or null
608 #define FOR_EACH_PARSENODE_SUBCLASS(MACRO) \
609 MACRO(BinaryNode) \
610 MACRO(AssignmentNode) \
611 MACRO(CaseClause) \
612 MACRO(ClassMethod) \
613 MACRO(ClassField) \
614 MACRO(StaticClassBlock) \
615 MACRO(PropertyDefinition) \
616 MACRO(ClassNames) \
617 MACRO(ForNode) \
618 MACRO(PropertyAccess) \
619 MACRO(OptionalPropertyAccess) \
620 MACRO(PropertyByValue) \
621 MACRO(OptionalPropertyByValue) \
622 MACRO(PrivateMemberAccess) \
623 MACRO(OptionalPrivateMemberAccess) \
624 MACRO(NewTargetNode) \
625 MACRO(SwitchStatement) \
626 MACRO(DeclarationListNode) \
628 MACRO(ParamsBodyNode) \
629 MACRO(FunctionNode) \
630 MACRO(ModuleNode) \
632 MACRO(LexicalScopeNode) \
633 MACRO(ClassBodyScopeNode) \
635 MACRO(ListNode) \
636 MACRO(CallSiteNode) \
637 MACRO(CallNode) \
639 MACRO(LoopControlStatement) \
640 MACRO(BreakStatement) \
641 MACRO(ContinueStatement) \
643 MACRO(NameNode) \
644 MACRO(LabeledStatement) \
646 MACRO(NullaryNode) \
647 MACRO(BooleanLiteral) \
648 MACRO(DebuggerStatement) \
649 MACRO(NullLiteral) \
650 MACRO(RawUndefinedLiteral) \
652 MACRO(NumericLiteral) \
653 MACRO(BigIntLiteral) \
655 MACRO(RegExpLiteral) \
657 MACRO(TernaryNode) \
658 MACRO(ClassNode) \
659 MACRO(ConditionalExpression) \
660 MACRO(TryNode) \
662 MACRO(UnaryNode) \
663 MACRO(ThisLiteral)
665 #define DECLARE_CLASS(typeName) class typeName;
666 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_CLASS)
667 #undef DECLARE_CLASS
669 enum class AccessorType { None, Getter, Setter };
671 static inline bool IsConstructorKind(FunctionSyntaxKind kind) {
672 return kind == FunctionSyntaxKind::ClassConstructor ||
673 kind == FunctionSyntaxKind::DerivedClassConstructor;
676 static inline bool IsMethodDefinitionKind(FunctionSyntaxKind kind) {
677 return IsConstructorKind(kind) || kind == FunctionSyntaxKind::Method ||
678 kind == FunctionSyntaxKind::FieldInitializer ||
679 kind == FunctionSyntaxKind::Getter ||
680 kind == FunctionSyntaxKind::Setter;
683 // To help diagnose sporadic crashes in the frontend, a few assertions are
684 // enabled in early beta builds. (Most are not; those still use MOZ_ASSERT.)
685 // See bug 1547561.
686 #if defined(EARLY_BETA_OR_EARLIER)
687 # define JS_PARSE_NODE_ASSERT MOZ_RELEASE_ASSERT
688 #else
689 # define JS_PARSE_NODE_ASSERT MOZ_ASSERT
690 #endif
692 class ParseNode;
693 struct ParseNodeError {};
694 using ParseNodeResult = mozilla::Result<ParseNode*, ParseNodeError>;
696 class ParseNode {
697 const ParseNodeKind pn_type;
699 bool pn_parens : 1; /* this expr was enclosed in parens */
700 bool pn_rhs_anon_fun : 1; /* this expr is anonymous function or class that
701 * is a direct RHS of ParseNodeKind::Assign or
702 * ParseNodeKind::PropertyDefinition of property,
703 * that needs SetFunctionName. */
705 protected:
706 // Used by ComputedName to indicate if the ComputedName is a
707 // a synthetic construct. This allows us to avoid needing to
708 // compute ToString on uncommon property values such as BigInt.
709 // Instead we parse as though they were computed names.
711 // We need this bit to distinguish a synthetic computed name like
712 // this however to undo this transformation in Reflect.parse and
713 // name guessing.
714 bool pn_synthetic_computed : 1;
716 ParseNode(const ParseNode& other) = delete;
717 void operator=(const ParseNode& other) = delete;
719 public:
720 explicit ParseNode(ParseNodeKind kind)
721 : pn_type(kind),
722 pn_parens(false),
723 pn_rhs_anon_fun(false),
724 pn_synthetic_computed(false),
725 pn_pos(0, 0),
726 pn_next(nullptr) {
727 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= kind);
728 JS_PARSE_NODE_ASSERT(kind < ParseNodeKind::Limit);
731 ParseNode(ParseNodeKind kind, const TokenPos& pos)
732 : pn_type(kind),
733 pn_parens(false),
734 pn_rhs_anon_fun(false),
735 pn_synthetic_computed(false),
736 pn_pos(pos),
737 pn_next(nullptr) {
738 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= kind);
739 JS_PARSE_NODE_ASSERT(kind < ParseNodeKind::Limit);
742 ParseNodeKind getKind() const {
743 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= pn_type);
744 JS_PARSE_NODE_ASSERT(pn_type < ParseNodeKind::Limit);
745 return pn_type;
747 bool isKind(ParseNodeKind kind) const { return getKind() == kind; }
749 protected:
750 size_t getKindAsIndex() const {
751 return size_t(getKind()) - size_t(ParseNodeKind::Start);
754 // Used to implement test() on a few ParseNodes efficiently.
755 // (This enum doesn't fully reflect the ParseNode class hierarchy,
756 // so don't use it for anything else.)
757 enum class TypeCode : uint8_t {
758 Nullary,
759 Unary,
760 Binary,
761 Ternary,
762 List,
763 Name,
764 Other
767 // typeCodeTable[getKindAsIndex()] is the type code of a ParseNode of kind
768 // pnk.
769 static const TypeCode typeCodeTable[];
771 private:
772 #ifdef DEBUG
773 static const size_t sizeTable[];
774 #endif
776 public:
777 TypeCode typeCode() const { return typeCodeTable[getKindAsIndex()]; }
779 bool isBinaryOperation() const {
780 ParseNodeKind kind = getKind();
781 return ParseNodeKind::BinOpFirst <= kind &&
782 kind <= ParseNodeKind::BinOpLast;
784 inline bool isName(TaggedParserAtomIndex name) const;
786 /* Boolean attributes. */
787 bool isInParens() const { return pn_parens; }
788 bool isLikelyIIFE() const { return isInParens(); }
789 void setInParens(bool enabled) { pn_parens = enabled; }
791 bool isDirectRHSAnonFunction() const { return pn_rhs_anon_fun; }
792 void setDirectRHSAnonFunction(bool enabled) { pn_rhs_anon_fun = enabled; }
794 TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
795 ParseNode* pn_next; /* intrinsic link in parent ListNode */
797 public:
799 * If |left| is a list of the given kind/left-associative op, append
800 * |right| to it and return |left|. Otherwise return a [left, right] list.
802 static ParseNodeResult appendOrCreateList(ParseNodeKind kind, ParseNode* left,
803 ParseNode* right,
804 FullParseHandler* handler,
805 ParseContext* pc);
807 /* True if pn is a parsenode representing a literal constant. */
808 bool isLiteral() const {
809 return isKind(ParseNodeKind::NumberExpr) ||
810 isKind(ParseNodeKind::BigIntExpr) ||
811 isKind(ParseNodeKind::StringExpr) ||
812 isKind(ParseNodeKind::TrueExpr) ||
813 isKind(ParseNodeKind::FalseExpr) ||
814 isKind(ParseNodeKind::NullExpr) ||
815 isKind(ParseNodeKind::RawUndefinedExpr);
818 inline bool isConstant();
820 template <class NodeType>
821 inline bool is() const {
822 return NodeType::test(*this);
825 /* Casting operations. */
826 template <class NodeType>
827 inline NodeType& as() {
828 MOZ_ASSERT(NodeType::test(*this));
829 return *static_cast<NodeType*>(this);
832 template <class NodeType>
833 inline const NodeType& as() const {
834 MOZ_ASSERT(NodeType::test(*this));
835 return *static_cast<const NodeType*>(this);
838 #ifdef DEBUG
839 // Debugger-friendly stderr printer.
840 void dump();
841 void dump(const ParserAtomsTable* parserAtoms);
842 void dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out);
843 void dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
844 int indent);
846 // The size of this node, in bytes.
847 size_t size() const { return sizeTable[getKindAsIndex()]; }
848 #endif
851 // Remove a ParseNode, **pnp, from a parse tree, putting another ParseNode,
852 // *pn, in its place.
854 // pnp points to a ParseNode pointer. This must be the only pointer that points
855 // to the parse node being replaced. The replacement, *pn, is unchanged except
856 // for its pn_next pointer; updating that is necessary if *pn's new parent is a
857 // list node.
858 inline void ReplaceNode(ParseNode** pnp, ParseNode* pn) {
859 pn->pn_next = (*pnp)->pn_next;
860 *pnp = pn;
863 class NullaryNode : public ParseNode {
864 public:
865 NullaryNode(ParseNodeKind kind, const TokenPos& pos) : ParseNode(kind, pos) {
866 MOZ_ASSERT(is<NullaryNode>());
869 static bool test(const ParseNode& node) {
870 return node.typeCode() == TypeCode::Nullary;
873 static constexpr TypeCode classTypeCode() { return TypeCode::Nullary; }
875 template <typename Visitor>
876 bool accept(Visitor& visitor) {
877 return true;
880 #ifdef DEBUG
881 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
882 int indent);
883 #endif
886 class NameNode : public ParseNode {
887 TaggedParserAtomIndex atom_; /* lexical name or label atom */
888 PrivateNameKind privateNameKind_ = PrivateNameKind::None;
890 public:
891 NameNode(ParseNodeKind kind, TaggedParserAtomIndex atom, const TokenPos& pos)
892 : ParseNode(kind, pos), atom_(atom) {
893 MOZ_ASSERT(atom);
894 MOZ_ASSERT(is<NameNode>());
897 static bool test(const ParseNode& node) {
898 return node.typeCode() == TypeCode::Name;
901 static constexpr TypeCode classTypeCode() { return TypeCode::Name; }
903 template <typename Visitor>
904 bool accept(Visitor& visitor) {
905 return true;
908 #ifdef DEBUG
909 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
910 int indent);
911 #endif
913 TaggedParserAtomIndex atom() const { return atom_; }
915 TaggedParserAtomIndex name() const {
916 MOZ_ASSERT(isKind(ParseNodeKind::Name) ||
917 isKind(ParseNodeKind::PrivateName));
918 return atom_;
921 void setAtom(TaggedParserAtomIndex atom) { atom_ = atom; }
923 void setPrivateNameKind(PrivateNameKind privateNameKind) {
924 privateNameKind_ = privateNameKind;
927 PrivateNameKind privateNameKind() { return privateNameKind_; }
930 inline bool ParseNode::isName(TaggedParserAtomIndex name) const {
931 return getKind() == ParseNodeKind::Name && as<NameNode>().name() == name;
934 class UnaryNode : public ParseNode {
935 ParseNode* kid_;
937 public:
938 UnaryNode(ParseNodeKind kind, const TokenPos& pos, ParseNode* kid)
939 : ParseNode(kind, pos), kid_(kid) {
940 MOZ_ASSERT(is<UnaryNode>());
943 static bool test(const ParseNode& node) {
944 return node.typeCode() == TypeCode::Unary;
947 static constexpr TypeCode classTypeCode() { return TypeCode::Unary; }
949 template <typename Visitor>
950 bool accept(Visitor& visitor) {
951 if (kid_) {
952 if (!visitor.visit(kid_)) {
953 return false;
956 return true;
959 #ifdef DEBUG
960 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
961 int indent);
962 #endif
964 ParseNode* kid() const { return kid_; }
967 * Non-null if this is a statement node which could be a member of a
968 * Directive Prologue: an expression statement consisting of a single
969 * string literal.
971 * This considers only the node and its children, not its context. After
972 * parsing, check the node's prologue flag to see if it is indeed part of
973 * a directive prologue.
975 * Note that a Directive Prologue can contain statements that cannot
976 * themselves be directives (string literals that include escape sequences
977 * or escaped newlines, say). This member function returns true for such
978 * nodes; we use it to determine the extent of the prologue.
980 TaggedParserAtomIndex isStringExprStatement() const {
981 if (isKind(ParseNodeKind::ExpressionStmt)) {
982 if (kid()->isKind(ParseNodeKind::StringExpr) && !kid()->isInParens()) {
983 return kid()->as<NameNode>().atom();
986 return TaggedParserAtomIndex::null();
989 // Methods used by FoldConstants.cpp.
990 ParseNode** unsafeKidReference() { return &kid_; }
992 void setSyntheticComputedName() { pn_synthetic_computed = true; }
993 bool isSyntheticComputedName() {
994 MOZ_ASSERT(isKind(ParseNodeKind::ComputedName));
995 return pn_synthetic_computed;
999 class BinaryNode : public ParseNode {
1000 ParseNode* left_;
1001 ParseNode* right_;
1003 public:
1004 BinaryNode(ParseNodeKind kind, const TokenPos& pos, ParseNode* left,
1005 ParseNode* right)
1006 : ParseNode(kind, pos), left_(left), right_(right) {
1007 MOZ_ASSERT(is<BinaryNode>());
1010 BinaryNode(ParseNodeKind kind, ParseNode* left, ParseNode* right)
1011 : ParseNode(kind, TokenPos::box(left->pn_pos, right->pn_pos)),
1012 left_(left),
1013 right_(right) {
1014 MOZ_ASSERT(is<BinaryNode>());
1017 static bool test(const ParseNode& node) {
1018 return node.typeCode() == TypeCode::Binary;
1021 static constexpr TypeCode classTypeCode() { return TypeCode::Binary; }
1023 template <typename Visitor>
1024 bool accept(Visitor& visitor) {
1025 if (left_) {
1026 if (!visitor.visit(left_)) {
1027 return false;
1030 if (right_) {
1031 if (!visitor.visit(right_)) {
1032 return false;
1035 return true;
1038 #ifdef DEBUG
1039 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1040 int indent);
1041 #endif
1043 ParseNode* left() const { return left_; }
1045 ParseNode* right() const { return right_; }
1047 // Methods used by FoldConstants.cpp.
1048 // callers are responsible for keeping the list consistent.
1049 ParseNode** unsafeLeftReference() { return &left_; }
1051 ParseNode** unsafeRightReference() { return &right_; }
1054 class AssignmentNode : public BinaryNode {
1055 public:
1056 AssignmentNode(ParseNodeKind kind, ParseNode* left, ParseNode* right)
1057 : BinaryNode(kind, TokenPos(left->pn_pos.begin, right->pn_pos.end), left,
1058 right) {
1059 MOZ_ASSERT(is<AssignmentNode>());
1062 static bool test(const ParseNode& node) {
1063 ParseNodeKind kind = node.getKind();
1064 bool match = ParseNodeKind::AssignmentStart <= kind &&
1065 kind <= ParseNodeKind::AssignmentLast;
1066 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1067 return match;
1071 class ForNode : public BinaryNode {
1072 unsigned iflags_; /* JSITER_* flags */
1074 public:
1075 ForNode(const TokenPos& pos, ParseNode* forHead, ParseNode* body,
1076 unsigned iflags)
1077 : BinaryNode(ParseNodeKind::ForStmt, pos, forHead, body),
1078 iflags_(iflags) {
1079 MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
1080 forHead->isKind(ParseNodeKind::ForOf) ||
1081 forHead->isKind(ParseNodeKind::ForHead));
1084 static bool test(const ParseNode& node) {
1085 bool match = node.isKind(ParseNodeKind::ForStmt);
1086 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1087 return match;
1090 TernaryNode* head() const { return &left()->as<TernaryNode>(); }
1092 ParseNode* body() const { return right(); }
1094 unsigned iflags() const { return iflags_; }
1097 class TernaryNode : public ParseNode {
1098 ParseNode* kid1_; /* condition, discriminant, etc. */
1099 ParseNode* kid2_; /* then-part, case list, etc. */
1100 ParseNode* kid3_; /* else-part, default case, etc. */
1102 public:
1103 TernaryNode(ParseNodeKind kind, ParseNode* kid1, ParseNode* kid2,
1104 ParseNode* kid3)
1105 : TernaryNode(kind, kid1, kid2, kid3,
1106 TokenPos((kid1 ? kid1
1107 : kid2 ? kid2
1108 : kid3)
1109 ->pn_pos.begin,
1110 (kid3 ? kid3
1111 : kid2 ? kid2
1112 : kid1)
1113 ->pn_pos.end)) {}
1115 TernaryNode(ParseNodeKind kind, ParseNode* kid1, ParseNode* kid2,
1116 ParseNode* kid3, const TokenPos& pos)
1117 : ParseNode(kind, pos), kid1_(kid1), kid2_(kid2), kid3_(kid3) {
1118 MOZ_ASSERT(is<TernaryNode>());
1121 static bool test(const ParseNode& node) {
1122 return node.typeCode() == TypeCode::Ternary;
1125 static constexpr TypeCode classTypeCode() { return TypeCode::Ternary; }
1127 template <typename Visitor>
1128 bool accept(Visitor& visitor) {
1129 if (kid1_) {
1130 if (!visitor.visit(kid1_)) {
1131 return false;
1134 if (kid2_) {
1135 if (!visitor.visit(kid2_)) {
1136 return false;
1139 if (kid3_) {
1140 if (!visitor.visit(kid3_)) {
1141 return false;
1144 return true;
1147 #ifdef DEBUG
1148 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1149 int indent);
1150 #endif
1152 ParseNode* kid1() const { return kid1_; }
1154 ParseNode* kid2() const { return kid2_; }
1156 ParseNode* kid3() const { return kid3_; }
1158 // Methods used by FoldConstants.cpp.
1159 ParseNode** unsafeKid1Reference() { return &kid1_; }
1161 ParseNode** unsafeKid2Reference() { return &kid2_; }
1163 ParseNode** unsafeKid3Reference() { return &kid3_; }
1166 class ListNode : public ParseNode {
1167 ParseNode* head_; /* first node in list */
1168 ParseNode** tail_; /* ptr to last node's pn_next in list */
1169 uint32_t count_; /* number of nodes in list */
1170 uint32_t xflags;
1172 private:
1173 // xflags bits.
1175 // Statement list has top-level function statements.
1176 static constexpr uint32_t hasTopLevelFunctionDeclarationsBit = Bit(0);
1178 // Array/Object/Class initializer has non-constants.
1179 // * array has holes
1180 // * array has spread node
1181 // * array has element which is known not to be constant
1182 // * array has no element
1183 // * object/class has __proto__
1184 // * object/class has property which is known not to be constant
1185 // * object/class shorthand property
1186 // * object/class spread property
1187 // * object/class has method
1188 // * object/class has computed property
1189 static constexpr uint32_t hasNonConstInitializerBit = Bit(1);
1191 // Flag set by the emitter after emitting top-level function statements.
1192 static constexpr uint32_t emittedTopLevelFunctionDeclarationsBit = Bit(2);
1194 public:
1195 ListNode(ParseNodeKind kind, const TokenPos& pos)
1196 : ParseNode(kind, pos),
1197 head_(nullptr),
1198 tail_(&head_),
1199 count_(0),
1200 xflags(0) {
1201 MOZ_ASSERT(is<ListNode>());
1204 ListNode(ParseNodeKind kind, ParseNode* kid)
1205 : ParseNode(kind, kid->pn_pos),
1206 head_(kid),
1207 tail_(&kid->pn_next),
1208 count_(1),
1209 xflags(0) {
1210 if (kid->pn_pos.begin < pn_pos.begin) {
1211 pn_pos.begin = kid->pn_pos.begin;
1213 pn_pos.end = kid->pn_pos.end;
1215 MOZ_ASSERT(is<ListNode>());
1218 static bool test(const ParseNode& node) {
1219 return node.typeCode() == TypeCode::List;
1222 static constexpr TypeCode classTypeCode() { return TypeCode::List; }
1224 template <typename Visitor>
1225 bool accept(Visitor& visitor) {
1226 ParseNode** listp = &head_;
1227 for (; *listp; listp = &(*listp)->pn_next) {
1228 // Don't use reference because we want to check if it changed, so we can
1229 // use ReplaceNode
1230 ParseNode* pn = *listp;
1231 if (!visitor.visit(pn)) {
1232 return false;
1234 if (pn != *listp) {
1235 ReplaceNode(listp, pn);
1238 unsafeReplaceTail(listp);
1239 return true;
1242 #ifdef DEBUG
1243 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1244 int indent);
1245 #endif
1247 ParseNode* head() const { return head_; }
1249 ParseNode** tail() const { return tail_; }
1251 uint32_t count() const { return count_; }
1253 bool empty() const { return count() == 0; }
1255 void checkConsistency() const
1256 #ifndef DEBUG
1258 #endif
1261 [[nodiscard]] bool hasTopLevelFunctionDeclarations() const {
1262 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1263 return xflags & hasTopLevelFunctionDeclarationsBit;
1266 [[nodiscard]] bool emittedTopLevelFunctionDeclarations() const {
1267 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1268 MOZ_ASSERT(hasTopLevelFunctionDeclarations());
1269 return xflags & emittedTopLevelFunctionDeclarationsBit;
1272 [[nodiscard]] bool hasNonConstInitializer() const {
1273 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1274 isKind(ParseNodeKind::ObjectExpr));
1275 return xflags & hasNonConstInitializerBit;
1278 void setHasTopLevelFunctionDeclarations() {
1279 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1280 xflags |= hasTopLevelFunctionDeclarationsBit;
1283 void setEmittedTopLevelFunctionDeclarations() {
1284 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1285 MOZ_ASSERT(hasTopLevelFunctionDeclarations());
1286 xflags |= emittedTopLevelFunctionDeclarationsBit;
1289 void setHasNonConstInitializer() {
1290 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1291 isKind(ParseNodeKind::ObjectExpr) ||
1292 IF_RECORD_TUPLE(isKind(ParseNodeKind::TupleExpr), false) ||
1293 IF_RECORD_TUPLE(isKind(ParseNodeKind::RecordExpr), false));
1294 xflags |= hasNonConstInitializerBit;
1297 void unsetHasNonConstInitializer() {
1298 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1299 isKind(ParseNodeKind::ObjectExpr) ||
1300 IF_RECORD_TUPLE(isKind(ParseNodeKind::TupleExpr), false) ||
1301 IF_RECORD_TUPLE(isKind(ParseNodeKind::RecordExpr), false));
1302 xflags &= ~hasNonConstInitializerBit;
1306 * Compute a pointer to the last element in a singly-linked list. NB: list
1307 * must be non-empty -- this is asserted!
1309 ParseNode* last() const {
1310 MOZ_ASSERT(!empty());
1312 // ParseNode ParseNode
1313 // +-----+---------+-----+ +-----+---------+-----+
1314 // | ... | pn_next | ... | +-...->| ... | pn_next | ... |
1315 // +-----+---------+-----+ | +-----+---------+-----+
1316 // ^ | | ^ ^
1317 // | +---------------+ | |
1318 // | | tail()
1319 // | |
1320 // head() last()
1322 return (ParseNode*)(uintptr_t(tail()) - offsetof(ParseNode, pn_next));
1325 void replaceLast(ParseNode* node) {
1326 MOZ_ASSERT(!empty());
1327 pn_pos.end = node->pn_pos.end;
1329 ParseNode* item = head();
1330 ParseNode* lastNode = last();
1331 MOZ_ASSERT(item);
1332 if (item == lastNode) {
1333 head_ = node;
1334 } else {
1335 while (item->pn_next != lastNode) {
1336 MOZ_ASSERT(item->pn_next);
1337 item = item->pn_next;
1339 item->pn_next = node;
1341 tail_ = &node->pn_next;
1344 void append(ParseNode* item) {
1345 MOZ_ASSERT(item->pn_pos.begin >= pn_pos.begin);
1346 pn_pos.end = item->pn_pos.end;
1347 *tail_ = item;
1348 tail_ = &item->pn_next;
1349 count_++;
1352 void prepend(ParseNode* item) {
1353 item->pn_next = head_;
1354 head_ = item;
1355 if (tail_ == &head_) {
1356 tail_ = &item->pn_next;
1358 count_++;
1361 // Methods used by FoldConstants.cpp.
1362 // Caller is responsible for keeping the list consistent.
1363 ParseNode** unsafeHeadReference() { return &head_; }
1365 void unsafeReplaceTail(ParseNode** newTail) {
1366 tail_ = newTail;
1367 checkConsistency();
1370 void unsafeDecrementCount() {
1371 MOZ_ASSERT(count() > 1);
1372 count_--;
1375 private:
1376 // Classes to iterate over ListNode contents:
1378 // Usage:
1379 // ListNode* list;
1380 // for (ParseNode* item : list->contents()) {
1381 // // item is ParseNode* typed.
1382 // }
1383 class iterator {
1384 private:
1385 ParseNode* node_;
1387 friend class ListNode;
1388 explicit iterator(ParseNode* node) : node_(node) {}
1390 public:
1391 // Implement std::iterator_traits.
1392 using iterator_category = std::input_iterator_tag;
1393 using value_type = ParseNode*;
1394 using difference_type = ptrdiff_t;
1395 using pointer = ParseNode**;
1396 using reference = ParseNode*&;
1398 bool operator==(const iterator& other) const {
1399 return node_ == other.node_;
1402 bool operator!=(const iterator& other) const { return !(*this == other); }
1404 iterator& operator++() {
1405 node_ = node_->pn_next;
1406 return *this;
1409 ParseNode* operator*() { return node_; }
1411 const ParseNode* operator*() const { return node_; }
1414 class range {
1415 private:
1416 ParseNode* begin_;
1417 ParseNode* end_;
1419 friend class ListNode;
1420 range(ParseNode* begin, ParseNode* end) : begin_(begin), end_(end) {}
1422 public:
1423 iterator begin() { return iterator(begin_); }
1425 iterator end() { return iterator(end_); }
1427 const iterator begin() const { return iterator(begin_); }
1429 const iterator end() const { return iterator(end_); }
1431 const iterator cbegin() const { return begin(); }
1433 const iterator cend() const { return end(); }
1436 #ifdef DEBUG
1437 [[nodiscard]] bool contains(ParseNode* target) const {
1438 MOZ_ASSERT(target);
1439 for (ParseNode* node : contents()) {
1440 if (target == node) {
1441 return true;
1444 return false;
1446 #endif
1448 public:
1449 range contents() { return range(head(), nullptr); }
1451 const range contents() const { return range(head(), nullptr); }
1453 range contentsFrom(ParseNode* begin) {
1454 MOZ_ASSERT_IF(begin, contains(begin));
1455 return range(begin, nullptr);
1458 const range contentsFrom(ParseNode* begin) const {
1459 MOZ_ASSERT_IF(begin, contains(begin));
1460 return range(begin, nullptr);
1463 range contentsTo(ParseNode* end) {
1464 MOZ_ASSERT_IF(end, contains(end));
1465 return range(head(), end);
1468 const range contentsTo(ParseNode* end) const {
1469 MOZ_ASSERT_IF(end, contains(end));
1470 return range(head(), end);
1474 class DeclarationListNode : public ListNode {
1475 public:
1476 DeclarationListNode(ParseNodeKind kind, const TokenPos& pos)
1477 : ListNode(kind, pos) {
1478 MOZ_ASSERT(is<DeclarationListNode>());
1481 static bool test(const ParseNode& node) {
1482 bool match = node.isKind(ParseNodeKind::VarStmt) ||
1483 node.isKind(ParseNodeKind::LetDecl) ||
1484 node.isKind(ParseNodeKind::ConstDecl);
1485 MOZ_ASSERT_IF(match, node.is<ListNode>());
1486 return match;
1489 auto* singleBinding() const {
1490 MOZ_ASSERT(count() == 1);
1491 return head();
1495 class ParamsBodyNode : public ListNode {
1496 public:
1497 explicit ParamsBodyNode(const TokenPos& pos)
1498 : ListNode(ParseNodeKind::ParamsBody, pos) {
1499 MOZ_ASSERT(is<ParamsBodyNode>());
1502 static bool test(const ParseNode& node) {
1503 bool match = node.isKind(ParseNodeKind::ParamsBody);
1504 MOZ_ASSERT_IF(match, node.is<ListNode>());
1505 return match;
1508 auto parameters() const {
1509 MOZ_ASSERT(last()->is<LexicalScopeNode>());
1510 return contentsTo(last());
1513 auto* body() const {
1514 MOZ_ASSERT(last()->is<LexicalScopeNode>());
1515 return &last()->as<LexicalScopeNode>();
1519 class FunctionNode : public ParseNode {
1520 FunctionBox* funbox_;
1521 ParseNode* body_;
1522 FunctionSyntaxKind syntaxKind_;
1524 public:
1525 FunctionNode(FunctionSyntaxKind syntaxKind, const TokenPos& pos)
1526 : ParseNode(ParseNodeKind::Function, pos),
1527 funbox_(nullptr),
1528 body_(nullptr),
1529 syntaxKind_(syntaxKind) {
1530 MOZ_ASSERT(!body_);
1531 MOZ_ASSERT(!funbox_);
1532 MOZ_ASSERT(is<FunctionNode>());
1535 static bool test(const ParseNode& node) {
1536 return node.isKind(ParseNodeKind::Function);
1539 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1541 template <typename Visitor>
1542 bool accept(Visitor& visitor) {
1543 // Note: body is null for lazily-parsed functions.
1544 if (body_) {
1545 if (!visitor.visit(body_)) {
1546 return false;
1548 MOZ_ASSERT(body_->is<ParamsBodyNode>());
1550 return true;
1553 #ifdef DEBUG
1554 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1555 int indent);
1556 #endif
1558 FunctionBox* funbox() const { return funbox_; }
1560 ParamsBodyNode* body() const {
1561 return body_ ? &body_->as<ParamsBodyNode>() : nullptr;
1564 void setFunbox(FunctionBox* funbox) { funbox_ = funbox; }
1566 void setBody(ParamsBodyNode* body) { body_ = body; }
1568 FunctionSyntaxKind syntaxKind() const { return syntaxKind_; }
1570 bool functionIsHoisted() const {
1571 return syntaxKind() == FunctionSyntaxKind::Statement;
1575 class ModuleNode : public ParseNode {
1576 ParseNode* body_;
1578 public:
1579 explicit ModuleNode(const TokenPos& pos)
1580 : ParseNode(ParseNodeKind::Module, pos), body_(nullptr) {
1581 MOZ_ASSERT(!body_);
1582 MOZ_ASSERT(is<ModuleNode>());
1585 static bool test(const ParseNode& node) {
1586 return node.isKind(ParseNodeKind::Module);
1589 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1591 template <typename Visitor>
1592 bool accept(Visitor& visitor) {
1593 return visitor.visit(body_);
1596 #ifdef DEBUG
1597 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1598 int indent);
1599 #endif
1601 ListNode* body() const { return &body_->as<ListNode>(); }
1603 void setBody(ListNode* body) { body_ = body; }
1606 class NumericLiteral : public ParseNode {
1607 double value_; /* aligned numeric literal value */
1608 DecimalPoint decimalPoint_; /* Whether the number has a decimal point */
1610 public:
1611 NumericLiteral(double value, DecimalPoint decimalPoint, const TokenPos& pos)
1612 : ParseNode(ParseNodeKind::NumberExpr, pos),
1613 value_(value),
1614 decimalPoint_(decimalPoint) {}
1616 static bool test(const ParseNode& node) {
1617 return node.isKind(ParseNodeKind::NumberExpr);
1620 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1622 template <typename Visitor>
1623 bool accept(Visitor& visitor) {
1624 return true;
1627 #ifdef DEBUG
1628 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1629 int indent);
1630 #endif
1632 double value() const { return value_; }
1634 DecimalPoint decimalPoint() const { return decimalPoint_; }
1636 // Return the decimal string representation of this numeric literal.
1637 TaggedParserAtomIndex toAtom(FrontendContext* fc,
1638 ParserAtomsTable& parserAtoms) const;
1641 class BigIntLiteral : public ParseNode {
1642 BigIntIndex index_;
1643 bool isZero_;
1645 public:
1646 BigIntLiteral(BigIntIndex index, bool isZero, const TokenPos& pos)
1647 : ParseNode(ParseNodeKind::BigIntExpr, pos),
1648 index_(index),
1649 isZero_(isZero) {}
1651 static bool test(const ParseNode& node) {
1652 return node.isKind(ParseNodeKind::BigIntExpr);
1655 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1657 template <typename Visitor>
1658 bool accept(Visitor& visitor) {
1659 return true;
1662 #ifdef DEBUG
1663 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1664 int indent);
1665 #endif
1667 BigIntIndex index() { return index_; }
1669 bool isZero() const { return isZero_; }
1672 template <ParseNodeKind NodeKind, typename ScopeType>
1673 class BaseScopeNode : public ParseNode {
1674 using ParserData = typename ScopeType::ParserData;
1675 ParserData* bindings;
1676 ParseNode* body;
1677 ScopeKind kind_;
1679 public:
1680 BaseScopeNode(ParserData* bindings, ParseNode* body,
1681 ScopeKind kind = ScopeKind::Lexical)
1682 : ParseNode(NodeKind, body->pn_pos),
1683 bindings(bindings),
1684 body(body),
1685 kind_(kind) {}
1687 static bool test(const ParseNode& node) { return node.isKind(NodeKind); }
1689 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1691 template <typename Visitor>
1692 bool accept(Visitor& visitor) {
1693 return visitor.visit(body);
1696 #ifdef DEBUG
1697 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1698 int indent);
1699 #endif
1701 ParserData* scopeBindings() const {
1702 MOZ_ASSERT(!isEmptyScope());
1703 return bindings;
1706 ParseNode* scopeBody() const { return body; }
1708 void setScopeBody(ParseNode* body) { this->body = body; }
1710 bool isEmptyScope() const { return !bindings; }
1712 ScopeKind kind() const { return kind_; }
1715 class LexicalScopeNode
1716 : public BaseScopeNode<ParseNodeKind::LexicalScope, LexicalScope> {
1717 public:
1718 LexicalScopeNode(LexicalScope::ParserData* bindings, ParseNode* body,
1719 ScopeKind kind = ScopeKind::Lexical)
1720 : BaseScopeNode(bindings, body, kind) {}
1723 class ClassBodyScopeNode
1724 : public BaseScopeNode<ParseNodeKind::ClassBodyScope, ClassBodyScope> {
1725 public:
1726 ClassBodyScopeNode(ClassBodyScope::ParserData* bindings, ListNode* memberList)
1727 : BaseScopeNode(bindings, memberList, ScopeKind::ClassBody) {
1728 MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
1731 ListNode* memberList() const {
1732 ListNode* list = &scopeBody()->as<ListNode>();
1733 MOZ_ASSERT(list->isKind(ParseNodeKind::ClassMemberList));
1734 return list;
1738 class LabeledStatement : public NameNode {
1739 ParseNode* statement_;
1741 public:
1742 LabeledStatement(TaggedParserAtomIndex label, ParseNode* stmt, uint32_t begin)
1743 : NameNode(ParseNodeKind::LabelStmt, label,
1744 TokenPos(begin, stmt->pn_pos.end)),
1745 statement_(stmt) {}
1747 TaggedParserAtomIndex label() const { return atom(); }
1749 ParseNode* statement() const { return statement_; }
1751 static bool test(const ParseNode& node) {
1752 return node.isKind(ParseNodeKind::LabelStmt);
1755 template <typename Visitor>
1756 bool accept(Visitor& visitor) {
1757 if (statement_) {
1758 if (!visitor.visit(statement_)) {
1759 return false;
1762 return true;
1765 #ifdef DEBUG
1766 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1767 int indent);
1768 #endif
1771 // Inside a switch statement, a CaseClause is a case-label and the subsequent
1772 // statements. The same node type is used for DefaultClauses. The only
1773 // difference is that their caseExpression() is null.
1774 class CaseClause : public BinaryNode {
1775 public:
1776 CaseClause(ParseNode* expr, ParseNode* stmts, uint32_t begin)
1777 : BinaryNode(ParseNodeKind::Case, TokenPos(begin, stmts->pn_pos.end),
1778 expr, stmts) {}
1780 ParseNode* caseExpression() const { return left(); }
1782 bool isDefault() const { return !caseExpression(); }
1784 ListNode* statementList() const { return &right()->as<ListNode>(); }
1786 static bool test(const ParseNode& node) {
1787 bool match = node.isKind(ParseNodeKind::Case);
1788 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1789 return match;
1793 class LoopControlStatement : public ParseNode {
1794 TaggedParserAtomIndex label_; /* target of break/continue statement */
1796 protected:
1797 LoopControlStatement(ParseNodeKind kind, TaggedParserAtomIndex label,
1798 const TokenPos& pos)
1799 : ParseNode(kind, pos), label_(label) {
1800 MOZ_ASSERT(kind == ParseNodeKind::BreakStmt ||
1801 kind == ParseNodeKind::ContinueStmt);
1802 MOZ_ASSERT(is<LoopControlStatement>());
1805 public:
1806 /* Label associated with this break/continue statement, if any. */
1807 TaggedParserAtomIndex label() const { return label_; }
1809 #ifdef DEBUG
1810 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1811 int indent);
1812 #endif
1814 static bool test(const ParseNode& node) {
1815 return node.isKind(ParseNodeKind::BreakStmt) ||
1816 node.isKind(ParseNodeKind::ContinueStmt);
1819 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1821 template <typename Visitor>
1822 bool accept(Visitor& visitor) {
1823 return true;
1827 class BreakStatement : public LoopControlStatement {
1828 public:
1829 BreakStatement(TaggedParserAtomIndex label, const TokenPos& pos)
1830 : LoopControlStatement(ParseNodeKind::BreakStmt, label, pos) {}
1832 static bool test(const ParseNode& node) {
1833 bool match = node.isKind(ParseNodeKind::BreakStmt);
1834 MOZ_ASSERT_IF(match, node.is<LoopControlStatement>());
1835 return match;
1839 class ContinueStatement : public LoopControlStatement {
1840 public:
1841 ContinueStatement(TaggedParserAtomIndex label, const TokenPos& pos)
1842 : LoopControlStatement(ParseNodeKind::ContinueStmt, label, pos) {}
1844 static bool test(const ParseNode& node) {
1845 bool match = node.isKind(ParseNodeKind::ContinueStmt);
1846 MOZ_ASSERT_IF(match, node.is<LoopControlStatement>());
1847 return match;
1851 class DebuggerStatement : public NullaryNode {
1852 public:
1853 explicit DebuggerStatement(const TokenPos& pos)
1854 : NullaryNode(ParseNodeKind::DebuggerStmt, pos) {}
1856 static bool test(const ParseNode& node) {
1857 bool match = node.isKind(ParseNodeKind::DebuggerStmt);
1858 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1859 return match;
1863 class ConditionalExpression : public TernaryNode {
1864 public:
1865 ConditionalExpression(ParseNode* condition, ParseNode* thenExpr,
1866 ParseNode* elseExpr)
1867 : TernaryNode(ParseNodeKind::ConditionalExpr, condition, thenExpr,
1868 elseExpr,
1869 TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end)) {
1870 MOZ_ASSERT(condition);
1871 MOZ_ASSERT(thenExpr);
1872 MOZ_ASSERT(elseExpr);
1875 ParseNode& condition() const { return *kid1(); }
1877 ParseNode& thenExpression() const { return *kid2(); }
1879 ParseNode& elseExpression() const { return *kid3(); }
1881 static bool test(const ParseNode& node) {
1882 bool match = node.isKind(ParseNodeKind::ConditionalExpr);
1883 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
1884 return match;
1888 class TryNode : public TernaryNode {
1889 public:
1890 TryNode(uint32_t begin, ParseNode* body, LexicalScopeNode* catchScope,
1891 ParseNode* finallyBlock)
1892 : TernaryNode(
1893 ParseNodeKind::TryStmt, body, catchScope, finallyBlock,
1894 TokenPos(begin,
1895 (finallyBlock ? finallyBlock : catchScope)->pn_pos.end)) {
1896 MOZ_ASSERT(body);
1897 MOZ_ASSERT(catchScope || finallyBlock);
1900 static bool test(const ParseNode& node) {
1901 bool match = node.isKind(ParseNodeKind::TryStmt);
1902 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
1903 return match;
1906 ParseNode* body() const { return kid1(); }
1908 LexicalScopeNode* catchScope() const {
1909 return kid2() ? &kid2()->as<LexicalScopeNode>() : nullptr;
1912 ParseNode* finallyBlock() const { return kid3(); }
1915 class ThisLiteral : public UnaryNode {
1916 public:
1917 ThisLiteral(const TokenPos& pos, ParseNode* thisName)
1918 : UnaryNode(ParseNodeKind::ThisExpr, pos, thisName) {}
1920 static bool test(const ParseNode& node) {
1921 bool match = node.isKind(ParseNodeKind::ThisExpr);
1922 MOZ_ASSERT_IF(match, node.is<UnaryNode>());
1923 return match;
1927 class NullLiteral : public NullaryNode {
1928 public:
1929 explicit NullLiteral(const TokenPos& pos)
1930 : NullaryNode(ParseNodeKind::NullExpr, pos) {}
1932 static bool test(const ParseNode& node) {
1933 bool match = node.isKind(ParseNodeKind::NullExpr);
1934 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1935 return match;
1939 // This is only used internally, currently just for tagged templates and the
1940 // initial value of fields without initializers. It represents the value
1941 // 'undefined' (aka `void 0`), like NullLiteral represents the value 'null'.
1942 class RawUndefinedLiteral : public NullaryNode {
1943 public:
1944 explicit RawUndefinedLiteral(const TokenPos& pos)
1945 : NullaryNode(ParseNodeKind::RawUndefinedExpr, pos) {}
1947 static bool test(const ParseNode& node) {
1948 bool match = node.isKind(ParseNodeKind::RawUndefinedExpr);
1949 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1950 return match;
1954 class BooleanLiteral : public NullaryNode {
1955 public:
1956 BooleanLiteral(bool b, const TokenPos& pos)
1957 : NullaryNode(b ? ParseNodeKind::TrueExpr : ParseNodeKind::FalseExpr,
1958 pos) {}
1960 static bool test(const ParseNode& node) {
1961 bool match = node.isKind(ParseNodeKind::TrueExpr) ||
1962 node.isKind(ParseNodeKind::FalseExpr);
1963 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1964 return match;
1968 class RegExpLiteral : public ParseNode {
1969 RegExpIndex index_;
1971 public:
1972 RegExpLiteral(RegExpIndex dataIndex, const TokenPos& pos)
1973 : ParseNode(ParseNodeKind::RegExpExpr, pos), index_(dataIndex) {}
1975 // Create a RegExp object of this RegExp literal.
1976 RegExpObject* create(JSContext* cx, FrontendContext* fc,
1977 ParserAtomsTable& parserAtoms,
1978 CompilationAtomCache& atomCache,
1979 ExtensibleCompilationStencil& stencil) const;
1981 #ifdef DEBUG
1982 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
1983 int indent);
1984 #endif
1986 static bool test(const ParseNode& node) {
1987 return node.isKind(ParseNodeKind::RegExpExpr);
1990 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1992 template <typename Visitor>
1993 bool accept(Visitor& visitor) {
1994 return true;
1997 RegExpIndex index() { return index_; }
2000 class PropertyAccessBase : public BinaryNode {
2001 public:
2003 * PropertyAccess nodes can have any expression/'super' as left-hand
2004 * side, but the name must be a ParseNodeKind::PropertyName node.
2006 PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, NameNode* name,
2007 uint32_t begin, uint32_t end)
2008 : BinaryNode(kind, TokenPos(begin, end), lhs, name) {
2009 MOZ_ASSERT(lhs);
2010 MOZ_ASSERT(name);
2013 ParseNode& expression() const { return *left(); }
2015 static bool test(const ParseNode& node) {
2016 bool match = node.isKind(ParseNodeKind::DotExpr) ||
2017 node.isKind(ParseNodeKind::OptionalDotExpr);
2018 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2019 MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
2020 ParseNodeKind::PropertyNameExpr));
2021 return match;
2024 NameNode& key() const { return right()->as<NameNode>(); }
2026 // Method used by BytecodeEmitter::emitPropLHS for optimization.
2027 // Those methods allow expression to temporarily be nullptr for
2028 // optimization purpose.
2029 ParseNode* maybeExpression() const { return left(); }
2031 void setExpression(ParseNode* pn) { *unsafeLeftReference() = pn; }
2033 TaggedParserAtomIndex name() const { return right()->as<NameNode>().atom(); }
2036 class PropertyAccess : public PropertyAccessBase {
2037 public:
2038 PropertyAccess(ParseNode* lhs, NameNode* name, uint32_t begin, uint32_t end)
2039 : PropertyAccessBase(ParseNodeKind::DotExpr, lhs, name, begin, end) {
2040 MOZ_ASSERT(lhs);
2041 MOZ_ASSERT(name);
2044 static bool test(const ParseNode& node) {
2045 bool match = node.isKind(ParseNodeKind::DotExpr);
2046 MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
2047 return match;
2050 bool isSuper() const {
2051 // ParseNodeKind::SuperBase cannot result from any expression syntax.
2052 return expression().isKind(ParseNodeKind::SuperBase);
2056 class OptionalPropertyAccess : public PropertyAccessBase {
2057 public:
2058 OptionalPropertyAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2059 uint32_t end)
2060 : PropertyAccessBase(ParseNodeKind::OptionalDotExpr, lhs, name, begin,
2061 end) {
2062 MOZ_ASSERT(lhs);
2063 MOZ_ASSERT(name);
2066 static bool test(const ParseNode& node) {
2067 bool match = node.isKind(ParseNodeKind::OptionalDotExpr);
2068 MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
2069 return match;
2073 class PropertyByValueBase : public BinaryNode {
2074 public:
2075 PropertyByValueBase(ParseNodeKind kind, ParseNode* lhs, ParseNode* propExpr,
2076 uint32_t begin, uint32_t end)
2077 : BinaryNode(kind, TokenPos(begin, end), lhs, propExpr) {}
2079 static bool test(const ParseNode& node) {
2080 bool match = node.isKind(ParseNodeKind::ElemExpr) ||
2081 node.isKind(ParseNodeKind::OptionalElemExpr);
2082 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2083 return match;
2086 ParseNode& expression() const { return *left(); }
2088 ParseNode& key() const { return *right(); }
2091 class PropertyByValue : public PropertyByValueBase {
2092 public:
2093 PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin,
2094 uint32_t end)
2095 : PropertyByValueBase(ParseNodeKind::ElemExpr, lhs, propExpr, begin,
2096 end) {}
2098 static bool test(const ParseNode& node) {
2099 bool match = node.isKind(ParseNodeKind::ElemExpr);
2100 MOZ_ASSERT_IF(match, node.is<PropertyByValueBase>());
2101 return match;
2104 bool isSuper() const { return left()->isKind(ParseNodeKind::SuperBase); }
2107 class OptionalPropertyByValue : public PropertyByValueBase {
2108 public:
2109 OptionalPropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin,
2110 uint32_t end)
2111 : PropertyByValueBase(ParseNodeKind::OptionalElemExpr, lhs, propExpr,
2112 begin, end) {}
2114 static bool test(const ParseNode& node) {
2115 bool match = node.isKind(ParseNodeKind::OptionalElemExpr);
2116 MOZ_ASSERT_IF(match, node.is<PropertyByValueBase>());
2117 return match;
2121 class PrivateMemberAccessBase : public BinaryNode {
2122 public:
2123 PrivateMemberAccessBase(ParseNodeKind kind, ParseNode* lhs, NameNode* name,
2124 uint32_t begin, uint32_t end)
2125 : BinaryNode(kind, TokenPos(begin, end), lhs, name) {
2126 MOZ_ASSERT(name->isKind(ParseNodeKind::PrivateName));
2129 ParseNode& expression() const { return *left(); }
2131 NameNode& privateName() const {
2132 NameNode& name = right()->as<NameNode>();
2133 MOZ_ASSERT(name.isKind(ParseNodeKind::PrivateName));
2134 return name;
2137 static bool test(const ParseNode& node) {
2138 bool match = node.isKind(ParseNodeKind::PrivateMemberExpr) ||
2139 node.isKind(ParseNodeKind::OptionalPrivateMemberExpr);
2140 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2141 MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
2142 ParseNodeKind::PrivateName));
2143 return match;
2147 class PrivateMemberAccess : public PrivateMemberAccessBase {
2148 public:
2149 PrivateMemberAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2150 uint32_t end)
2151 : PrivateMemberAccessBase(ParseNodeKind::PrivateMemberExpr, lhs, name,
2152 begin, end) {}
2154 static bool test(const ParseNode& node) {
2155 return node.isKind(ParseNodeKind::PrivateMemberExpr);
2159 class OptionalPrivateMemberAccess : public PrivateMemberAccessBase {
2160 public:
2161 OptionalPrivateMemberAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2162 uint32_t end)
2163 : PrivateMemberAccessBase(ParseNodeKind::OptionalPrivateMemberExpr, lhs,
2164 name, begin, end) {}
2166 static bool test(const ParseNode& node) {
2167 return node.isKind(ParseNodeKind::OptionalPrivateMemberExpr);
2171 class NewTargetNode : public TernaryNode {
2172 public:
2173 NewTargetNode(NullaryNode* newHolder, NullaryNode* targetHolder,
2174 NameNode* newTargetName)
2175 : TernaryNode(ParseNodeKind::NewTargetExpr, newHolder, targetHolder,
2176 newTargetName) {}
2178 static bool test(const ParseNode& node) {
2179 bool match = node.isKind(ParseNodeKind::NewTargetExpr);
2180 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
2181 return match;
2184 auto* newHolder() const { return &kid1()->as<NullaryNode>(); }
2185 auto* targetHolder() const { return &kid2()->as<NullaryNode>(); }
2186 auto* newTargetName() const { return &kid3()->as<NameNode>(); }
2190 * A CallSiteNode represents the implicit call site object argument in a
2191 * TaggedTemplate.
2193 class CallSiteNode : public ListNode {
2194 public:
2195 explicit CallSiteNode(uint32_t begin)
2196 : ListNode(ParseNodeKind::CallSiteObj, TokenPos(begin, begin + 1)) {}
2198 static bool test(const ParseNode& node) {
2199 bool match = node.isKind(ParseNodeKind::CallSiteObj);
2200 MOZ_ASSERT_IF(match, node.is<ListNode>());
2201 return match;
2204 ListNode* rawNodes() const {
2205 MOZ_ASSERT(head());
2206 return &head()->as<ListNode>();
2210 class CallNode : public BinaryNode {
2211 const JSOp callOp_;
2213 public:
2214 CallNode(ParseNodeKind kind, JSOp callOp, ParseNode* left, ListNode* right)
2215 : CallNode(kind, callOp, TokenPos(left->pn_pos.begin, right->pn_pos.end),
2216 left, right) {}
2218 CallNode(ParseNodeKind kind, JSOp callOp, TokenPos pos, ParseNode* left,
2219 ListNode* right)
2220 : BinaryNode(kind, pos, left, right), callOp_(callOp) {
2221 MOZ_ASSERT(is<CallNode>());
2224 static bool test(const ParseNode& node) {
2225 bool match = node.isKind(ParseNodeKind::CallExpr) ||
2226 node.isKind(ParseNodeKind::SuperCallExpr) ||
2227 node.isKind(ParseNodeKind::OptionalCallExpr) ||
2228 node.isKind(ParseNodeKind::TaggedTemplateExpr) ||
2229 node.isKind(ParseNodeKind::NewExpr);
2230 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2231 return match;
2234 JSOp callOp() const { return callOp_; }
2235 auto* callee() const { return left(); }
2236 auto* args() const { return &right()->as<ListNode>(); }
2239 class ClassMethod : public BinaryNode {
2240 using Base = BinaryNode;
2242 bool isStatic_;
2243 AccessorType accessorType_;
2244 FunctionNode* initializerIfPrivate_;
2246 #ifdef ENABLE_DECORATORS
2247 ListNode* decorators_;
2248 #endif
2250 public:
2252 * Method definitions often keep a name and function body that overlap,
2253 * so explicitly define the beginning and end here.
2255 ClassMethod(ParseNodeKind kind, ParseNode* name, ParseNode* body,
2256 AccessorType accessorType, bool isStatic,
2257 FunctionNode* initializerIfPrivate
2258 #ifdef ENABLE_DECORATORS
2260 ListNode* decorators
2261 #endif
2263 : BinaryNode(kind, TokenPos(name->pn_pos.begin, body->pn_pos.end), name,
2264 body),
2265 isStatic_(isStatic),
2266 accessorType_(accessorType),
2267 initializerIfPrivate_(initializerIfPrivate)
2268 #ifdef ENABLE_DECORATORS
2270 decorators_(decorators)
2271 #endif
2273 MOZ_ASSERT(kind == ParseNodeKind::DefaultConstructor ||
2274 kind == ParseNodeKind::ClassMethod);
2277 static bool test(const ParseNode& node) {
2278 bool match = node.isKind(ParseNodeKind::DefaultConstructor) ||
2279 node.isKind(ParseNodeKind::ClassMethod);
2280 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2281 return match;
2284 ParseNode& name() const { return *left(); }
2286 FunctionNode& method() const { return right()->as<FunctionNode>(); }
2288 bool isStatic() const { return isStatic_; }
2290 AccessorType accessorType() const { return accessorType_; }
2292 FunctionNode* initializerIfPrivate() const { return initializerIfPrivate_; }
2294 #ifdef ENABLE_DECORATORS
2295 ListNode* decorators() const { return decorators_; }
2297 # ifdef DEBUG
2298 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
2299 int indent);
2300 # endif
2301 #endif
2304 class ClassField : public BinaryNode {
2305 using Base = BinaryNode;
2307 bool isStatic_;
2308 #ifdef ENABLE_DECORATORS
2309 // The accessorGetterNode_ and accessorSetterNode_ are used to store the
2310 // getter and setter synthesized by the `accessor` keyword when they are
2311 // decorated. Otherwise, they are null.
2313 // In most cases, the accessors are not added to the class members, and the
2314 // code generation occurs immediately prior to the decorator running. For
2315 // non-static private methods, the accessors are added to the class members
2316 // which causes them to be stored in lexical variables. The references here
2317 // are used to store the names of the accessors to look up the values of these
2318 // variables during bytecode generation.
2319 ClassMethod* accessorGetterNode_;
2320 ClassMethod* accessorSetterNode_;
2321 ListNode* decorators_;
2322 #endif
2324 public:
2325 ClassField(ParseNode* name, ParseNode* initializer, bool isStatic
2326 #ifdef ENABLE_DECORATORS
2328 ListNode* decorators, ClassMethod* accessorGetterNode,
2329 ClassMethod* accessorSetterNode
2330 #endif
2332 : BinaryNode(ParseNodeKind::ClassField, initializer->pn_pos, name,
2333 initializer),
2334 isStatic_(isStatic)
2335 #ifdef ENABLE_DECORATORS
2337 accessorGetterNode_(accessorGetterNode),
2338 accessorSetterNode_(accessorSetterNode),
2339 decorators_(decorators)
2340 #endif
2342 #ifdef ENABLE_DECORATORS
2343 MOZ_ASSERT((accessorGetterNode_ == nullptr) ==
2344 (accessorSetterNode_ == nullptr));
2345 #endif
2348 static bool test(const ParseNode& node) {
2349 bool match = node.isKind(ParseNodeKind::ClassField);
2350 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2351 return match;
2354 ParseNode& name() const { return *left(); }
2356 FunctionNode* initializer() const { return &right()->as<FunctionNode>(); }
2358 bool isStatic() const { return isStatic_; }
2360 #ifdef ENABLE_DECORATORS
2361 ListNode* decorators() const { return decorators_; }
2362 bool hasAccessor() const {
2363 return accessorGetterNode_ != nullptr && accessorSetterNode_ != nullptr;
2365 ClassMethod* accessorGetterNode() { return accessorGetterNode_; }
2366 ClassMethod* accessorSetterNode() { return accessorSetterNode_; }
2368 # ifdef DEBUG
2369 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
2370 int indent);
2371 # endif
2372 #endif
2375 // Hold onto the function generated for a class static block like
2377 // class A {
2378 // static { /* this static block */ }
2379 // }
2381 class StaticClassBlock : public UnaryNode {
2382 public:
2383 explicit StaticClassBlock(FunctionNode* function)
2384 : UnaryNode(ParseNodeKind::StaticClassBlock, function->pn_pos, function) {
2387 static bool test(const ParseNode& node) {
2388 bool match = node.isKind(ParseNodeKind::StaticClassBlock);
2389 MOZ_ASSERT_IF(match, node.is<UnaryNode>());
2390 return match;
2392 FunctionNode* function() const { return &kid()->as<FunctionNode>(); }
2395 class PropertyDefinition : public BinaryNode {
2396 AccessorType accessorType_;
2398 public:
2399 PropertyDefinition(ParseNode* name, ParseNode* value,
2400 AccessorType accessorType)
2401 : BinaryNode(ParseNodeKind::PropertyDefinition,
2402 TokenPos(name->pn_pos.begin, value->pn_pos.end), name,
2403 value),
2404 accessorType_(accessorType) {}
2406 static bool test(const ParseNode& node) {
2407 bool match = node.isKind(ParseNodeKind::PropertyDefinition);
2408 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2409 return match;
2412 AccessorType accessorType() { return accessorType_; }
2415 class SwitchStatement : public BinaryNode {
2416 bool hasDefault_; /* only for ParseNodeKind::Switch */
2418 public:
2419 SwitchStatement(uint32_t begin, ParseNode* discriminant,
2420 LexicalScopeNode* lexicalForCaseList, bool hasDefault)
2421 : BinaryNode(ParseNodeKind::SwitchStmt,
2422 TokenPos(begin, lexicalForCaseList->pn_pos.end),
2423 discriminant, lexicalForCaseList),
2424 hasDefault_(hasDefault) {
2425 #ifdef DEBUG
2426 ListNode* cases = &lexicalForCaseList->scopeBody()->as<ListNode>();
2427 MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
2428 bool found = false;
2429 for (ParseNode* item : cases->contents()) {
2430 CaseClause* caseNode = &item->as<CaseClause>();
2431 if (caseNode->isDefault()) {
2432 found = true;
2433 break;
2436 MOZ_ASSERT(found == hasDefault);
2437 #endif
2440 static bool test(const ParseNode& node) {
2441 bool match = node.isKind(ParseNodeKind::SwitchStmt);
2442 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2443 return match;
2446 ParseNode& discriminant() const { return *left(); }
2448 LexicalScopeNode& lexicalForCaseList() const {
2449 return right()->as<LexicalScopeNode>();
2452 bool hasDefault() const { return hasDefault_; }
2455 class ClassNames : public BinaryNode {
2456 public:
2457 ClassNames(ParseNode* outerBinding, ParseNode* innerBinding,
2458 const TokenPos& pos)
2459 : BinaryNode(ParseNodeKind::ClassNames, pos, outerBinding, innerBinding) {
2460 MOZ_ASSERT_IF(outerBinding, outerBinding->isKind(ParseNodeKind::Name));
2461 MOZ_ASSERT(innerBinding->isKind(ParseNodeKind::Name));
2462 MOZ_ASSERT_IF(outerBinding, innerBinding->as<NameNode>().atom() ==
2463 outerBinding->as<NameNode>().atom());
2466 static bool test(const ParseNode& node) {
2467 bool match = node.isKind(ParseNodeKind::ClassNames);
2468 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2469 return match;
2473 * Classes require two definitions: The first "outer" binding binds the
2474 * class into the scope in which it was declared. the outer binding is a
2475 * mutable lexial binding. The second "inner" binding binds the class by
2476 * name inside a block in which the methods are evaulated. It is immutable,
2477 * giving the methods access to the static members of the class even if
2478 * the outer binding has been overwritten.
2480 NameNode* outerBinding() const {
2481 if (ParseNode* binding = left()) {
2482 return &binding->as<NameNode>();
2484 return nullptr;
2487 NameNode* innerBinding() const { return &right()->as<NameNode>(); }
2490 class ClassNode : public TernaryNode {
2491 using Base = TernaryNode;
2493 private:
2494 LexicalScopeNode* innerScope() const {
2495 return &kid3()->as<LexicalScopeNode>();
2498 ClassBodyScopeNode* bodyScope() const {
2499 return &innerScope()->scopeBody()->as<ClassBodyScopeNode>();
2502 #ifdef ENABLE_DECORATORS
2503 ListNode* decorators_;
2504 #endif
2506 public:
2507 ClassNode(ParseNode* names, ParseNode* heritage,
2508 LexicalScopeNode* memberBlock,
2509 #ifdef ENABLE_DECORATORS
2510 ListNode* decorators,
2511 #endif
2512 const TokenPos& pos)
2513 : TernaryNode(ParseNodeKind::ClassDecl, names, heritage, memberBlock, pos)
2514 #ifdef ENABLE_DECORATORS
2516 decorators_(decorators)
2517 #endif
2519 MOZ_ASSERT(innerScope()->scopeBody()->is<ClassBodyScopeNode>());
2520 MOZ_ASSERT_IF(names, names->is<ClassNames>());
2523 static bool test(const ParseNode& node) {
2524 bool match = node.isKind(ParseNodeKind::ClassDecl);
2525 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
2526 return match;
2529 ClassNames* names() const {
2530 return kid1() ? &kid1()->as<ClassNames>() : nullptr;
2533 ParseNode* heritage() const { return kid2(); }
2535 ListNode* memberList() const { return bodyScope()->memberList(); }
2537 LexicalScopeNode* scopeBindings() const {
2538 LexicalScopeNode* scope = innerScope();
2539 return scope->isEmptyScope() ? nullptr : scope;
2542 ClassBodyScopeNode* bodyScopeBindings() const {
2543 ClassBodyScopeNode* scope = bodyScope();
2544 return scope->isEmptyScope() ? nullptr : scope;
2546 #ifdef ENABLE_DECORATORS
2547 ListNode* decorators() const { return decorators_; }
2549 # ifdef DEBUG
2550 void dumpImpl(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
2551 int indent);
2552 # endif
2553 #endif
2556 #ifdef DEBUG
2557 void DumpParseTree(ParserBase* parser, ParseNode* pn, GenericPrinter& out,
2558 int indent = 0);
2559 #endif
2561 class ParseNodeAllocator {
2562 public:
2563 explicit ParseNodeAllocator(FrontendContext* fc, LifoAlloc& alloc)
2564 : fc(fc), alloc(alloc) {}
2566 void* allocNode(size_t size);
2568 private:
2569 FrontendContext* fc;
2570 LifoAlloc& alloc;
2573 inline bool ParseNode::isConstant() {
2574 switch (pn_type) {
2575 case ParseNodeKind::NumberExpr:
2576 case ParseNodeKind::StringExpr:
2577 case ParseNodeKind::TemplateStringExpr:
2578 case ParseNodeKind::NullExpr:
2579 case ParseNodeKind::RawUndefinedExpr:
2580 case ParseNodeKind::FalseExpr:
2581 case ParseNodeKind::TrueExpr:
2582 return true;
2583 case ParseNodeKind::ArrayExpr:
2584 case ParseNodeKind::ObjectExpr:
2585 return !as<ListNode>().hasNonConstInitializer();
2586 default:
2587 return false;
2591 bool IsAnonymousFunctionDefinition(ParseNode* pn);
2593 } /* namespace frontend */
2594 } /* namespace js */
2596 #endif /* frontend_ParseNode_h */