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/. */
6
7 #ifndef frontend_ParseNode_h
8 #define frontend_ParseNode_h
9
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Span.h" // mozilla::Span
12
13 #include <iterator>
14 #include <stddef.h>
15 #include <stdint.h>
16
17 #include "jstypes.h" // js::Bit
18
19 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
20 #include "frontend/NameAnalysisTypes.h" // PrivateNameKind
21 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
22 #include "frontend/Stencil.h" // BigIntStencil
23 #include "frontend/Token.h"
24 #include "js/RootingAPI.h"
25 #include "vm/BytecodeUtil.h"
26 #include "vm/Scope.h"
27 #include "vm/ScopeKind.h"
28 #include "vm/StringType.h"
29
30 // [SMDOC] ParseNode tree lifetime information
31 //
32 // - All the `ParseNode` instances MUST BE explicitly allocated in the context's
33 // `LifoAlloc`. This is typically implemented by the `FullParseHandler` or it
34 // can be reimplemented with a custom `new_`.
35 //
36 // - The tree is bulk-deallocated when the parser is deallocated. Consequently,
37 // references to a subtree MUST NOT exist once the parser has been
38 // deallocated.
39 //
40 // - This bulk-deallocation DOES NOT run destructors.
41 //
42 // - Instances of `LexicalScope::ParserData` and `ClassBodyScope::ParserData`
43 // MUST BE allocated as instances of `ParseNode`, in the same `LifoAlloc`.
44 // They are bulk-deallocated alongside the rest of the tree.
45
46 struct JSContext;
47
48 namespace JS {
49 class BigInt;
50 }
51
52 namespace js {
53
54 class GenericPrinter;
55 class LifoAlloc;
56 class RegExpObject;
57
58 namespace frontend {
59
60 class ParserBase;
61 class ParseContext;
62 class ParserAtomsTable;
63 struct ExtensibleCompilationStencil;
64 class ParserSharedBase;
65 class FullParseHandler;
66
67 class FunctionBox;
68
69 #define FOR_EACH_PARSE_NODE_KIND(F) \
70 F(EmptyStmt, NullaryNode) \
71 F(ExpressionStmt, UnaryNode) \
72 F(CommaExpr, ListNode) \
73 F(ConditionalExpr, ConditionalExpression) \
74 F(PropertyDefinition, PropertyDefinition) \
75 F(Shorthand, BinaryNode) \
76 F(PosExpr, UnaryNode) \
77 F(NegExpr, UnaryNode) \
78 F(PreIncrementExpr, UnaryNode) \
79 F(PostIncrementExpr, UnaryNode) \
80 F(PreDecrementExpr, UnaryNode) \
81 F(PostDecrementExpr, UnaryNode) \
82 F(PropertyNameExpr, NameNode) \
83 F(DotExpr, PropertyAccess) \
84 F(ElemExpr, PropertyByValue) \
85 F(PrivateMemberExpr, PrivateMemberAccess) \
86 F(OptionalDotExpr, OptionalPropertyAccess) \
87 F(OptionalChain, UnaryNode) \
88 F(OptionalElemExpr, OptionalPropertyByValue) \
89 F(OptionalPrivateMemberExpr, OptionalPrivateMemberAccess) \
90 F(OptionalCallExpr, BinaryNode) \
91 F(ArrayExpr, ListNode) \
92 F(Elision, NullaryNode) \
93 F(StatementList, ListNode) \
94 F(LabelStmt, LabeledStatement) \
95 F(ObjectExpr, ListNode) \
96 F(CallExpr, BinaryNode) \
97 F(Arguments, ListNode) \
98 F(Name, NameNode) \
99 F(ObjectPropertyName, NameNode) \
100 F(PrivateName, NameNode) \
101 F(ComputedName, UnaryNode) \
102 F(NumberExpr, NumericLiteral) \
103 F(BigIntExpr, BigIntLiteral) \
104 F(StringExpr, NameNode) \
105 F(TemplateStringListExpr, ListNode) \
106 F(TemplateStringExpr, NameNode) \
107 F(TaggedTemplateExpr, BinaryNode) \
108 F(CallSiteObj, CallSiteNode) \
109 F(RegExpExpr, RegExpLiteral) \
110 F(TrueExpr, BooleanLiteral) \
111 F(FalseExpr, BooleanLiteral) \
112 F(NullExpr, NullLiteral) \
113 F(RawUndefinedExpr, RawUndefinedLiteral) \
114 F(ThisExpr, UnaryNode) \
115 F(Function, FunctionNode) \
116 F(Module, ModuleNode) \
117 F(IfStmt, TernaryNode) \
118 F(SwitchStmt, SwitchStatement) \
119 F(Case, CaseClause) \
120 F(WhileStmt, BinaryNode) \
121 F(DoWhileStmt, BinaryNode) \
122 F(ForStmt, ForNode) \
123 F(BreakStmt, BreakStatement) \
124 F(ContinueStmt, ContinueStatement) \
125 F(VarStmt, ListNode) \
126 F(ConstDecl, ListNode) \
127 F(WithStmt, BinaryNode) \
128 F(ReturnStmt, UnaryNode) \
129 F(NewExpr, BinaryNode) \
130 /* Delete operations. These must be sequential. */ \
131 F(DeleteNameExpr, UnaryNode) \
132 F(DeletePropExpr, UnaryNode) \
133 F(DeleteElemExpr, UnaryNode) \
134 F(DeleteOptionalChainExpr, UnaryNode) \
135 F(DeleteExpr, UnaryNode) \
136 F(TryStmt, TernaryNode) \
137 F(Catch, BinaryNode) \
138 F(ThrowStmt, UnaryNode) \
139 F(DebuggerStmt, DebuggerStatement) \
140 F(Generator, NullaryNode) \
141 F(InitialYield, UnaryNode) \
142 F(YieldExpr, UnaryNode) \
143 F(YieldStarExpr, UnaryNode) \
144 F(LexicalScope, LexicalScopeNode) \
145 F(LetDecl, ListNode) \
146 F(ImportDecl, BinaryNode) \
147 F(ImportSpecList, ListNode) \
148 F(ImportSpec, BinaryNode) \
149 F(ImportNamespaceSpec, UnaryNode) \
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, ListNode) \
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, BinaryNode) \
172 F(PosHolder, NullaryNode) \
173 F(SuperBase, UnaryNode) \
174 F(SuperCallExpr, BinaryNode) \
175 F(SetThis, BinaryNode) \
176 F(ImportMetaExpr, BinaryNode) \
177 F(CallImportExpr, BinaryNode) \
178 F(InitExpr, BinaryNode) \
179 \
180 /* Unary operators. */ \
181 F(TypeOfNameExpr, UnaryNode) \
182 F(TypeOfExpr, UnaryNode) \
183 F(VoidExpr, UnaryNode) \
184 F(NotExpr, UnaryNode) \
185 F(BitNotExpr, UnaryNode) \
186 F(AwaitExpr, UnaryNode) \
187 \
188 /* \
189 * Binary operators. \
190 * This list must be kept in the same order in several places: \
191 * - The binary operators in ParseNode.h \
192 * - the binary operators in TokenKind.h \
193 * - the precedence list in Parser.cpp \
194 * - the JSOp code list in BytecodeEmitter.cpp \
195 */ \
196 F(CoalesceExpr, ListNode) \
197 F(OrExpr, ListNode) \
198 F(AndExpr, ListNode) \
199 F(BitOrExpr, ListNode) \
200 F(BitXorExpr, ListNode) \
201 F(BitAndExpr, ListNode) \
202 F(StrictEqExpr, ListNode) \
203 F(EqExpr, ListNode) \
204 F(StrictNeExpr, ListNode) \
205 F(NeExpr, ListNode) \
206 F(LtExpr, ListNode) \
207 F(LeExpr, ListNode) \
208 F(GtExpr, ListNode) \
209 F(GeExpr, ListNode) \
210 F(InstanceOfExpr, ListNode) \
211 F(InExpr, ListNode) \
212 F(PrivateInExpr, ListNode) \
213 F(LshExpr, ListNode) \
214 F(RshExpr, ListNode) \
215 F(UrshExpr, ListNode) \
216 F(AddExpr, ListNode) \
217 F(SubExpr, ListNode) \
218 F(MulExpr, ListNode) \
219 F(DivExpr, ListNode) \
220 F(ModExpr, ListNode) \
221 F(PowExpr, ListNode) \
222 \
223 /* Assignment operators (= += -= etc.). */ \
224 /* AssignmentNode::test assumes all these are consecutive. */ \
225 F(AssignExpr, AssignmentNode) \
226 F(AddAssignExpr, AssignmentNode) \
227 F(SubAssignExpr, AssignmentNode) \
228 F(CoalesceAssignExpr, AssignmentNode) \
229 F(OrAssignExpr, AssignmentNode) \
230 F(AndAssignExpr, AssignmentNode) \
231 F(BitOrAssignExpr, AssignmentNode) \
232 F(BitXorAssignExpr, AssignmentNode) \
233 F(BitAndAssignExpr, AssignmentNode) \
234 F(LshAssignExpr, AssignmentNode) \
235 F(RshAssignExpr, AssignmentNode) \
236 F(UrshAssignExpr, AssignmentNode) \
237 F(MulAssignExpr, AssignmentNode) \
238 F(DivAssignExpr, AssignmentNode) \
239 F(ModAssignExpr, AssignmentNode) \
240 F(PowAssignExpr, AssignmentNode)
241
242 /*
243 * Parsing builds a tree of nodes that directs code generation. This tree is
244 * not a concrete syntax tree in all respects (for example, || and && are left
245 * associative, but (A && B && C) translates into the right-associated tree
246 * <A && <B && C>> so that code generation can emit a left-associative branch
247 * around <B && C> when A is false). Nodes are labeled by kind.
248 *
249 * The long comment after this enum block describes the kinds in detail.
250 */
251 enum class ParseNodeKind : uint16_t {
252 // These constants start at 1001, the better to catch
253 LastUnused = 1000,
254 #define EMIT_ENUM(name, _type) name,
255 FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
256 #undef EMIT_ENUM
257 Limit,
258 Start = LastUnused + 1,
259 BinOpFirst = ParseNodeKind::CoalesceExpr,
260 BinOpLast = ParseNodeKind::PowExpr,
261 AssignmentStart = ParseNodeKind::AssignExpr,
262 AssignmentLast = ParseNodeKind::PowAssignExpr,
263 };
264
IsDeleteKind(ParseNodeKind kind)265 inline bool IsDeleteKind(ParseNodeKind kind) {
266 return ParseNodeKind::DeleteNameExpr <= kind &&
267 kind <= ParseNodeKind::DeleteExpr;
268 }
269
IsTypeofKind(ParseNodeKind kind)270 inline bool IsTypeofKind(ParseNodeKind kind) {
271 return ParseNodeKind::TypeOfNameExpr <= kind &&
272 kind <= ParseNodeKind::TypeOfExpr;
273 }
274
275 /*
276 * <Definitions>
277 * Function (FunctionNode)
278 * funbox: ptr to js::FunctionBox
279 * body: ParamsBody or null for lazily-parsed function, ordinarily;
280 * ParseNodeKind::LexicalScope for implicit function in genexpr
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 either:
292 * * StatementList node for function body statements
293 * * ReturnStmt for expression closure
294 * count: number of formal parameters + 1
295 * Spread (UnaryNode)
296 * kid: expression being spread
297 * ClassDecl (ClassNode)
298 * kid1: ClassNames for class name. can be null for anonymous class.
299 * kid2: expression after `extends`. null if no expression
300 * kid3: either of
301 * * ClassMemberList, if anonymous class
302 * * LexicalScopeNode which contains ClassMemberList as scopeBody,
303 * if named class
304 * ClassNames (ClassNames)
305 * left: Name node for outer binding, or null if the class is an expression
306 * that doesn't create an outer binding
307 * right: Name node for inner binding
308 * ClassMemberList (ListNode)
309 * head: list of N ClassMethod, ClassField or StaticClassBlock nodes
310 * count: N >= 0
311 * DefaultConstructor (ClassMethod)
312 * name: propertyName
313 * method: methodDefinition
314 * ClassMethod (ClassMethod)
315 * name: propertyName
316 * method: methodDefinition
317 * initializerIfPrivate: initializer to stamp private method onto instance
318 * Module (ModuleNode)
319 * body: statement list of the module
320 *
321 * <Statements>
322 * StatementList (ListNode)
323 * head: list of N statements
324 * count: N >= 0
325 * IfStmt (TernaryNode)
326 * kid1: cond
327 * kid2: then
328 * kid3: else or null
329 * SwitchStmt (SwitchStatement)
330 * left: discriminant
331 * right: LexicalScope node that contains the list of Case nodes, with at
332 * most one default node.
333 * hasDefault: true if there's a default case
334 * Case (CaseClause)
335 * left: case-expression if CaseClause, or null if DefaultClause
336 * right: StatementList node for this case's statements
337 * WhileStmt (BinaryNode)
338 * left: cond
339 * right: body
340 * DoWhileStmt (BinaryNode)
341 * left: body
342 * right: cond
343 * ForStmt (ForNode)
344 * left: one of
345 * * ForIn: for (x in y) ...
346 * * ForOf: for (x of x) ...
347 * * ForHead: for (;;) ...
348 * right: body
349 * ForIn (TernaryNode)
350 * kid1: declaration or expression to left of 'in'
351 * kid2: null
352 * kid3: object expr to right of 'in'
353 * ForOf (TernaryNode)
354 * kid1: declaration or expression to left of 'of'
355 * kid2: null
356 * kid3: expr to right of 'of'
357 * ForHead (TernaryNode)
358 * kid1: init expr before first ';' or nullptr
359 * kid2: cond expr before second ';' or nullptr
360 * kid3: update expr after second ';' or nullptr
361 * ThrowStmt (UnaryNode)
362 * kid: thrown exception
363 * TryStmt (TernaryNode)
364 * kid1: try block
365 * kid2: null or LexicalScope for catch-block with scopeBody pointing to a
366 * Catch node
367 * kid3: null or finally block
368 * Catch (BinaryNode)
369 * left: Name, Array, or Object catch var node
370 * (Array or Object if destructuring),
371 * or null if optional catch binding
372 * right: catch block statements
373 * BreakStmt (BreakStatement)
374 * label: label or null
375 * ContinueStmt (ContinueStatement)
376 * label: label or null
377 * WithStmt (BinaryNode)
378 * left: head expr
379 * right: body
380 * VarStmt, LetDecl, ConstDecl (ListNode)
381 * head: list of N Name or AssignExpr nodes
382 * each name node has either
383 * atom: variable name
384 * expr: initializer or null
385 * or
386 * atom: variable name
387 * each assignment node has
388 * left: pattern
389 * right: initializer
390 * count: N > 0
391 * ReturnStmt (UnaryNode)
392 * kid: returned expression, or null if none
393 * ExpressionStmt (UnaryNode)
394 * kid: expr
395 * EmptyStmt (NullaryNode)
396 * (no fields)
397 * LabelStmt (LabeledStatement)
398 * atom: label
399 * expr: labeled statement
400 * ImportDecl (BinaryNode)
401 * left: ImportSpecList import specifiers
402 * right: String module specifier
403 * ImportSpecList (ListNode)
404 * head: list of N ImportSpec nodes
405 * count: N >= 0 (N = 0 for `import {} from ...`)
406 * ImportSpec (BinaryNode)
407 * left: import name
408 * right: local binding name
409 * ImportNamespaceSpec (UnaryNode)
410 * kid: local binding name
411 * ExportStmt (UnaryNode)
412 * kid: declaration expression
413 * ExportFromStmt (BinaryNode)
414 * left: ExportSpecList export specifiers
415 * right: String module specifier
416 * ExportSpecList (ListNode)
417 * head: list of N ExportSpec nodes
418 * count: N >= 0 (N = 0 for `export {}`)
419 * ExportSpec (BinaryNode)
420 * left: local binding name
421 * right: export name
422 * ExportNamespaceSpec (UnaryNode)
423 * kid: export name
424 * ExportDefaultStmt (BinaryNode)
425 * left: export default declaration or expression
426 * right: Name node for assignment
427 *
428 * <Expressions>
429 * The `Expr` suffix is used for nodes that can appear anywhere an expression
430 * could appear. It is not used on a few weird kinds like Arguments and
431 * CallSiteObj that are always the child node of an expression node, but which
432 * can't stand alone.
433 *
434 * All left-associated binary trees of the same type are optimized into lists
435 * to avoid recursion when processing expression chains.
436 *
437 * CommaExpr (ListNode)
438 * head: list of N comma-separated exprs
439 * count: N >= 2
440 * AssignExpr (BinaryNode)
441 * left: target of assignment
442 * right: value to assign
443 * AddAssignExpr, SubAssignExpr, CoalesceAssignExpr, OrAssignExpr,
444 * AndAssignExpr, BitOrAssignExpr, BitXorAssignExpr, BitAndAssignExpr,
445 * LshAssignExpr, RshAssignExpr, UrshAssignExpr, MulAssignExpr, DivAssignExpr,
446 * ModAssignExpr, PowAssignExpr (AssignmentNode)
447 * left: target of assignment
448 * right: value to assign
449 * ConditionalExpr (ConditionalExpression)
450 * (cond ? thenExpr : elseExpr)
451 * kid1: cond
452 * kid2: thenExpr
453 * kid3: elseExpr
454 * CoalesceExpr, OrExpr, AndExpr, BitOrExpr, BitXorExpr,
455 * BitAndExpr, StrictEqExpr, EqExpr, StrictNeExpr, NeExpr, LtExpr, LeExpr,
456 * GtExpr, GeExpr, InstanceOfExpr, InExpr, LshExpr, RshExpr, UrshExpr, AddExpr,
457 * SubExpr, MulExpr, DivExpr, ModExpr, PowExpr (ListNode)
458 * head: list of N subexpressions
459 * All of these operators are left-associative except Pow which is
460 * right-associative, but still forms a list (see comments in
461 * ParseNode::appendOrCreateList).
462 * count: N >= 2
463 * PosExpr, NegExpr, VoidExpr, NotExpr, BitNotExpr, TypeOfNameExpr,
464 * TypeOfExpr (UnaryNode)
465 * kid: unary expr
466 * PreIncrementExpr, PostIncrementExpr, PreDecrementExpr,
467 * PostDecrementExpr (UnaryNode)
468 * kid: member expr
469 * NewExpr (BinaryNode)
470 * left: ctor expression on the left of the '('
471 * right: Arguments
472 * DeleteNameExpr, DeletePropExpr, DeleteElemExpr, DeleteExpr (UnaryNode)
473 * kid: expression that's evaluated, then the overall delete evaluates to
474 * true; can't be a kind for a more-specific ParseNodeKind::Delete*
475 * unless constant folding (or a similar parse tree manipulation) has
476 * occurred
477 * * DeleteNameExpr: Name expr
478 * * DeletePropExpr: Dot expr
479 * * DeleteElemExpr: Elem expr
480 * * DeleteOptionalChainExpr: Member expr
481 * * DeleteExpr: Member expr
482 * DeleteOptionalChainExpr (UnaryNode)
483 * kid: expression that's evaluated, then the overall delete evaluates to
484 * true; If constant folding occurs, Elem expr may become Dot expr.
485 * OptionalElemExpr does not get folded into OptionalDot.
486 * OptionalChain (UnaryNode)
487 * kid: expression that is evaluated as a chain. An Optional chain contains
488 * one or more optional nodes. It's first node (kid) is always an
489 * optional node, for example: an OptionalElemExpr, OptionalDotExpr, or
490 * OptionalCall. An OptionalChain will shortcircuit and return
491 * Undefined without evaluating the rest of the expression if any of the
492 * optional nodes it contains are nullish. An optionalChain also can
493 * contain nodes such as DotExpr, ElemExpr, NameExpr CallExpr, etc.
494 * These are evaluated normally.
495 * * OptionalDotExpr: Dot expr with jump
496 * * OptionalElemExpr: Elem expr with jump
497 * * OptionalCallExpr: Call expr with jump
498 * * DotExpr: Dot expr without jump
499 * * ElemExpr: Elem expr without jump
500 * * CallExpr: Call expr without jump
501 * PropertyNameExpr (NameNode)
502 * atom: property name being accessed
503 * privateNameKind: kind of the name if private
504 * DotExpr (PropertyAccess)
505 * left: MEMBER expr to left of '.'
506 * right: PropertyName to right of '.'
507 * OptionalDotExpr (OptionalPropertyAccess)
508 * left: MEMBER expr to left of '.', short circuits back to OptionalChain
509 * if nullish.
510 * right: PropertyName to right of '.'
511 * ElemExpr (PropertyByValue)
512 * left: MEMBER expr to left of '['
513 * right: expr between '[' and ']'
514 * OptionalElemExpr (OptionalPropertyByValue)
515 * left: MEMBER expr to left of '[', short circuits back to OptionalChain
516 * if nullish.
517 * right: expr between '[' and ']'
518 * CallExpr (BinaryNode)
519 * left: callee expression on the left of the '('
520 * right: Arguments
521 * OptionalCallExpr (BinaryNode)
522 * left: callee expression on the left of the '(', short circuits back to
523 * OptionalChain if nullish.
524 * right: Arguments
525 * Arguments (ListNode)
526 * head: list of arg1, arg2, ... argN
527 * count: N >= 0
528 * ArrayExpr (ListNode)
529 * head: list of N array element expressions
530 * holes ([,,]) are represented by Elision nodes,
531 * spread elements ([...X]) are represented by Spread nodes
532 * count: N >= 0
533 * ObjectExpr (ListNode)
534 * head: list of N nodes, each item is one of:
535 * * MutateProto
536 * * PropertyDefinition
537 * * Shorthand
538 * * Spread
539 * count: N >= 0
540 * PropertyDefinition (PropertyDefinition)
541 * key-value pair in object initializer or destructuring lhs
542 * left: property id
543 * right: value
544 * Shorthand (BinaryNode)
545 * Same fields as PropertyDefinition. This is used for object literal
546 * properties using shorthand ({x}).
547 * ComputedName (UnaryNode)
548 * ES6 ComputedPropertyName.
549 * kid: the AssignmentExpression inside the square brackets
550 * Name (NameNode)
551 * atom: name, or object atom
552 * StringExpr (NameNode)
553 * atom: string
554 * TemplateStringListExpr (ListNode)
555 * head: list of alternating expr and template strings
556 * TemplateString [, expression, TemplateString]+
557 * there's at least one expression. If the template literal contains
558 * no ${}-delimited expression, it's parsed as a single TemplateString
559 * TemplateStringExpr (NameNode)
560 * atom: template string atom
561 * TaggedTemplateExpr (BinaryNode)
562 * left: tag expression
563 * right: Arguments, with the first being the call site object, then
564 * arg1, arg2, ... argN
565 * CallSiteObj (CallSiteNode)
566 * head: an Array of raw TemplateString, then corresponding cooked
567 * TemplateString nodes
568 * Array [, cooked TemplateString]+
569 * where the Array is
570 * [raw TemplateString]+
571 * RegExpExpr (RegExpLiteral)
572 * regexp: RegExp model object
573 * NumberExpr (NumericLiteral)
574 * value: double value of numeric literal
575 * BigIntExpr (BigIntLiteral)
576 * stencil: script compilation struct that has |bigIntData| vector
577 * index: index into the script compilation's |bigIntData| vector
578 * TrueExpr, FalseExpr (BooleanLiteral)
579 * NullExpr (NullLiteral)
580 * RawUndefinedExpr (RawUndefinedLiteral)
581 *
582 * ThisExpr (UnaryNode)
583 * kid: '.this' Name if function `this`, else nullptr
584 * SuperBase (UnaryNode)
585 * kid: '.this' Name
586 * SuperCallExpr (BinaryNode)
587 * left: SuperBase
588 * right: Arguments
589 * SetThis (BinaryNode)
590 * left: '.this' Name
591 * right: SuperCall
592 *
593 * LexicalScope (LexicalScopeNode)
594 * scopeBindings: scope bindings
595 * scopeBody: scope body
596 * Generator (NullaryNode)
597 * InitialYield (UnaryNode)
598 * kid: generator object
599 * YieldExpr, YieldStarExpr, AwaitExpr (UnaryNode)
600 * kid: expr or null
601 */
602
603 // FIXME: Remove `*Type` (bug 1489008)
604 #define FOR_EACH_PARSENODE_SUBCLASS(MACRO) \
605 MACRO(BinaryNode, BinaryNodeType, asBinary) \
606 MACRO(AssignmentNode, AssignmentNodeType, asAssignment) \
607 MACRO(CaseClause, CaseClauseType, asCaseClause) \
608 MACRO(ClassMethod, ClassMethodType, asClassMethod) \
609 MACRO(ClassField, ClassFieldType, asClassField) \
610 MACRO(StaticClassBlock, StaticClassBlockType, asStaticClassBlock) \
611 MACRO(PropertyDefinition, PropertyDefinitionType, asPropertyDefinition) \
612 MACRO(ClassNames, ClassNamesType, asClassNames) \
613 MACRO(ForNode, ForNodeType, asFor) \
614 MACRO(PropertyAccess, PropertyAccessType, asPropertyAccess) \
615 MACRO(OptionalPropertyAccess, OptionalPropertyAccessType, \
616 asOptionalPropertyAccess) \
617 MACRO(PropertyByValue, PropertyByValueType, asPropertyByValue) \
618 MACRO(OptionalPropertyByValue, OptionalPropertyByValueType, \
619 asOptionalPropertyByValue) \
620 MACRO(PrivateMemberAccess, PrivateMemberAccessType, asPrivateMemberAccess) \
621 MACRO(OptionalPrivateMemberAccess, OptionalPrivateMemberAccessType, \
622 asOptionalPrivateMemberAccess) \
623 MACRO(SwitchStatement, SwitchStatementType, asSwitchStatement) \
624 \
625 MACRO(FunctionNode, FunctionNodeType, asFunction) \
626 MACRO(ModuleNode, ModuleNodeType, asModule) \
627 \
628 MACRO(LexicalScopeNode, LexicalScopeNodeType, asLexicalScope) \
629 MACRO(ClassBodyScopeNode, ClassBodyScopeNodeType, asClassBodyScope) \
630 \
631 MACRO(ListNode, ListNodeType, asList) \
632 MACRO(CallSiteNode, CallSiteNodeType, asCallSite) \
633 MACRO(CallNode, CallNodeType, asCallNode) \
634 MACRO(CallNode, OptionalCallNodeType, asOptionalCallNode) \
635 \
636 MACRO(LoopControlStatement, LoopControlStatementType, \
637 asLoopControlStatement) \
638 MACRO(BreakStatement, BreakStatementType, asBreakStatement) \
639 MACRO(ContinueStatement, ContinueStatementType, asContinueStatement) \
640 \
641 MACRO(NameNode, NameNodeType, asName) \
642 MACRO(LabeledStatement, LabeledStatementType, asLabeledStatement) \
643 \
644 MACRO(NullaryNode, NullaryNodeType, asNullary) \
645 MACRO(BooleanLiteral, BooleanLiteralType, asBooleanLiteral) \
646 MACRO(DebuggerStatement, DebuggerStatementType, asDebuggerStatement) \
647 MACRO(NullLiteral, NullLiteralType, asNullLiteral) \
648 MACRO(RawUndefinedLiteral, RawUndefinedLiteralType, asRawUndefinedLiteral) \
649 \
650 MACRO(NumericLiteral, NumericLiteralType, asNumericLiteral) \
651 MACRO(BigIntLiteral, BigIntLiteralType, asBigIntLiteral) \
652 \
653 MACRO(RegExpLiteral, RegExpLiteralType, asRegExpLiteral) \
654 \
655 MACRO(TernaryNode, TernaryNodeType, asTernary) \
656 MACRO(ClassNode, ClassNodeType, asClass) \
657 MACRO(ConditionalExpression, ConditionalExpressionType, \
658 asConditionalExpression) \
659 MACRO(TryNode, TryNodeType, asTry) \
660 \
661 MACRO(UnaryNode, UnaryNodeType, asUnary) \
662 MACRO(ThisLiteral, ThisLiteralType, asThisLiteral)
663
664 #define DECLARE_CLASS(typeName, longTypeName, asMethodName) class typeName;
665 FOR_EACH_PARSENODE_SUBCLASS(DECLARE_CLASS)
666 #undef DECLARE_CLASS
667
668 enum class AccessorType { None, Getter, Setter };
669
IsConstructorKind(FunctionSyntaxKind kind)670 static inline bool IsConstructorKind(FunctionSyntaxKind kind) {
671 return kind == FunctionSyntaxKind::ClassConstructor ||
672 kind == FunctionSyntaxKind::DerivedClassConstructor;
673 }
674
IsMethodDefinitionKind(FunctionSyntaxKind kind)675 static inline bool IsMethodDefinitionKind(FunctionSyntaxKind kind) {
676 return IsConstructorKind(kind) || kind == FunctionSyntaxKind::Method ||
677 kind == FunctionSyntaxKind::FieldInitializer ||
678 kind == FunctionSyntaxKind::Getter ||
679 kind == FunctionSyntaxKind::Setter;
680 }
681
682 // To help diagnose sporadic crashes in the frontend, a few assertions are
683 // enabled in early beta builds. (Most are not; those still use MOZ_ASSERT.)
684 // See bug 1547561.
685 #if defined(EARLY_BETA_OR_EARLIER)
686 # define JS_PARSE_NODE_ASSERT MOZ_RELEASE_ASSERT
687 #else
688 # define JS_PARSE_NODE_ASSERT MOZ_ASSERT
689 #endif
690
691 class ParseNode {
692 const ParseNodeKind pn_type; /* ParseNodeKind::PNK_* type */
693
694 bool pn_parens : 1; /* this expr was enclosed in parens */
695 bool pn_rhs_anon_fun : 1; /* this expr is anonymous function or class that
696 * is a direct RHS of ParseNodeKind::Assign or
697 * ParseNodeKind::PropertyDefinition of property,
698 * that needs SetFunctionName. */
699
700 protected:
701 // Used by ComputedName to indicate if the ComputedName is a
702 // a synthetic construct. This allows us to avoid needing to
703 // compute ToString on uncommon property values such as BigInt.
704 // Instead we parse as though they were computed names.
705 //
706 // We need this bit to distinguish a synthetic computed name like
707 // this however to undo this transformation in Reflect.parse and
708 // name guessing.
709 bool pn_synthetic_computed : 1;
710
711 ParseNode(const ParseNode& other) = delete;
712 void operator=(const ParseNode& other) = delete;
713
714 public:
ParseNode(ParseNodeKind kind)715 explicit ParseNode(ParseNodeKind kind)
716 : pn_type(kind),
717 pn_parens(false),
718 pn_rhs_anon_fun(false),
719 pn_synthetic_computed(false),
720 pn_pos(0, 0),
721 pn_next(nullptr) {
722 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= kind);
723 JS_PARSE_NODE_ASSERT(kind < ParseNodeKind::Limit);
724 }
725
ParseNode(ParseNodeKind kind,const TokenPos & pos)726 ParseNode(ParseNodeKind kind, const TokenPos& pos)
727 : pn_type(kind),
728 pn_parens(false),
729 pn_rhs_anon_fun(false),
730 pn_synthetic_computed(false),
731 pn_pos(pos),
732 pn_next(nullptr) {
733 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= kind);
734 JS_PARSE_NODE_ASSERT(kind < ParseNodeKind::Limit);
735 }
736
getKind()737 ParseNodeKind getKind() const {
738 JS_PARSE_NODE_ASSERT(ParseNodeKind::Start <= pn_type);
739 JS_PARSE_NODE_ASSERT(pn_type < ParseNodeKind::Limit);
740 return pn_type;
741 }
isKind(ParseNodeKind kind)742 bool isKind(ParseNodeKind kind) const { return getKind() == kind; }
743
744 protected:
getKindAsIndex()745 size_t getKindAsIndex() const {
746 return size_t(getKind()) - size_t(ParseNodeKind::Start);
747 }
748
749 // Used to implement test() on a few ParseNodes efficiently.
750 // (This enum doesn't fully reflect the ParseNode class hierarchy,
751 // so don't use it for anything else.)
752 enum class TypeCode : uint8_t {
753 Nullary,
754 Unary,
755 Binary,
756 Ternary,
757 List,
758 Name,
759 Other
760 };
761
762 // typeCodeTable[getKindAsIndex()] is the type code of a ParseNode of kind
763 // pnk.
764 static const TypeCode typeCodeTable[];
765
766 private:
767 #ifdef DEBUG
768 static const size_t sizeTable[];
769 #endif
770
771 public:
typeCode()772 TypeCode typeCode() const { return typeCodeTable[getKindAsIndex()]; }
773
isBinaryOperation()774 bool isBinaryOperation() const {
775 ParseNodeKind kind = getKind();
776 return ParseNodeKind::BinOpFirst <= kind &&
777 kind <= ParseNodeKind::BinOpLast;
778 }
779 inline bool isName(TaggedParserAtomIndex name) const;
780
781 /* Boolean attributes. */
isInParens()782 bool isInParens() const { return pn_parens; }
isLikelyIIFE()783 bool isLikelyIIFE() const { return isInParens(); }
setInParens(bool enabled)784 void setInParens(bool enabled) { pn_parens = enabled; }
785
isDirectRHSAnonFunction()786 bool isDirectRHSAnonFunction() const { return pn_rhs_anon_fun; }
setDirectRHSAnonFunction(bool enabled)787 void setDirectRHSAnonFunction(bool enabled) { pn_rhs_anon_fun = enabled; }
788
789 TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
790 ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
791
792 public:
793 /*
794 * If |left| is a list of the given kind/left-associative op, append
795 * |right| to it and return |left|. Otherwise return a [left, right] list.
796 */
797 static ParseNode* appendOrCreateList(ParseNodeKind kind, ParseNode* left,
798 ParseNode* right,
799 FullParseHandler* handler,
800 ParseContext* pc);
801
802 /* True if pn is a parsenode representing a literal constant. */
isLiteral()803 bool isLiteral() const {
804 return isKind(ParseNodeKind::NumberExpr) ||
805 isKind(ParseNodeKind::BigIntExpr) ||
806 isKind(ParseNodeKind::StringExpr) ||
807 isKind(ParseNodeKind::TrueExpr) ||
808 isKind(ParseNodeKind::FalseExpr) ||
809 isKind(ParseNodeKind::NullExpr) ||
810 isKind(ParseNodeKind::RawUndefinedExpr);
811 }
812
813 // True iff this is a for-in/of loop variable declaration (var/let/const).
814 inline bool isForLoopDeclaration() const;
815
816 inline bool isConstant();
817
818 template <class NodeType>
is()819 inline bool is() const {
820 return NodeType::test(*this);
821 }
822
823 /* Casting operations. */
824 template <class NodeType>
as()825 inline NodeType& as() {
826 MOZ_ASSERT(NodeType::test(*this));
827 return *static_cast<NodeType*>(this);
828 }
829
830 template <class NodeType>
as()831 inline const NodeType& as() const {
832 MOZ_ASSERT(NodeType::test(*this));
833 return *static_cast<const NodeType*>(this);
834 }
835
836 #ifdef DEBUG
837 // Debugger-friendly stderr printer.
838 void dump();
839 void dump(ParserBase* parser);
840 void dump(ParserBase* parser, GenericPrinter& out);
841 void dump(ParserBase* parser, GenericPrinter& out, int indent);
842
843 // The size of this node, in bytes.
size()844 size_t size() const { return sizeTable[getKindAsIndex()]; }
845 #endif
846 };
847
848 // Remove a ParseNode, **pnp, from a parse tree, putting another ParseNode,
849 // *pn, in its place.
850 //
851 // pnp points to a ParseNode pointer. This must be the only pointer that points
852 // to the parse node being replaced. The replacement, *pn, is unchanged except
853 // for its pn_next pointer; updating that is necessary if *pn's new parent is a
854 // list node.
ReplaceNode(ParseNode ** pnp,ParseNode * pn)855 inline void ReplaceNode(ParseNode** pnp, ParseNode* pn) {
856 pn->pn_next = (*pnp)->pn_next;
857 *pnp = pn;
858 }
859
860 class NullaryNode : public ParseNode {
861 public:
NullaryNode(ParseNodeKind kind,const TokenPos & pos)862 NullaryNode(ParseNodeKind kind, const TokenPos& pos) : ParseNode(kind, pos) {
863 MOZ_ASSERT(is<NullaryNode>());
864 }
865
test(const ParseNode & node)866 static bool test(const ParseNode& node) {
867 return node.typeCode() == TypeCode::Nullary;
868 }
869
classTypeCode()870 static constexpr TypeCode classTypeCode() { return TypeCode::Nullary; }
871
872 template <typename Visitor>
accept(Visitor & visitor)873 bool accept(Visitor& visitor) {
874 return true;
875 }
876
877 #ifdef DEBUG
878 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
879 #endif
880 };
881
882 class NameNode : public ParseNode {
883 TaggedParserAtomIndex atom_; /* lexical name or label atom */
884 PrivateNameKind privateNameKind_ = PrivateNameKind::None;
885
886 public:
NameNode(ParseNodeKind kind,TaggedParserAtomIndex atom,const TokenPos & pos)887 NameNode(ParseNodeKind kind, TaggedParserAtomIndex atom, const TokenPos& pos)
888 : ParseNode(kind, pos), atom_(atom) {
889 MOZ_ASSERT(atom);
890 MOZ_ASSERT(is<NameNode>());
891 }
892
test(const ParseNode & node)893 static bool test(const ParseNode& node) {
894 return node.typeCode() == TypeCode::Name;
895 }
896
classTypeCode()897 static constexpr TypeCode classTypeCode() { return TypeCode::Name; }
898
899 template <typename Visitor>
accept(Visitor & visitor)900 bool accept(Visitor& visitor) {
901 return true;
902 }
903
904 #ifdef DEBUG
905 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
906 #endif
907
atom()908 TaggedParserAtomIndex atom() const { return atom_; }
909
name()910 TaggedParserAtomIndex name() const {
911 MOZ_ASSERT(isKind(ParseNodeKind::Name) ||
912 isKind(ParseNodeKind::PrivateName));
913 return atom_;
914 }
915
setAtom(TaggedParserAtomIndex atom)916 void setAtom(TaggedParserAtomIndex atom) { atom_ = atom; }
917
setPrivateNameKind(PrivateNameKind privateNameKind)918 void setPrivateNameKind(PrivateNameKind privateNameKind) {
919 privateNameKind_ = privateNameKind;
920 }
921
privateNameKind()922 PrivateNameKind privateNameKind() { return privateNameKind_; }
923 };
924
isName(TaggedParserAtomIndex name)925 inline bool ParseNode::isName(TaggedParserAtomIndex name) const {
926 return getKind() == ParseNodeKind::Name && as<NameNode>().name() == name;
927 }
928
929 class UnaryNode : public ParseNode {
930 ParseNode* kid_;
931
932 public:
UnaryNode(ParseNodeKind kind,const TokenPos & pos,ParseNode * kid)933 UnaryNode(ParseNodeKind kind, const TokenPos& pos, ParseNode* kid)
934 : ParseNode(kind, pos), kid_(kid) {
935 MOZ_ASSERT(is<UnaryNode>());
936 }
937
test(const ParseNode & node)938 static bool test(const ParseNode& node) {
939 return node.typeCode() == TypeCode::Unary;
940 }
941
classTypeCode()942 static constexpr TypeCode classTypeCode() { return TypeCode::Unary; }
943
944 template <typename Visitor>
accept(Visitor & visitor)945 bool accept(Visitor& visitor) {
946 if (kid_) {
947 if (!visitor.visit(kid_)) {
948 return false;
949 }
950 }
951 return true;
952 }
953
954 #ifdef DEBUG
955 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
956 #endif
957
kid()958 ParseNode* kid() const { return kid_; }
959
960 /*
961 * Non-null if this is a statement node which could be a member of a
962 * Directive Prologue: an expression statement consisting of a single
963 * string literal.
964 *
965 * This considers only the node and its children, not its context. After
966 * parsing, check the node's prologue flag to see if it is indeed part of
967 * a directive prologue.
968 *
969 * Note that a Directive Prologue can contain statements that cannot
970 * themselves be directives (string literals that include escape sequences
971 * or escaped newlines, say). This member function returns true for such
972 * nodes; we use it to determine the extent of the prologue.
973 */
isStringExprStatement()974 TaggedParserAtomIndex isStringExprStatement() const {
975 if (isKind(ParseNodeKind::ExpressionStmt)) {
976 if (kid()->isKind(ParseNodeKind::StringExpr) && !kid()->isInParens()) {
977 return kid()->as<NameNode>().atom();
978 }
979 }
980 return TaggedParserAtomIndex::null();
981 }
982
983 // Methods used by FoldConstants.cpp.
unsafeKidReference()984 ParseNode** unsafeKidReference() { return &kid_; }
985
setSyntheticComputedName()986 void setSyntheticComputedName() { pn_synthetic_computed = true; }
isSyntheticComputedName()987 bool isSyntheticComputedName() {
988 MOZ_ASSERT(isKind(ParseNodeKind::ComputedName));
989 return pn_synthetic_computed;
990 }
991 };
992
993 class BinaryNode : public ParseNode {
994 ParseNode* left_;
995 ParseNode* right_;
996
997 public:
BinaryNode(ParseNodeKind kind,const TokenPos & pos,ParseNode * left,ParseNode * right)998 BinaryNode(ParseNodeKind kind, const TokenPos& pos, ParseNode* left,
999 ParseNode* right)
1000 : ParseNode(kind, pos), left_(left), right_(right) {
1001 MOZ_ASSERT(is<BinaryNode>());
1002 }
1003
BinaryNode(ParseNodeKind kind,ParseNode * left,ParseNode * right)1004 BinaryNode(ParseNodeKind kind, ParseNode* left, ParseNode* right)
1005 : ParseNode(kind, TokenPos::box(left->pn_pos, right->pn_pos)),
1006 left_(left),
1007 right_(right) {
1008 MOZ_ASSERT(is<BinaryNode>());
1009 }
1010
test(const ParseNode & node)1011 static bool test(const ParseNode& node) {
1012 return node.typeCode() == TypeCode::Binary;
1013 }
1014
classTypeCode()1015 static constexpr TypeCode classTypeCode() { return TypeCode::Binary; }
1016
1017 template <typename Visitor>
accept(Visitor & visitor)1018 bool accept(Visitor& visitor) {
1019 if (left_) {
1020 if (!visitor.visit(left_)) {
1021 return false;
1022 }
1023 }
1024 if (right_) {
1025 if (!visitor.visit(right_)) {
1026 return false;
1027 }
1028 }
1029 return true;
1030 }
1031
1032 #ifdef DEBUG
1033 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1034 #endif
1035
left()1036 ParseNode* left() const { return left_; }
1037
right()1038 ParseNode* right() const { return right_; }
1039
1040 // Methods used by FoldConstants.cpp.
1041 // callers are responsible for keeping the list consistent.
unsafeLeftReference()1042 ParseNode** unsafeLeftReference() { return &left_; }
1043
unsafeRightReference()1044 ParseNode** unsafeRightReference() { return &right_; }
1045 };
1046
1047 class AssignmentNode : public BinaryNode {
1048 public:
AssignmentNode(ParseNodeKind kind,ParseNode * left,ParseNode * right)1049 AssignmentNode(ParseNodeKind kind, ParseNode* left, ParseNode* right)
1050 : BinaryNode(kind, TokenPos(left->pn_pos.begin, right->pn_pos.end), left,
1051 right) {}
1052
test(const ParseNode & node)1053 static bool test(const ParseNode& node) {
1054 ParseNodeKind kind = node.getKind();
1055 bool match = ParseNodeKind::AssignmentStart <= kind &&
1056 kind <= ParseNodeKind::AssignmentLast;
1057 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1058 return match;
1059 }
1060 };
1061
1062 class ForNode : public BinaryNode {
1063 unsigned iflags_; /* JSITER_* flags */
1064
1065 public:
ForNode(const TokenPos & pos,ParseNode * forHead,ParseNode * body,unsigned iflags)1066 ForNode(const TokenPos& pos, ParseNode* forHead, ParseNode* body,
1067 unsigned iflags)
1068 : BinaryNode(ParseNodeKind::ForStmt, pos, forHead, body),
1069 iflags_(iflags) {
1070 MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
1071 forHead->isKind(ParseNodeKind::ForOf) ||
1072 forHead->isKind(ParseNodeKind::ForHead));
1073 }
1074
test(const ParseNode & node)1075 static bool test(const ParseNode& node) {
1076 bool match = node.isKind(ParseNodeKind::ForStmt);
1077 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1078 return match;
1079 }
1080
head()1081 TernaryNode* head() const { return &left()->as<TernaryNode>(); }
1082
body()1083 ParseNode* body() const { return right(); }
1084
iflags()1085 unsigned iflags() const { return iflags_; }
1086 };
1087
1088 class TernaryNode : public ParseNode {
1089 ParseNode* kid1_; /* condition, discriminant, etc. */
1090 ParseNode* kid2_; /* then-part, case list, etc. */
1091 ParseNode* kid3_; /* else-part, default case, etc. */
1092
1093 public:
TernaryNode(ParseNodeKind kind,ParseNode * kid1,ParseNode * kid2,ParseNode * kid3)1094 TernaryNode(ParseNodeKind kind, ParseNode* kid1, ParseNode* kid2,
1095 ParseNode* kid3)
1096 : TernaryNode(kind, kid1, kid2, kid3,
1097 TokenPos((kid1 ? kid1
1098 : kid2 ? kid2
1099 : kid3)
1100 ->pn_pos.begin,
1101 (kid3 ? kid3
1102 : kid2 ? kid2
1103 : kid1)
1104 ->pn_pos.end)) {}
1105
TernaryNode(ParseNodeKind kind,ParseNode * kid1,ParseNode * kid2,ParseNode * kid3,const TokenPos & pos)1106 TernaryNode(ParseNodeKind kind, ParseNode* kid1, ParseNode* kid2,
1107 ParseNode* kid3, const TokenPos& pos)
1108 : ParseNode(kind, pos), kid1_(kid1), kid2_(kid2), kid3_(kid3) {
1109 MOZ_ASSERT(is<TernaryNode>());
1110 }
1111
test(const ParseNode & node)1112 static bool test(const ParseNode& node) {
1113 return node.typeCode() == TypeCode::Ternary;
1114 }
1115
classTypeCode()1116 static constexpr TypeCode classTypeCode() { return TypeCode::Ternary; }
1117
1118 template <typename Visitor>
accept(Visitor & visitor)1119 bool accept(Visitor& visitor) {
1120 if (kid1_) {
1121 if (!visitor.visit(kid1_)) {
1122 return false;
1123 }
1124 }
1125 if (kid2_) {
1126 if (!visitor.visit(kid2_)) {
1127 return false;
1128 }
1129 }
1130 if (kid3_) {
1131 if (!visitor.visit(kid3_)) {
1132 return false;
1133 }
1134 }
1135 return true;
1136 }
1137
1138 #ifdef DEBUG
1139 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1140 #endif
1141
kid1()1142 ParseNode* kid1() const { return kid1_; }
1143
kid2()1144 ParseNode* kid2() const { return kid2_; }
1145
kid3()1146 ParseNode* kid3() const { return kid3_; }
1147
1148 // Methods used by FoldConstants.cpp.
unsafeKid1Reference()1149 ParseNode** unsafeKid1Reference() { return &kid1_; }
1150
unsafeKid2Reference()1151 ParseNode** unsafeKid2Reference() { return &kid2_; }
1152
unsafeKid3Reference()1153 ParseNode** unsafeKid3Reference() { return &kid3_; }
1154 };
1155
1156 class ListNode : public ParseNode {
1157 ParseNode* head_; /* first node in list */
1158 ParseNode** tail_; /* ptr to last node's pn_next in list */
1159 uint32_t count_; /* number of nodes in list */
1160 uint32_t xflags;
1161
1162 private:
1163 // xflags bits.
1164
1165 // Statement list has top-level function statements.
1166 static constexpr uint32_t hasTopLevelFunctionDeclarationsBit = Bit(0);
1167
1168 // Array/Object/Class initializer has non-constants.
1169 // * array has holes
1170 // * array has spread node
1171 // * array has element which is known not to be constant
1172 // * array has no element
1173 // * object/class has __proto__
1174 // * object/class has property which is known not to be constant
1175 // * object/class shorthand property
1176 // * object/class spread property
1177 // * object/class has method
1178 // * object/class has computed property
1179 static constexpr uint32_t hasNonConstInitializerBit = Bit(1);
1180
1181 // Flag set by the emitter after emitting top-level function statements.
1182 static constexpr uint32_t emittedTopLevelFunctionDeclarationsBit = Bit(2);
1183
1184 public:
ListNode(ParseNodeKind kind,const TokenPos & pos)1185 ListNode(ParseNodeKind kind, const TokenPos& pos) : ParseNode(kind, pos) {
1186 makeEmpty();
1187 MOZ_ASSERT(is<ListNode>());
1188 }
1189
ListNode(ParseNodeKind kind,ParseNode * kid)1190 ListNode(ParseNodeKind kind, ParseNode* kid)
1191 : ParseNode(kind, kid->pn_pos),
1192 head_(kid),
1193 tail_(&kid->pn_next),
1194 count_(1),
1195 xflags(0) {
1196 if (kid->pn_pos.begin < pn_pos.begin) {
1197 pn_pos.begin = kid->pn_pos.begin;
1198 }
1199 pn_pos.end = kid->pn_pos.end;
1200
1201 MOZ_ASSERT(is<ListNode>());
1202 }
1203
test(const ParseNode & node)1204 static bool test(const ParseNode& node) {
1205 return node.typeCode() == TypeCode::List;
1206 }
1207
classTypeCode()1208 static constexpr TypeCode classTypeCode() { return TypeCode::List; }
1209
1210 template <typename Visitor>
accept(Visitor & visitor)1211 bool accept(Visitor& visitor) {
1212 ParseNode** listp = &head_;
1213 for (; *listp; listp = &(*listp)->pn_next) {
1214 // Don't use PN*& because we want to check if it changed, so we can use
1215 // ReplaceNode
1216 ParseNode* pn = *listp;
1217 if (!visitor.visit(pn)) {
1218 return false;
1219 }
1220 if (pn != *listp) {
1221 ReplaceNode(listp, pn);
1222 }
1223 }
1224 unsafeReplaceTail(listp);
1225 return true;
1226 }
1227
1228 #ifdef DEBUG
1229 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1230 #endif
1231
head()1232 ParseNode* head() const { return head_; }
1233
tail()1234 ParseNode** tail() const { return tail_; }
1235
count()1236 uint32_t count() const { return count_; }
1237
empty()1238 bool empty() const { return count() == 0; }
1239
checkConsistency()1240 void checkConsistency() const
1241 #ifndef DEBUG
1242 {
1243 }
1244 #endif
1245 ;
1246
hasTopLevelFunctionDeclarations()1247 [[nodiscard]] bool hasTopLevelFunctionDeclarations() const {
1248 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1249 return xflags & hasTopLevelFunctionDeclarationsBit;
1250 }
1251
emittedTopLevelFunctionDeclarations()1252 [[nodiscard]] bool emittedTopLevelFunctionDeclarations() const {
1253 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1254 MOZ_ASSERT(hasTopLevelFunctionDeclarations());
1255 return xflags & emittedTopLevelFunctionDeclarationsBit;
1256 }
1257
hasNonConstInitializer()1258 [[nodiscard]] bool hasNonConstInitializer() const {
1259 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1260 isKind(ParseNodeKind::ObjectExpr));
1261 return xflags & hasNonConstInitializerBit;
1262 }
1263
setHasTopLevelFunctionDeclarations()1264 void setHasTopLevelFunctionDeclarations() {
1265 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1266 xflags |= hasTopLevelFunctionDeclarationsBit;
1267 }
1268
setEmittedTopLevelFunctionDeclarations()1269 void setEmittedTopLevelFunctionDeclarations() {
1270 MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
1271 MOZ_ASSERT(hasTopLevelFunctionDeclarations());
1272 xflags |= emittedTopLevelFunctionDeclarationsBit;
1273 }
1274
setHasNonConstInitializer()1275 void setHasNonConstInitializer() {
1276 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1277 isKind(ParseNodeKind::ObjectExpr));
1278 xflags |= hasNonConstInitializerBit;
1279 }
1280
unsetHasNonConstInitializer()1281 void unsetHasNonConstInitializer() {
1282 MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
1283 isKind(ParseNodeKind::ObjectExpr));
1284 xflags &= ~hasNonConstInitializerBit;
1285 }
1286
1287 /*
1288 * Compute a pointer to the last element in a singly-linked list. NB: list
1289 * must be non-empty -- this is asserted!
1290 */
last()1291 ParseNode* last() const {
1292 MOZ_ASSERT(!empty());
1293 //
1294 // ParseNode ParseNode
1295 // +-----+---------+-----+ +-----+---------+-----+
1296 // | ... | pn_next | ... | +-...->| ... | pn_next | ... |
1297 // +-----+---------+-----+ | +-----+---------+-----+
1298 // ^ | | ^ ^
1299 // | +---------------+ | |
1300 // | | tail()
1301 // | |
1302 // head() last()
1303 //
1304 return (ParseNode*)(uintptr_t(tail()) - offsetof(ParseNode, pn_next));
1305 }
1306
replaceLast(ParseNode * node)1307 void replaceLast(ParseNode* node) {
1308 MOZ_ASSERT(!empty());
1309 pn_pos.end = node->pn_pos.end;
1310
1311 ParseNode* item = head();
1312 ParseNode* lastNode = last();
1313 MOZ_ASSERT(item);
1314 if (item == lastNode) {
1315 head_ = node;
1316 } else {
1317 while (item->pn_next != lastNode) {
1318 MOZ_ASSERT(item->pn_next);
1319 item = item->pn_next;
1320 }
1321 item->pn_next = node;
1322 }
1323 tail_ = &node->pn_next;
1324 }
1325
makeEmpty()1326 void makeEmpty() {
1327 head_ = nullptr;
1328 tail_ = &head_;
1329 count_ = 0;
1330 xflags = 0;
1331 }
1332
append(ParseNode * item)1333 void append(ParseNode* item) {
1334 MOZ_ASSERT(item->pn_pos.begin >= pn_pos.begin);
1335 pn_pos.end = item->pn_pos.end;
1336 *tail_ = item;
1337 tail_ = &item->pn_next;
1338 count_++;
1339 }
1340
prepend(ParseNode * item)1341 void prepend(ParseNode* item) {
1342 item->pn_next = head_;
1343 head_ = item;
1344 if (tail_ == &head_) {
1345 tail_ = &item->pn_next;
1346 }
1347 count_++;
1348 }
1349
prependAndUpdatePos(ParseNode * item)1350 void prependAndUpdatePos(ParseNode* item) {
1351 prepend(item);
1352 pn_pos.begin = item->pn_pos.begin;
1353 }
1354
1355 // Methods used by FoldConstants.cpp.
1356 // Caller is responsible for keeping the list consistent.
unsafeHeadReference()1357 ParseNode** unsafeHeadReference() { return &head_; }
1358
unsafeReplaceTail(ParseNode ** newTail)1359 void unsafeReplaceTail(ParseNode** newTail) {
1360 tail_ = newTail;
1361 checkConsistency();
1362 }
1363
unsafeDecrementCount()1364 void unsafeDecrementCount() {
1365 MOZ_ASSERT(count() > 1);
1366 count_--;
1367 }
1368
1369 private:
1370 // Classes to iterate over ListNode contents:
1371 //
1372 // Usage:
1373 // ListNode* list;
1374 // for (ParseNode* item : list->contents()) {
1375 // // item is ParseNode* typed.
1376 // }
1377 class iterator {
1378 private:
1379 ParseNode* node_;
1380
1381 friend class ListNode;
iterator(ParseNode * node)1382 explicit iterator(ParseNode* node) : node_(node) {}
1383
1384 public:
1385 // Implement std::iterator_traits.
1386 using iterator_category = std::input_iterator_tag;
1387 using value_type = ParseNode*;
1388 using difference_type = ptrdiff_t;
1389 using pointer = ParseNode**;
1390 using reference = ParseNode*&;
1391
1392 bool operator==(const iterator& other) const {
1393 return node_ == other.node_;
1394 }
1395
1396 bool operator!=(const iterator& other) const { return !(*this == other); }
1397
1398 iterator& operator++() {
1399 node_ = node_->pn_next;
1400 return *this;
1401 }
1402
1403 ParseNode* operator*() { return node_; }
1404
1405 const ParseNode* operator*() const { return node_; }
1406 };
1407
1408 class range {
1409 private:
1410 ParseNode* begin_;
1411 ParseNode* end_;
1412
1413 friend class ListNode;
range(ParseNode * begin,ParseNode * end)1414 range(ParseNode* begin, ParseNode* end) : begin_(begin), end_(end) {}
1415
1416 public:
begin()1417 iterator begin() { return iterator(begin_); }
1418
end()1419 iterator end() { return iterator(end_); }
1420
begin()1421 const iterator begin() const { return iterator(begin_); }
1422
end()1423 const iterator end() const { return iterator(end_); }
1424
cbegin()1425 const iterator cbegin() const { return begin(); }
1426
cend()1427 const iterator cend() const { return end(); }
1428 };
1429
1430 #ifdef DEBUG
contains(ParseNode * target)1431 [[nodiscard]] bool contains(ParseNode* target) const {
1432 MOZ_ASSERT(target);
1433 for (ParseNode* node : contents()) {
1434 if (target == node) {
1435 return true;
1436 }
1437 }
1438 return false;
1439 }
1440 #endif
1441
1442 public:
contents()1443 range contents() { return range(head(), nullptr); }
1444
contents()1445 const range contents() const { return range(head(), nullptr); }
1446
contentsFrom(ParseNode * begin)1447 range contentsFrom(ParseNode* begin) {
1448 MOZ_ASSERT_IF(begin, contains(begin));
1449 return range(begin, nullptr);
1450 }
1451
contentsFrom(ParseNode * begin)1452 const range contentsFrom(ParseNode* begin) const {
1453 MOZ_ASSERT_IF(begin, contains(begin));
1454 return range(begin, nullptr);
1455 }
1456
contentsTo(ParseNode * end)1457 range contentsTo(ParseNode* end) {
1458 MOZ_ASSERT_IF(end, contains(end));
1459 return range(head(), end);
1460 }
1461
contentsTo(ParseNode * end)1462 const range contentsTo(ParseNode* end) const {
1463 MOZ_ASSERT_IF(end, contains(end));
1464 return range(head(), end);
1465 }
1466 };
1467
isForLoopDeclaration()1468 inline bool ParseNode::isForLoopDeclaration() const {
1469 if (isKind(ParseNodeKind::VarStmt) || isKind(ParseNodeKind::LetDecl) ||
1470 isKind(ParseNodeKind::ConstDecl)) {
1471 MOZ_ASSERT(!as<ListNode>().empty());
1472 return true;
1473 }
1474
1475 return false;
1476 }
1477
1478 class FunctionNode : public ParseNode {
1479 FunctionBox* funbox_;
1480 ParseNode* body_;
1481 FunctionSyntaxKind syntaxKind_;
1482
1483 public:
FunctionNode(FunctionSyntaxKind syntaxKind,const TokenPos & pos)1484 FunctionNode(FunctionSyntaxKind syntaxKind, const TokenPos& pos)
1485 : ParseNode(ParseNodeKind::Function, pos),
1486 funbox_(nullptr),
1487 body_(nullptr),
1488 syntaxKind_(syntaxKind) {
1489 MOZ_ASSERT(!body_);
1490 MOZ_ASSERT(!funbox_);
1491 MOZ_ASSERT(is<FunctionNode>());
1492 }
1493
test(const ParseNode & node)1494 static bool test(const ParseNode& node) {
1495 return node.isKind(ParseNodeKind::Function);
1496 }
1497
classTypeCode()1498 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1499
1500 template <typename Visitor>
accept(Visitor & visitor)1501 bool accept(Visitor& visitor) {
1502 // Note: body is null for lazily-parsed functions.
1503 if (body_) {
1504 if (!visitor.visit(body_)) {
1505 return false;
1506 }
1507 }
1508 return true;
1509 }
1510
1511 #ifdef DEBUG
1512 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1513 #endif
1514
funbox()1515 FunctionBox* funbox() const { return funbox_; }
1516
body()1517 ListNode* body() const { return body_ ? &body_->as<ListNode>() : nullptr; }
1518
setFunbox(FunctionBox * funbox)1519 void setFunbox(FunctionBox* funbox) { funbox_ = funbox; }
1520
setBody(ListNode * body)1521 void setBody(ListNode* body) { body_ = body; }
1522
syntaxKind()1523 FunctionSyntaxKind syntaxKind() const { return syntaxKind_; }
1524
functionIsHoisted()1525 bool functionIsHoisted() const {
1526 return syntaxKind() == FunctionSyntaxKind::Statement;
1527 }
1528 };
1529
1530 class ModuleNode : public ParseNode {
1531 ParseNode* body_;
1532
1533 public:
ModuleNode(const TokenPos & pos)1534 explicit ModuleNode(const TokenPos& pos)
1535 : ParseNode(ParseNodeKind::Module, pos), body_(nullptr) {
1536 MOZ_ASSERT(!body_);
1537 MOZ_ASSERT(is<ModuleNode>());
1538 }
1539
test(const ParseNode & node)1540 static bool test(const ParseNode& node) {
1541 return node.isKind(ParseNodeKind::Module);
1542 }
1543
classTypeCode()1544 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1545
1546 template <typename Visitor>
accept(Visitor & visitor)1547 bool accept(Visitor& visitor) {
1548 return visitor.visit(body_);
1549 }
1550
1551 #ifdef DEBUG
1552 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1553 #endif
1554
body()1555 ListNode* body() const { return &body_->as<ListNode>(); }
1556
setBody(ListNode * body)1557 void setBody(ListNode* body) { body_ = body; }
1558 };
1559
1560 class NumericLiteral : public ParseNode {
1561 double value_; /* aligned numeric literal value */
1562 DecimalPoint decimalPoint_; /* Whether the number has a decimal point */
1563
1564 public:
NumericLiteral(double value,DecimalPoint decimalPoint,const TokenPos & pos)1565 NumericLiteral(double value, DecimalPoint decimalPoint, const TokenPos& pos)
1566 : ParseNode(ParseNodeKind::NumberExpr, pos),
1567 value_(value),
1568 decimalPoint_(decimalPoint) {}
1569
test(const ParseNode & node)1570 static bool test(const ParseNode& node) {
1571 return node.isKind(ParseNodeKind::NumberExpr);
1572 }
1573
classTypeCode()1574 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1575
1576 template <typename Visitor>
accept(Visitor & visitor)1577 bool accept(Visitor& visitor) {
1578 return true;
1579 }
1580
1581 #ifdef DEBUG
1582 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1583 #endif
1584
value()1585 double value() const { return value_; }
1586
decimalPoint()1587 DecimalPoint decimalPoint() const { return decimalPoint_; }
1588
setValue(double v)1589 void setValue(double v) { value_ = v; }
1590
setDecimalPoint(DecimalPoint d)1591 void setDecimalPoint(DecimalPoint d) { decimalPoint_ = d; }
1592
1593 // Return the decimal string representation of this numeric literal.
1594 TaggedParserAtomIndex toAtom(JSContext* cx,
1595 ParserAtomsTable& parserAtoms) const;
1596 };
1597
1598 class BigIntLiteral : public ParseNode {
1599 BigIntIndex index_;
1600 bool isZero_;
1601
1602 public:
BigIntLiteral(BigIntIndex index,bool isZero,const TokenPos & pos)1603 BigIntLiteral(BigIntIndex index, bool isZero, const TokenPos& pos)
1604 : ParseNode(ParseNodeKind::BigIntExpr, pos),
1605 index_(index),
1606 isZero_(isZero) {}
1607
test(const ParseNode & node)1608 static bool test(const ParseNode& node) {
1609 return node.isKind(ParseNodeKind::BigIntExpr);
1610 }
1611
classTypeCode()1612 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1613
1614 template <typename Visitor>
accept(Visitor & visitor)1615 bool accept(Visitor& visitor) {
1616 return true;
1617 }
1618
1619 #ifdef DEBUG
1620 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1621 #endif
1622
index()1623 BigIntIndex index() { return index_; }
1624
isZero()1625 bool isZero() const { return isZero_; }
1626 };
1627
1628 template <ParseNodeKind NodeKind, typename ScopeType>
1629 class BaseScopeNode : public ParseNode {
1630 using ParserData = typename ScopeType::ParserData;
1631 ParserData* bindings;
1632 ParseNode* body;
1633 ScopeKind kind_;
1634
1635 public:
1636 BaseScopeNode(ParserData* bindings, ParseNode* body,
1637 ScopeKind kind = ScopeKind::Lexical)
1638 : ParseNode(NodeKind, body->pn_pos),
1639 bindings(bindings),
1640 body(body),
1641 kind_(kind) {}
1642
test(const ParseNode & node)1643 static bool test(const ParseNode& node) { return node.isKind(NodeKind); }
1644
classTypeCode()1645 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1646
1647 template <typename Visitor>
accept(Visitor & visitor)1648 bool accept(Visitor& visitor) {
1649 return visitor.visit(body);
1650 }
1651
1652 #ifdef DEBUG
1653 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1654 #endif
1655
scopeBindings()1656 ParserData* scopeBindings() const {
1657 MOZ_ASSERT(!isEmptyScope());
1658 return bindings;
1659 }
1660
scopeBody()1661 ParseNode* scopeBody() const { return body; }
1662
setScopeBody(ParseNode * body)1663 void setScopeBody(ParseNode* body) { this->body = body; }
1664
isEmptyScope()1665 bool isEmptyScope() const { return !bindings; }
1666
kind()1667 ScopeKind kind() const { return kind_; }
1668 };
1669
1670 class LexicalScopeNode
1671 : public BaseScopeNode<ParseNodeKind::LexicalScope, LexicalScope> {
1672 public:
1673 LexicalScopeNode(LexicalScope::ParserData* bindings, ParseNode* body,
1674 ScopeKind kind = ScopeKind::Lexical)
BaseScopeNode(bindings,body,kind)1675 : BaseScopeNode(bindings, body, kind) {}
1676 };
1677
1678 class ClassBodyScopeNode
1679 : public BaseScopeNode<ParseNodeKind::ClassBodyScope, ClassBodyScope> {
1680 public:
ClassBodyScopeNode(ClassBodyScope::ParserData * bindings,ListNode * memberList)1681 ClassBodyScopeNode(ClassBodyScope::ParserData* bindings, ListNode* memberList)
1682 : BaseScopeNode(bindings, memberList, ScopeKind::ClassBody) {
1683 MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
1684 }
1685
memberList()1686 ListNode* memberList() const {
1687 ListNode* list = &scopeBody()->as<ListNode>();
1688 MOZ_ASSERT(list->isKind(ParseNodeKind::ClassMemberList));
1689 return list;
1690 }
1691 };
1692
1693 class LabeledStatement : public NameNode {
1694 ParseNode* statement_;
1695
1696 public:
LabeledStatement(TaggedParserAtomIndex label,ParseNode * stmt,uint32_t begin)1697 LabeledStatement(TaggedParserAtomIndex label, ParseNode* stmt, uint32_t begin)
1698 : NameNode(ParseNodeKind::LabelStmt, label,
1699 TokenPos(begin, stmt->pn_pos.end)),
1700 statement_(stmt) {}
1701
label()1702 TaggedParserAtomIndex label() const { return atom(); }
1703
statement()1704 ParseNode* statement() const { return statement_; }
1705
test(const ParseNode & node)1706 static bool test(const ParseNode& node) {
1707 return node.isKind(ParseNodeKind::LabelStmt);
1708 }
1709
1710 template <typename Visitor>
accept(Visitor & visitor)1711 bool accept(Visitor& visitor) {
1712 if (statement_) {
1713 if (!visitor.visit(statement_)) {
1714 return false;
1715 }
1716 }
1717 return true;
1718 }
1719
1720 #ifdef DEBUG
1721 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1722 #endif
1723 };
1724
1725 // Inside a switch statement, a CaseClause is a case-label and the subsequent
1726 // statements. The same node type is used for DefaultClauses. The only
1727 // difference is that their caseExpression() is null.
1728 class CaseClause : public BinaryNode {
1729 public:
CaseClause(ParseNode * expr,ParseNode * stmts,uint32_t begin)1730 CaseClause(ParseNode* expr, ParseNode* stmts, uint32_t begin)
1731 : BinaryNode(ParseNodeKind::Case, TokenPos(begin, stmts->pn_pos.end),
1732 expr, stmts) {}
1733
caseExpression()1734 ParseNode* caseExpression() const { return left(); }
1735
isDefault()1736 bool isDefault() const { return !caseExpression(); }
1737
statementList()1738 ListNode* statementList() const { return &right()->as<ListNode>(); }
1739
test(const ParseNode & node)1740 static bool test(const ParseNode& node) {
1741 bool match = node.isKind(ParseNodeKind::Case);
1742 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1743 return match;
1744 }
1745 };
1746
1747 class LoopControlStatement : public ParseNode {
1748 TaggedParserAtomIndex label_; /* target of break/continue statement */
1749
1750 protected:
LoopControlStatement(ParseNodeKind kind,TaggedParserAtomIndex label,const TokenPos & pos)1751 LoopControlStatement(ParseNodeKind kind, TaggedParserAtomIndex label,
1752 const TokenPos& pos)
1753 : ParseNode(kind, pos), label_(label) {
1754 MOZ_ASSERT(kind == ParseNodeKind::BreakStmt ||
1755 kind == ParseNodeKind::ContinueStmt);
1756 MOZ_ASSERT(is<LoopControlStatement>());
1757 }
1758
1759 public:
1760 /* Label associated with this break/continue statement, if any. */
label()1761 TaggedParserAtomIndex label() const { return label_; }
1762
1763 #ifdef DEBUG
1764 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1765 #endif
1766
test(const ParseNode & node)1767 static bool test(const ParseNode& node) {
1768 return node.isKind(ParseNodeKind::BreakStmt) ||
1769 node.isKind(ParseNodeKind::ContinueStmt);
1770 }
1771
classTypeCode()1772 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1773
1774 template <typename Visitor>
accept(Visitor & visitor)1775 bool accept(Visitor& visitor) {
1776 return true;
1777 }
1778 };
1779
1780 class BreakStatement : public LoopControlStatement {
1781 public:
BreakStatement(TaggedParserAtomIndex label,const TokenPos & pos)1782 BreakStatement(TaggedParserAtomIndex label, const TokenPos& pos)
1783 : LoopControlStatement(ParseNodeKind::BreakStmt, label, pos) {}
1784
test(const ParseNode & node)1785 static bool test(const ParseNode& node) {
1786 bool match = node.isKind(ParseNodeKind::BreakStmt);
1787 MOZ_ASSERT_IF(match, node.is<LoopControlStatement>());
1788 return match;
1789 }
1790 };
1791
1792 class ContinueStatement : public LoopControlStatement {
1793 public:
ContinueStatement(TaggedParserAtomIndex label,const TokenPos & pos)1794 ContinueStatement(TaggedParserAtomIndex label, const TokenPos& pos)
1795 : LoopControlStatement(ParseNodeKind::ContinueStmt, label, pos) {}
1796
test(const ParseNode & node)1797 static bool test(const ParseNode& node) {
1798 bool match = node.isKind(ParseNodeKind::ContinueStmt);
1799 MOZ_ASSERT_IF(match, node.is<LoopControlStatement>());
1800 return match;
1801 }
1802 };
1803
1804 class DebuggerStatement : public NullaryNode {
1805 public:
DebuggerStatement(const TokenPos & pos)1806 explicit DebuggerStatement(const TokenPos& pos)
1807 : NullaryNode(ParseNodeKind::DebuggerStmt, pos) {}
1808
test(const ParseNode & node)1809 static bool test(const ParseNode& node) {
1810 bool match = node.isKind(ParseNodeKind::DebuggerStmt);
1811 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1812 return match;
1813 }
1814 };
1815
1816 class ConditionalExpression : public TernaryNode {
1817 public:
ConditionalExpression(ParseNode * condition,ParseNode * thenExpr,ParseNode * elseExpr)1818 ConditionalExpression(ParseNode* condition, ParseNode* thenExpr,
1819 ParseNode* elseExpr)
1820 : TernaryNode(ParseNodeKind::ConditionalExpr, condition, thenExpr,
1821 elseExpr,
1822 TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end)) {
1823 MOZ_ASSERT(condition);
1824 MOZ_ASSERT(thenExpr);
1825 MOZ_ASSERT(elseExpr);
1826 }
1827
condition()1828 ParseNode& condition() const { return *kid1(); }
1829
thenExpression()1830 ParseNode& thenExpression() const { return *kid2(); }
1831
elseExpression()1832 ParseNode& elseExpression() const { return *kid3(); }
1833
test(const ParseNode & node)1834 static bool test(const ParseNode& node) {
1835 bool match = node.isKind(ParseNodeKind::ConditionalExpr);
1836 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
1837 return match;
1838 }
1839 };
1840
1841 class TryNode : public TernaryNode {
1842 public:
TryNode(uint32_t begin,ParseNode * body,LexicalScopeNode * catchScope,ParseNode * finallyBlock)1843 TryNode(uint32_t begin, ParseNode* body, LexicalScopeNode* catchScope,
1844 ParseNode* finallyBlock)
1845 : TernaryNode(
1846 ParseNodeKind::TryStmt, body, catchScope, finallyBlock,
1847 TokenPos(begin,
1848 (finallyBlock ? finallyBlock : catchScope)->pn_pos.end)) {
1849 MOZ_ASSERT(body);
1850 MOZ_ASSERT(catchScope || finallyBlock);
1851 }
1852
test(const ParseNode & node)1853 static bool test(const ParseNode& node) {
1854 bool match = node.isKind(ParseNodeKind::TryStmt);
1855 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
1856 return match;
1857 }
1858
body()1859 ParseNode* body() const { return kid1(); }
1860
catchScope()1861 LexicalScopeNode* catchScope() const {
1862 return kid2() ? &kid2()->as<LexicalScopeNode>() : nullptr;
1863 }
1864
finallyBlock()1865 ParseNode* finallyBlock() const { return kid3(); }
1866 };
1867
1868 class ThisLiteral : public UnaryNode {
1869 public:
ThisLiteral(const TokenPos & pos,ParseNode * thisName)1870 ThisLiteral(const TokenPos& pos, ParseNode* thisName)
1871 : UnaryNode(ParseNodeKind::ThisExpr, pos, thisName) {}
1872
test(const ParseNode & node)1873 static bool test(const ParseNode& node) {
1874 bool match = node.isKind(ParseNodeKind::ThisExpr);
1875 MOZ_ASSERT_IF(match, node.is<UnaryNode>());
1876 return match;
1877 }
1878 };
1879
1880 class NullLiteral : public NullaryNode {
1881 public:
NullLiteral(const TokenPos & pos)1882 explicit NullLiteral(const TokenPos& pos)
1883 : NullaryNode(ParseNodeKind::NullExpr, pos) {}
1884
test(const ParseNode & node)1885 static bool test(const ParseNode& node) {
1886 bool match = node.isKind(ParseNodeKind::NullExpr);
1887 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1888 return match;
1889 }
1890 };
1891
1892 // This is only used internally, currently just for tagged templates and the
1893 // initial value of fields without initializers. It represents the value
1894 // 'undefined' (aka `void 0`), like NullLiteral represents the value 'null'.
1895 class RawUndefinedLiteral : public NullaryNode {
1896 public:
RawUndefinedLiteral(const TokenPos & pos)1897 explicit RawUndefinedLiteral(const TokenPos& pos)
1898 : NullaryNode(ParseNodeKind::RawUndefinedExpr, pos) {}
1899
test(const ParseNode & node)1900 static bool test(const ParseNode& node) {
1901 bool match = node.isKind(ParseNodeKind::RawUndefinedExpr);
1902 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1903 return match;
1904 }
1905 };
1906
1907 class BooleanLiteral : public NullaryNode {
1908 public:
BooleanLiteral(bool b,const TokenPos & pos)1909 BooleanLiteral(bool b, const TokenPos& pos)
1910 : NullaryNode(b ? ParseNodeKind::TrueExpr : ParseNodeKind::FalseExpr,
1911 pos) {}
1912
test(const ParseNode & node)1913 static bool test(const ParseNode& node) {
1914 bool match = node.isKind(ParseNodeKind::TrueExpr) ||
1915 node.isKind(ParseNodeKind::FalseExpr);
1916 MOZ_ASSERT_IF(match, node.is<NullaryNode>());
1917 return match;
1918 }
1919 };
1920
1921 class RegExpLiteral : public ParseNode {
1922 RegExpIndex index_;
1923
1924 public:
RegExpLiteral(RegExpIndex dataIndex,const TokenPos & pos)1925 RegExpLiteral(RegExpIndex dataIndex, const TokenPos& pos)
1926 : ParseNode(ParseNodeKind::RegExpExpr, pos), index_(dataIndex) {}
1927
1928 // Create a RegExp object of this RegExp literal.
1929 RegExpObject* create(JSContext* cx, ParserAtomsTable& parserAtoms,
1930 CompilationAtomCache& atomCache,
1931 ExtensibleCompilationStencil& stencil) const;
1932
1933 #ifdef DEBUG
1934 void dumpImpl(ParserBase* parser, GenericPrinter& out, int indent);
1935 #endif
1936
test(const ParseNode & node)1937 static bool test(const ParseNode& node) {
1938 return node.isKind(ParseNodeKind::RegExpExpr);
1939 }
1940
classTypeCode()1941 static constexpr TypeCode classTypeCode() { return TypeCode::Other; }
1942
1943 template <typename Visitor>
accept(Visitor & visitor)1944 bool accept(Visitor& visitor) {
1945 return true;
1946 }
1947
index()1948 RegExpIndex index() { return index_; }
1949 };
1950
1951 class PropertyAccessBase : public BinaryNode {
1952 public:
1953 /*
1954 * PropertyAccess nodes can have any expression/'super' as left-hand
1955 * side, but the name must be a ParseNodeKind::PropertyName node.
1956 */
PropertyAccessBase(ParseNodeKind kind,ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)1957 PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, NameNode* name,
1958 uint32_t begin, uint32_t end)
1959 : BinaryNode(kind, TokenPos(begin, end), lhs, name) {
1960 MOZ_ASSERT(lhs);
1961 MOZ_ASSERT(name);
1962 }
1963
expression()1964 ParseNode& expression() const { return *left(); }
1965
test(const ParseNode & node)1966 static bool test(const ParseNode& node) {
1967 bool match = node.isKind(ParseNodeKind::DotExpr) ||
1968 node.isKind(ParseNodeKind::OptionalDotExpr);
1969 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
1970 MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
1971 ParseNodeKind::PropertyNameExpr));
1972 return match;
1973 }
1974
key()1975 NameNode& key() const { return right()->as<NameNode>(); }
1976
1977 // Method used by BytecodeEmitter::emitPropLHS for optimization.
1978 // Those methods allow expression to temporarily be nullptr for
1979 // optimization purpose.
maybeExpression()1980 ParseNode* maybeExpression() const { return left(); }
1981
setExpression(ParseNode * pn)1982 void setExpression(ParseNode* pn) { *unsafeLeftReference() = pn; }
1983
name()1984 TaggedParserAtomIndex name() const { return right()->as<NameNode>().atom(); }
1985 };
1986
1987 class PropertyAccess : public PropertyAccessBase {
1988 public:
PropertyAccess(ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)1989 PropertyAccess(ParseNode* lhs, NameNode* name, uint32_t begin, uint32_t end)
1990 : PropertyAccessBase(ParseNodeKind::DotExpr, lhs, name, begin, end) {
1991 MOZ_ASSERT(lhs);
1992 MOZ_ASSERT(name);
1993 }
1994
test(const ParseNode & node)1995 static bool test(const ParseNode& node) {
1996 bool match = node.isKind(ParseNodeKind::DotExpr);
1997 MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
1998 return match;
1999 }
2000
isSuper()2001 bool isSuper() const {
2002 // ParseNodeKind::SuperBase cannot result from any expression syntax.
2003 return expression().isKind(ParseNodeKind::SuperBase);
2004 }
2005 };
2006
2007 class OptionalPropertyAccess : public PropertyAccessBase {
2008 public:
OptionalPropertyAccess(ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)2009 OptionalPropertyAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2010 uint32_t end)
2011 : PropertyAccessBase(ParseNodeKind::OptionalDotExpr, lhs, name, begin,
2012 end) {
2013 MOZ_ASSERT(lhs);
2014 MOZ_ASSERT(name);
2015 }
2016
test(const ParseNode & node)2017 static bool test(const ParseNode& node) {
2018 bool match = node.isKind(ParseNodeKind::OptionalDotExpr);
2019 MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
2020 return match;
2021 }
2022 };
2023
2024 class PropertyByValueBase : public BinaryNode {
2025 public:
PropertyByValueBase(ParseNodeKind kind,ParseNode * lhs,ParseNode * propExpr,uint32_t begin,uint32_t end)2026 PropertyByValueBase(ParseNodeKind kind, ParseNode* lhs, ParseNode* propExpr,
2027 uint32_t begin, uint32_t end)
2028 : BinaryNode(kind, TokenPos(begin, end), lhs, propExpr) {}
2029
test(const ParseNode & node)2030 static bool test(const ParseNode& node) {
2031 bool match = node.isKind(ParseNodeKind::ElemExpr) ||
2032 node.isKind(ParseNodeKind::OptionalElemExpr);
2033 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2034 return match;
2035 }
2036
expression()2037 ParseNode& expression() const { return *left(); }
2038
key()2039 ParseNode& key() const { return *right(); }
2040 };
2041
2042 class PropertyByValue : public PropertyByValueBase {
2043 public:
PropertyByValue(ParseNode * lhs,ParseNode * propExpr,uint32_t begin,uint32_t end)2044 PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin,
2045 uint32_t end)
2046 : PropertyByValueBase(ParseNodeKind::ElemExpr, lhs, propExpr, begin,
2047 end) {}
2048
test(const ParseNode & node)2049 static bool test(const ParseNode& node) {
2050 bool match = node.isKind(ParseNodeKind::ElemExpr);
2051 MOZ_ASSERT_IF(match, node.is<PropertyByValueBase>());
2052 return match;
2053 }
2054
isSuper()2055 bool isSuper() const { return left()->isKind(ParseNodeKind::SuperBase); }
2056 };
2057
2058 class OptionalPropertyByValue : public PropertyByValueBase {
2059 public:
OptionalPropertyByValue(ParseNode * lhs,ParseNode * propExpr,uint32_t begin,uint32_t end)2060 OptionalPropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin,
2061 uint32_t end)
2062 : PropertyByValueBase(ParseNodeKind::OptionalElemExpr, lhs, propExpr,
2063 begin, end) {}
2064
test(const ParseNode & node)2065 static bool test(const ParseNode& node) {
2066 bool match = node.isKind(ParseNodeKind::OptionalElemExpr);
2067 MOZ_ASSERT_IF(match, node.is<PropertyByValueBase>());
2068 return match;
2069 }
2070 };
2071
2072 class PrivateMemberAccessBase : public BinaryNode {
2073 public:
PrivateMemberAccessBase(ParseNodeKind kind,ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)2074 PrivateMemberAccessBase(ParseNodeKind kind, ParseNode* lhs, NameNode* name,
2075 uint32_t begin, uint32_t end)
2076 : BinaryNode(kind, TokenPos(begin, end), lhs, name) {
2077 MOZ_ASSERT(name->isKind(ParseNodeKind::PrivateName));
2078 }
2079
expression()2080 ParseNode& expression() const { return *left(); }
2081
privateName()2082 NameNode& privateName() const {
2083 NameNode& name = right()->as<NameNode>();
2084 MOZ_ASSERT(name.isKind(ParseNodeKind::PrivateName));
2085 return name;
2086 }
2087
test(const ParseNode & node)2088 static bool test(const ParseNode& node) {
2089 bool match = node.isKind(ParseNodeKind::PrivateMemberExpr) ||
2090 node.isKind(ParseNodeKind::OptionalPrivateMemberExpr);
2091 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2092 MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
2093 ParseNodeKind::PrivateName));
2094 return match;
2095 }
2096 };
2097
2098 class PrivateMemberAccess : public PrivateMemberAccessBase {
2099 public:
PrivateMemberAccess(ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)2100 PrivateMemberAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2101 uint32_t end)
2102 : PrivateMemberAccessBase(ParseNodeKind::PrivateMemberExpr, lhs, name,
2103 begin, end) {}
2104
test(const ParseNode & node)2105 static bool test(const ParseNode& node) {
2106 return node.isKind(ParseNodeKind::PrivateMemberExpr);
2107 }
2108 };
2109
2110 class OptionalPrivateMemberAccess : public PrivateMemberAccessBase {
2111 public:
OptionalPrivateMemberAccess(ParseNode * lhs,NameNode * name,uint32_t begin,uint32_t end)2112 OptionalPrivateMemberAccess(ParseNode* lhs, NameNode* name, uint32_t begin,
2113 uint32_t end)
2114 : PrivateMemberAccessBase(ParseNodeKind::OptionalPrivateMemberExpr, lhs,
2115 name, begin, end) {}
2116
test(const ParseNode & node)2117 static bool test(const ParseNode& node) {
2118 return node.isKind(ParseNodeKind::OptionalPrivateMemberExpr);
2119 }
2120 };
2121
2122 /*
2123 * A CallSiteNode represents the implicit call site object argument in a
2124 * TaggedTemplate.
2125 */
2126 class CallSiteNode : public ListNode {
2127 public:
CallSiteNode(uint32_t begin)2128 explicit CallSiteNode(uint32_t begin)
2129 : ListNode(ParseNodeKind::CallSiteObj, TokenPos(begin, begin + 1)) {}
2130
test(const ParseNode & node)2131 static bool test(const ParseNode& node) {
2132 bool match = node.isKind(ParseNodeKind::CallSiteObj);
2133 MOZ_ASSERT_IF(match, node.is<ListNode>());
2134 return match;
2135 }
2136
rawNodes()2137 ListNode* rawNodes() const {
2138 MOZ_ASSERT(head());
2139 return &head()->as<ListNode>();
2140 }
2141 };
2142
2143 class CallNode : public BinaryNode {
2144 const JSOp callOp_;
2145
2146 public:
CallNode(ParseNodeKind kind,JSOp callOp,ParseNode * left,ParseNode * right)2147 CallNode(ParseNodeKind kind, JSOp callOp, ParseNode* left, ParseNode* right)
2148 : CallNode(kind, callOp, TokenPos(left->pn_pos.begin, right->pn_pos.end),
2149 left, right) {}
2150
CallNode(ParseNodeKind kind,JSOp callOp,TokenPos pos,ParseNode * left,ParseNode * right)2151 CallNode(ParseNodeKind kind, JSOp callOp, TokenPos pos, ParseNode* left,
2152 ParseNode* right)
2153 : BinaryNode(kind, pos, left, right), callOp_(callOp) {
2154 MOZ_ASSERT(is<CallNode>());
2155 }
2156
test(const ParseNode & node)2157 static bool test(const ParseNode& node) {
2158 bool match = node.isKind(ParseNodeKind::CallExpr) ||
2159 node.isKind(ParseNodeKind::SuperCallExpr) ||
2160 node.isKind(ParseNodeKind::OptionalCallExpr) ||
2161 node.isKind(ParseNodeKind::TaggedTemplateExpr) ||
2162 node.isKind(ParseNodeKind::CallImportExpr) ||
2163 node.isKind(ParseNodeKind::NewExpr);
2164 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2165 return match;
2166 }
2167
callOp()2168 JSOp callOp() { return callOp_; }
2169 };
2170
2171 class ClassMethod : public BinaryNode {
2172 bool isStatic_;
2173 AccessorType accessorType_;
2174 FunctionNode* initializerIfPrivate_;
2175
2176 public:
2177 /*
2178 * Method definitions often keep a name and function body that overlap,
2179 * so explicitly define the beginning and end here.
2180 */
ClassMethod(ParseNodeKind kind,ParseNode * name,ParseNode * body,AccessorType accessorType,bool isStatic,FunctionNode * initializerIfPrivate)2181 ClassMethod(ParseNodeKind kind, ParseNode* name, ParseNode* body,
2182 AccessorType accessorType, bool isStatic,
2183 FunctionNode* initializerIfPrivate)
2184 : BinaryNode(kind, TokenPos(name->pn_pos.begin, body->pn_pos.end), name,
2185 body),
2186 isStatic_(isStatic),
2187 accessorType_(accessorType),
2188 initializerIfPrivate_(initializerIfPrivate) {
2189 MOZ_ASSERT(kind == ParseNodeKind::DefaultConstructor ||
2190 kind == ParseNodeKind::ClassMethod);
2191 }
2192
test(const ParseNode & node)2193 static bool test(const ParseNode& node) {
2194 bool match = node.isKind(ParseNodeKind::DefaultConstructor) ||
2195 node.isKind(ParseNodeKind::ClassMethod);
2196 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2197 return match;
2198 }
2199
name()2200 ParseNode& name() const { return *left(); }
2201
method()2202 FunctionNode& method() const { return right()->as<FunctionNode>(); }
2203
isStatic()2204 bool isStatic() const { return isStatic_; }
2205
accessorType()2206 AccessorType accessorType() const { return accessorType_; }
2207
initializerIfPrivate()2208 FunctionNode* initializerIfPrivate() const { return initializerIfPrivate_; }
2209 };
2210
2211 class ClassField : public BinaryNode {
2212 bool isStatic_;
2213
2214 public:
ClassField(ParseNode * name,ParseNode * initializer,bool isStatic)2215 ClassField(ParseNode* name, ParseNode* initializer, bool isStatic)
2216 : BinaryNode(ParseNodeKind::ClassField, initializer->pn_pos, name,
2217 initializer),
2218 isStatic_(isStatic) {}
2219
test(const ParseNode & node)2220 static bool test(const ParseNode& node) {
2221 bool match = node.isKind(ParseNodeKind::ClassField);
2222 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2223 return match;
2224 }
2225
name()2226 ParseNode& name() const { return *left(); }
2227
initializer()2228 FunctionNode* initializer() const { return &right()->as<FunctionNode>(); }
2229
isStatic()2230 bool isStatic() const { return isStatic_; }
2231 };
2232
2233 // Hold onto the function generated for a class static block like
2234 //
2235 // class A {
2236 // static { /* this static block */ }
2237 // }
2238 //
2239 class StaticClassBlock : public UnaryNode {
2240 public:
StaticClassBlock(FunctionNode * function)2241 explicit StaticClassBlock(FunctionNode* function)
2242 : UnaryNode(ParseNodeKind::StaticClassBlock, function->pn_pos, function) {
2243 }
2244
test(const ParseNode & node)2245 static bool test(const ParseNode& node) {
2246 bool match = node.isKind(ParseNodeKind::StaticClassBlock);
2247 MOZ_ASSERT_IF(match, node.is<UnaryNode>());
2248 return match;
2249 }
function()2250 FunctionNode* function() const { return &kid()->as<FunctionNode>(); }
2251 };
2252
2253 class PropertyDefinition : public BinaryNode {
2254 AccessorType accessorType_;
2255
2256 public:
PropertyDefinition(ParseNode * name,ParseNode * value,AccessorType accessorType)2257 PropertyDefinition(ParseNode* name, ParseNode* value,
2258 AccessorType accessorType)
2259 : BinaryNode(ParseNodeKind::PropertyDefinition,
2260 TokenPos(name->pn_pos.begin, value->pn_pos.end), name,
2261 value),
2262 accessorType_(accessorType) {}
2263
test(const ParseNode & node)2264 static bool test(const ParseNode& node) {
2265 bool match = node.isKind(ParseNodeKind::PropertyDefinition);
2266 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2267 return match;
2268 }
2269
accessorType()2270 AccessorType accessorType() { return accessorType_; }
2271 };
2272
2273 class SwitchStatement : public BinaryNode {
2274 bool hasDefault_; /* only for ParseNodeKind::Switch */
2275
2276 public:
SwitchStatement(uint32_t begin,ParseNode * discriminant,LexicalScopeNode * lexicalForCaseList,bool hasDefault)2277 SwitchStatement(uint32_t begin, ParseNode* discriminant,
2278 LexicalScopeNode* lexicalForCaseList, bool hasDefault)
2279 : BinaryNode(ParseNodeKind::SwitchStmt,
2280 TokenPos(begin, lexicalForCaseList->pn_pos.end),
2281 discriminant, lexicalForCaseList),
2282 hasDefault_(hasDefault) {
2283 #ifdef DEBUG
2284 ListNode* cases = &lexicalForCaseList->scopeBody()->as<ListNode>();
2285 MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
2286 bool found = false;
2287 for (ParseNode* item : cases->contents()) {
2288 CaseClause* caseNode = &item->as<CaseClause>();
2289 if (caseNode->isDefault()) {
2290 found = true;
2291 break;
2292 }
2293 }
2294 MOZ_ASSERT(found == hasDefault);
2295 #endif
2296 }
2297
test(const ParseNode & node)2298 static bool test(const ParseNode& node) {
2299 bool match = node.isKind(ParseNodeKind::SwitchStmt);
2300 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2301 return match;
2302 }
2303
discriminant()2304 ParseNode& discriminant() const { return *left(); }
2305
lexicalForCaseList()2306 LexicalScopeNode& lexicalForCaseList() const {
2307 return right()->as<LexicalScopeNode>();
2308 }
2309
hasDefault()2310 bool hasDefault() const { return hasDefault_; }
2311 };
2312
2313 class ClassNames : public BinaryNode {
2314 public:
ClassNames(ParseNode * outerBinding,ParseNode * innerBinding,const TokenPos & pos)2315 ClassNames(ParseNode* outerBinding, ParseNode* innerBinding,
2316 const TokenPos& pos)
2317 : BinaryNode(ParseNodeKind::ClassNames, pos, outerBinding, innerBinding) {
2318 MOZ_ASSERT_IF(outerBinding, outerBinding->isKind(ParseNodeKind::Name));
2319 MOZ_ASSERT(innerBinding->isKind(ParseNodeKind::Name));
2320 MOZ_ASSERT_IF(outerBinding, innerBinding->as<NameNode>().atom() ==
2321 outerBinding->as<NameNode>().atom());
2322 }
2323
test(const ParseNode & node)2324 static bool test(const ParseNode& node) {
2325 bool match = node.isKind(ParseNodeKind::ClassNames);
2326 MOZ_ASSERT_IF(match, node.is<BinaryNode>());
2327 return match;
2328 }
2329
2330 /*
2331 * Classes require two definitions: The first "outer" binding binds the
2332 * class into the scope in which it was declared. the outer binding is a
2333 * mutable lexial binding. The second "inner" binding binds the class by
2334 * name inside a block in which the methods are evaulated. It is immutable,
2335 * giving the methods access to the static members of the class even if
2336 * the outer binding has been overwritten.
2337 */
outerBinding()2338 NameNode* outerBinding() const {
2339 if (ParseNode* binding = left()) {
2340 return &binding->as<NameNode>();
2341 }
2342 return nullptr;
2343 }
2344
innerBinding()2345 NameNode* innerBinding() const { return &right()->as<NameNode>(); }
2346 };
2347
2348 class ClassNode : public TernaryNode {
2349 private:
innerScope()2350 LexicalScopeNode* innerScope() const {
2351 return &kid3()->as<LexicalScopeNode>();
2352 }
2353
bodyScope()2354 ClassBodyScopeNode* bodyScope() const {
2355 return &innerScope()->scopeBody()->as<ClassBodyScopeNode>();
2356 }
2357
2358 public:
ClassNode(ParseNode * names,ParseNode * heritage,LexicalScopeNode * memberBlock,const TokenPos & pos)2359 ClassNode(ParseNode* names, ParseNode* heritage,
2360 LexicalScopeNode* memberBlock, const TokenPos& pos)
2361 : TernaryNode(ParseNodeKind::ClassDecl, names, heritage, memberBlock,
2362 pos) {
2363 MOZ_ASSERT(innerScope()->scopeBody()->is<ClassBodyScopeNode>());
2364 MOZ_ASSERT_IF(names, names->is<ClassNames>());
2365 }
2366
test(const ParseNode & node)2367 static bool test(const ParseNode& node) {
2368 bool match = node.isKind(ParseNodeKind::ClassDecl);
2369 MOZ_ASSERT_IF(match, node.is<TernaryNode>());
2370 return match;
2371 }
2372
names()2373 ClassNames* names() const {
2374 return kid1() ? &kid1()->as<ClassNames>() : nullptr;
2375 }
2376
heritage()2377 ParseNode* heritage() const { return kid2(); }
2378
memberList()2379 ListNode* memberList() const { return bodyScope()->memberList(); }
2380
scopeBindings()2381 LexicalScopeNode* scopeBindings() const {
2382 LexicalScopeNode* scope = innerScope();
2383 return scope->isEmptyScope() ? nullptr : scope;
2384 }
2385
bodyScopeBindings()2386 ClassBodyScopeNode* bodyScopeBindings() const {
2387 ClassBodyScopeNode* scope = bodyScope();
2388 return scope->isEmptyScope() ? nullptr : scope;
2389 }
2390 };
2391
2392 #ifdef DEBUG
2393 void DumpParseTree(ParserBase* parser, ParseNode* pn, GenericPrinter& out,
2394 int indent = 0);
2395 #endif
2396
2397 class ParseNodeAllocator {
2398 public:
ParseNodeAllocator(JSContext * cx,LifoAlloc & alloc)2399 explicit ParseNodeAllocator(JSContext* cx, LifoAlloc& alloc)
2400 : cx(cx), alloc(alloc) {}
2401
2402 void* allocNode(size_t size);
2403
2404 private:
2405 JSContext* cx;
2406 LifoAlloc& alloc;
2407 };
2408
isConstant()2409 inline bool ParseNode::isConstant() {
2410 switch (pn_type) {
2411 case ParseNodeKind::NumberExpr:
2412 case ParseNodeKind::StringExpr:
2413 case ParseNodeKind::TemplateStringExpr:
2414 case ParseNodeKind::NullExpr:
2415 case ParseNodeKind::RawUndefinedExpr:
2416 case ParseNodeKind::FalseExpr:
2417 case ParseNodeKind::TrueExpr:
2418 return true;
2419 case ParseNodeKind::ArrayExpr:
2420 case ParseNodeKind::ObjectExpr:
2421 return !as<ListNode>().hasNonConstInitializer();
2422 default:
2423 return false;
2424 }
2425 }
2426
FunctionFormalParametersList(ParseNode * fn,unsigned * numFormals)2427 static inline ParseNode* FunctionFormalParametersList(ParseNode* fn,
2428 unsigned* numFormals) {
2429 MOZ_ASSERT(fn->isKind(ParseNodeKind::Function));
2430 ListNode* argsBody = fn->as<FunctionNode>().body();
2431 MOZ_ASSERT(argsBody->isKind(ParseNodeKind::ParamsBody));
2432 *numFormals = argsBody->count();
2433 if (*numFormals > 0 && argsBody->last()->is<LexicalScopeNode>() &&
2434 argsBody->last()->as<LexicalScopeNode>().scopeBody()->isKind(
2435 ParseNodeKind::StatementList)) {
2436 (*numFormals)--;
2437 }
2438 return argsBody->head();
2439 }
2440
2441 bool IsAnonymousFunctionDefinition(ParseNode* pn);
2442
2443 } /* namespace frontend */
2444 } /* namespace js */
2445
2446 #endif /* frontend_ParseNode_h */
2447