Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/Attributes.h"
11 :
12 : #include "builtin/ModuleObject.h"
13 : #include "frontend/TokenStream.h"
14 :
15 : namespace js {
16 : namespace frontend {
17 :
18 : class ParseContext;
19 : class FullParseHandler;
20 : class FunctionBox;
21 : class ObjectBox;
22 :
23 : #define FOR_EACH_PARSE_NODE_KIND(F) \
24 : F(NOP) \
25 : F(SEMI) \
26 : F(COMMA) \
27 : F(CONDITIONAL) \
28 : F(COLON) \
29 : F(SHORTHAND) \
30 : F(POS) \
31 : F(NEG) \
32 : F(PREINCREMENT) \
33 : F(POSTINCREMENT) \
34 : F(PREDECREMENT) \
35 : F(POSTDECREMENT) \
36 : F(DOT) \
37 : F(ELEM) \
38 : F(ARRAY) \
39 : F(ELISION) \
40 : F(STATEMENTLIST) \
41 : F(LABEL) \
42 : F(OBJECT) \
43 : F(CALL) \
44 : F(NAME) \
45 : F(OBJECT_PROPERTY_NAME) \
46 : F(COMPUTED_NAME) \
47 : F(NUMBER) \
48 : F(STRING) \
49 : F(TEMPLATE_STRING_LIST) \
50 : F(TEMPLATE_STRING) \
51 : F(TAGGED_TEMPLATE) \
52 : F(CALLSITEOBJ) \
53 : F(REGEXP) \
54 : F(TRUE) \
55 : F(FALSE) \
56 : F(NULL) \
57 : F(RAW_UNDEFINED) \
58 : F(THIS) \
59 : F(FUNCTION) \
60 : F(MODULE) \
61 : F(IF) \
62 : F(SWITCH) \
63 : F(CASE) \
64 : F(WHILE) \
65 : F(DOWHILE) \
66 : F(FOR) \
67 : F(COMPREHENSIONFOR) \
68 : F(BREAK) \
69 : F(CONTINUE) \
70 : F(VAR) \
71 : F(CONST) \
72 : F(WITH) \
73 : F(RETURN) \
74 : F(NEW) \
75 : /* Delete operations. These must be sequential. */ \
76 : F(DELETENAME) \
77 : F(DELETEPROP) \
78 : F(DELETEELEM) \
79 : F(DELETEEXPR) \
80 : F(TRY) \
81 : F(CATCH) \
82 : F(CATCHLIST) \
83 : F(THROW) \
84 : F(DEBUGGER) \
85 : F(GENERATOR) \
86 : F(INITIALYIELD) \
87 : F(YIELD) \
88 : F(YIELD_STAR) \
89 : F(GENEXP) \
90 : F(ARRAYCOMP) \
91 : F(ARRAYPUSH) \
92 : F(LEXICALSCOPE) \
93 : F(LET) \
94 : F(IMPORT) \
95 : F(IMPORT_SPEC_LIST) \
96 : F(IMPORT_SPEC) \
97 : F(EXPORT) \
98 : F(EXPORT_FROM) \
99 : F(EXPORT_DEFAULT) \
100 : F(EXPORT_SPEC_LIST) \
101 : F(EXPORT_SPEC) \
102 : F(EXPORT_BATCH_SPEC) \
103 : F(FORIN) \
104 : F(FOROF) \
105 : F(FORHEAD) \
106 : F(PARAMSBODY) \
107 : F(SPREAD) \
108 : F(MUTATEPROTO) \
109 : F(CLASS) \
110 : F(CLASSMETHOD) \
111 : F(CLASSMETHODLIST) \
112 : F(CLASSNAMES) \
113 : F(NEWTARGET) \
114 : F(POSHOLDER) \
115 : F(SUPERBASE) \
116 : F(SUPERCALL) \
117 : F(SETTHIS) \
118 : \
119 : /* Unary operators. */ \
120 : F(TYPEOFNAME) \
121 : F(TYPEOFEXPR) \
122 : F(VOID) \
123 : F(NOT) \
124 : F(BITNOT) \
125 : F(AWAIT) \
126 : \
127 : /* \
128 : * Binary operators. \
129 : * These must be in the same order as TOK_OR and friends in TokenStream.h. \
130 : */ \
131 : F(OR) \
132 : F(AND) \
133 : F(BITOR) \
134 : F(BITXOR) \
135 : F(BITAND) \
136 : F(STRICTEQ) \
137 : F(EQ) \
138 : F(STRICTNE) \
139 : F(NE) \
140 : F(LT) \
141 : F(LE) \
142 : F(GT) \
143 : F(GE) \
144 : F(INSTANCEOF) \
145 : F(IN) \
146 : F(LSH) \
147 : F(RSH) \
148 : F(URSH) \
149 : F(ADD) \
150 : F(SUB) \
151 : F(STAR) \
152 : F(DIV) \
153 : F(MOD) \
154 : F(POW) \
155 : \
156 : /* Assignment operators (= += -= etc.). */ \
157 : /* ParseNode::isAssignment assumes all these are consecutive. */ \
158 : F(ASSIGN) \
159 : F(ADDASSIGN) \
160 : F(SUBASSIGN) \
161 : F(BITORASSIGN) \
162 : F(BITXORASSIGN) \
163 : F(BITANDASSIGN) \
164 : F(LSHASSIGN) \
165 : F(RSHASSIGN) \
166 : F(URSHASSIGN) \
167 : F(MULASSIGN) \
168 : F(DIVASSIGN) \
169 : F(MODASSIGN) \
170 : F(POWASSIGN)
171 :
172 : /*
173 : * Parsing builds a tree of nodes that directs code generation. This tree is
174 : * not a concrete syntax tree in all respects (for example, || and && are left
175 : * associative, but (A && B && C) translates into the right-associated tree
176 : * <A && <B && C>> so that code generation can emit a left-associative branch
177 : * around <B && C> when A is false). Nodes are labeled by kind, with a
178 : * secondary JSOp label when needed.
179 : *
180 : * The long comment after this enum block describes the kinds in detail.
181 : */
182 : enum ParseNodeKind
183 : {
184 : #define EMIT_ENUM(name) PNK_##name,
185 : FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
186 : #undef EMIT_ENUM
187 : PNK_LIMIT, /* domain size */
188 : PNK_BINOP_FIRST = PNK_OR,
189 : PNK_BINOP_LAST = PNK_POW,
190 : PNK_ASSIGNMENT_START = PNK_ASSIGN,
191 : PNK_ASSIGNMENT_LAST = PNK_POWASSIGN
192 : };
193 :
194 : inline bool
195 0 : IsDeleteKind(ParseNodeKind kind)
196 : {
197 0 : return PNK_DELETENAME <= kind && kind <= PNK_DELETEEXPR;
198 : }
199 :
200 : inline bool
201 0 : IsTypeofKind(ParseNodeKind kind)
202 : {
203 0 : return PNK_TYPEOFNAME <= kind && kind <= PNK_TYPEOFEXPR;
204 : }
205 :
206 : /*
207 : * Label Variant Members
208 : * ----- ------- -------
209 : * <Definitions>
210 : * PNK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function
211 : * object containing arg and var properties. We
212 : * create the function object at parse (not emit)
213 : * time to specialize arg and var bytecodes early.
214 : * pn_body: PNK_PARAMSBODY, ordinarily;
215 : * PNK_LEXICALSCOPE for implicit function in genexpr
216 : * PNK_PARAMSBODY list list of formal parameters with
217 : * PNK_NAME node with non-empty name for
218 : * SingleNameBinding without Initializer
219 : * PNK_ASSIGN node for SingleNameBinding with
220 : * Initializer
221 : * PNK_NAME node with empty name for destructuring
222 : * pn_expr: PNK_ARRAY, PNK_OBJECT, or PNK_ASSIGN
223 : * PNK_ARRAY or PNK_OBJECT for BindingPattern
224 : * without Initializer
225 : * PNK_ASSIGN for BindingPattern with
226 : * Initializer
227 : * followed by:
228 : * PNK_STATEMENTLIST node for function body
229 : * statements,
230 : * PNK_RETURN for expression closure
231 : * pn_count: 1 + number of formal parameters
232 : * pn_tree: PNK_PARAMSBODY or PNK_STATEMENTLIST node
233 : * PNK_SPREAD unary pn_kid: expression being spread
234 : *
235 : * <Statements>
236 : * PNK_STATEMENTLIST list pn_head: list of pn_count statements
237 : * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
238 : * In body of a comprehension or desugared generator
239 : * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH,
240 : * or (if the push was optimized away) empty
241 : * PNK_STATEMENTLIST.
242 : * PNK_SWITCH binary pn_left: discriminant
243 : * pn_right: list of PNK_CASE nodes, with at most one
244 : * default node, or if there are let bindings
245 : * in the top level of the switch body's cases, a
246 : * PNK_LEXICALSCOPE node that contains the list of
247 : * PNK_CASE nodes.
248 : * PNK_CASE binary pn_left: case-expression if CaseClause, or
249 : * null if DefaultClause
250 : * pn_right: PNK_STATEMENTLIST node for this case's
251 : * statements
252 : * pn_u.binary.offset: scratch space for the emitter
253 : * PNK_WHILE binary pn_left: cond, pn_right: body
254 : * PNK_DOWHILE binary pn_left: body, pn_right: cond
255 : * PNK_FOR binary pn_left: either PNK_FORIN (for-in statement),
256 : * PNK_FOROF (for-of) or PNK_FORHEAD (for(;;))
257 : * pn_right: body
258 : * PNK_COMPREHENSIONFOR pn_left: either PNK_FORIN or PNK_FOROF
259 : * binary pn_right: body
260 : * PNK_FORIN ternary pn_kid1: declaration or expression to left of 'in'
261 : * pn_kid2: null
262 : * pn_kid3: object expr to right of 'in'
263 : * PNK_FOROF ternary pn_kid1: declaration or expression to left of 'of'
264 : * pn_kid2: null
265 : * pn_kid3: expr to right of 'of'
266 : * PNK_FORHEAD ternary pn_kid1: init expr before first ';' or nullptr
267 : * pn_kid2: cond expr before second ';' or nullptr
268 : * pn_kid3: update expr after second ';' or nullptr
269 : * PNK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
270 : * PNK_TRY ternary pn_kid1: try block
271 : * pn_kid2: null or PNK_CATCHLIST list
272 : * pn_kid3: null or finally block
273 : * PNK_CATCHLIST list pn_head: list of PNK_LEXICALSCOPE nodes, one per
274 : * catch-block, each with pn_expr pointing
275 : * to a PNK_CATCH node
276 : * PNK_CATCH ternary pn_kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch var node
277 : * (PNK_ARRAY or PNK_OBJECT if destructuring)
278 : * pn_kid2: null or the catch guard expression
279 : * pn_kid3: catch block statements
280 : * PNK_BREAK name pn_atom: label or null
281 : * PNK_CONTINUE name pn_atom: label or null
282 : * PNK_WITH binary pn_left: head expr; pn_right: body;
283 : * PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes
284 : * PNK_LET, each name node has either
285 : * PNK_CONST pn_used: false
286 : * pn_atom: variable name
287 : * pn_expr: initializer or null
288 : * or
289 : * pn_used: true
290 : * pn_atom: variable name
291 : * pn_lexdef: def node
292 : * each assignment node has
293 : * pn_left: PNK_NAME with pn_used true and
294 : * pn_lexdef (NOT pn_expr) set
295 : * pn_right: initializer
296 : * PNK_RETURN unary pn_kid: return expr or null
297 : * PNK_SEMI unary pn_kid: expr or null statement
298 : * pn_prologue: true if Directive Prologue member
299 : * in original source, not introduced via
300 : * constant folding or other tree rewriting
301 : * PNK_LABEL name pn_atom: label, pn_expr: labeled statement
302 : * PNK_IMPORT binary pn_left: PNK_IMPORT_SPEC_LIST import specifiers
303 : * pn_right: PNK_STRING module specifier
304 : * PNK_EXPORT unary pn_kid: declaration expression
305 : * PNK_EXPORT_FROM binary pn_left: PNK_EXPORT_SPEC_LIST export specifiers
306 : * pn_right: PNK_STRING module specifier
307 : * PNK_EXPORT_DEFAULT unary pn_kid: export default declaration or expression
308 : *
309 : * <Expressions>
310 : * All left-associated binary trees of the same type are optimized into lists
311 : * to avoid recursion when processing expression chains.
312 : * PNK_COMMA list pn_head: list of pn_count comma-separated exprs
313 : * PNK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
314 : * PNK_ADDASSIGN, binary pn_left: lvalue, pn_right: rvalue
315 : * PNK_SUBASSIGN, pn_op: JSOP_ADD for +=, etc.
316 : * PNK_BITORASSIGN,
317 : * PNK_BITXORASSIGN,
318 : * PNK_BITANDASSIGN,
319 : * PNK_LSHASSIGN,
320 : * PNK_RSHASSIGN,
321 : * PNK_URSHASSIGN,
322 : * PNK_MULASSIGN,
323 : * PNK_DIVASSIGN,
324 : * PNK_MODASSIGN,
325 : * PNK_POWASSIGN
326 : * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
327 : * pn_kid1: cond, pn_kid2: then, pn_kid3: else
328 : * PNK_OR, list pn_head; list of pn_count subexpressions
329 : * PNK_AND, All of these operators are left-associative except (**).
330 : * PNK_BITOR,
331 : * PNK_BITXOR,
332 : * PNK_BITAND,
333 : * PNK_EQ,
334 : * PNK_NE,
335 : * PNK_STRICTEQ,
336 : * PNK_STRICTNE,
337 : * PNK_LT,
338 : * PNK_LE,
339 : * PNK_GT,
340 : * PNK_GE,
341 : * PNK_LSH,
342 : * PNK_RSH,
343 : * PNK_URSH,
344 : * PNK_ADD,
345 : * PNK_SUB,
346 : * PNK_STAR,
347 : * PNK_DIV,
348 : * PNK_MOD,
349 : * PNK_POW (**) is right-associative, but forms a list
350 : * nonetheless. Special hacks everywhere.
351 : *
352 : * PNK_POS, unary pn_kid: UNARY expr
353 : * PNK_NEG
354 : * PNK_VOID, unary pn_kid: UNARY expr
355 : * PNK_NOT,
356 : * PNK_BITNOT
357 : * PNK_TYPEOFNAME, unary pn_kid: UNARY expr
358 : * PNK_TYPEOFEXPR
359 : * PNK_PREINCREMENT, unary pn_kid: MEMBER expr
360 : * PNK_POSTINCREMENT,
361 : * PNK_PREDECREMENT,
362 : * PNK_POSTDECREMENT
363 : * PNK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
364 : * pn_count: 1 + N (where N is number of args)
365 : * ctor is a MEMBER expr
366 : * PNK_DELETENAME unary pn_kid: PNK_NAME expr
367 : * PNK_DELETEPROP unary pn_kid: PNK_DOT expr
368 : * PNK_DELETEELEM unary pn_kid: PNK_ELEM expr
369 : * PNK_DELETEEXPR unary pn_kid: MEMBER expr that's evaluated, then the
370 : * overall delete evaluates to true; can't be a kind
371 : * for a more-specific PNK_DELETE* unless constant
372 : * folding (or a similar parse tree manipulation) has
373 : * occurred
374 : * PNK_DOT name pn_expr: MEMBER expr to left of .
375 : * pn_atom: name to right of .
376 : * PNK_ELEM binary pn_left: MEMBER expr to left of [
377 : * pn_right: expr between [ and ]
378 : * PNK_CALL list pn_head: list of call, arg1, arg2, ... argN
379 : * pn_count: 1 + N (where N is number of args)
380 : * call is a MEMBER expr naming a callable object
381 : * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call
382 : * in the desugaring of a generator-expression.
383 : * PNK_ARRAY list pn_head: list of pn_count array element exprs
384 : * [,,] holes are represented by PNK_ELISION nodes
385 : * pn_xflags: PN_ENDCOMMA if extra comma at end
386 : * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes
387 : * PNK_COLON binary key-value pair in object initializer or
388 : * destructuring lhs
389 : * pn_left: property id, pn_right: value
390 : * PNK_SHORTHAND binary Same fields as PNK_COLON. This is used for object
391 : * literal properties using shorthand ({x}).
392 : * PNK_COMPUTED_NAME unary ES6 ComputedPropertyName.
393 : * pn_kid: the AssignmentExpression inside the square brackets
394 : * PNK_NAME, name pn_atom: name, string, or object atom
395 : * PNK_STRING pn_op: JSOP_GETNAME, JSOP_STRING, or JSOP_OBJECT
396 : * If JSOP_GETNAME, pn_op may be JSOP_*ARG or JSOP_*VAR
397 : * telling const-ness and static analysis results
398 : * PNK_TEMPLATE_STRING_LIST pn_head: list of alternating expr and template strings
399 : * list
400 : * PNK_TEMPLATE_STRING pn_atom: template string atom
401 : nullary pn_op: JSOP_NOP
402 : * PNK_TAGGED_TEMPLATE pn_head: list of call, call site object, arg1, arg2, ... argN
403 : * list pn_count: 2 + N (N is the number of substitutions)
404 : * PNK_CALLSITEOBJ list pn_head: a PNK_ARRAY node followed by
405 : * list of pn_count - 1 PNK_TEMPLATE_STRING nodes
406 : * PNK_REGEXP nullary pn_objbox: RegExp model object
407 : * PNK_NUMBER dval pn_dval: double value of numeric literal
408 : * PNK_TRUE, nullary pn_op: JSOp bytecode
409 : * PNK_FALSE,
410 : * PNK_NULL,
411 : * PNK_RAW_UNDEFINED
412 : *
413 : * PNK_THIS, unary pn_kid: '.this' Name if function `this`, else nullptr
414 : * PNK_SUPERBASE unary pn_kid: '.this' Name
415 : *
416 : * PNK_SETTHIS binary pn_left: '.this' Name, pn_right: SuperCall
417 : *
418 : * PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
419 : * pn_u.scope.body: scope body
420 : * PNK_GENERATOR nullary
421 : * PNK_INITIALYIELD unary pn_kid: generator object
422 : * PNK_YIELD, unary pn_kid: expr or null
423 : * PNK_YIELD_STAR,
424 : * PNK_AWAIT
425 : * PNK_ARRAYCOMP list pn_count: 1
426 : * pn_head: list of 1 element, which is block
427 : * enclosing for loop(s) and optionally
428 : * if-guarded PNK_ARRAYPUSH
429 : * PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
430 : * pn_kid: array comprehension expression
431 : * PNK_NOP nullary
432 : */
433 : enum ParseNodeArity
434 : {
435 : PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
436 : PN_UNARY, /* one kid, plus a couple of scalars */
437 : PN_BINARY, /* two kids, plus a couple of scalars */
438 : PN_TERNARY, /* three kids */
439 : PN_CODE, /* module or function definition node */
440 : PN_LIST, /* generic singly linked list */
441 : PN_NAME, /* name, label, or regexp */
442 : PN_SCOPE /* lexical scope */
443 : };
444 :
445 : class LoopControlStatement;
446 : class BreakStatement;
447 : class ContinueStatement;
448 : class ConditionalExpression;
449 : class PropertyAccess;
450 :
451 : class ParseNode
452 : {
453 : uint16_t pn_type; /* PNK_* type */
454 : uint8_t pn_op; /* see JSOp enum and jsopcode.tbl */
455 : uint8_t pn_arity:4; /* see ParseNodeArity enum */
456 : bool pn_parens:1; /* this expr was enclosed in parens */
457 : bool pn_rhs_anon_fun:1; /* this expr is anonymous function or class that
458 : * is a direct RHS of PNK_ASSIGN or PNK_COLON of
459 : * property, that needs SetFunctionName. */
460 :
461 : ParseNode(const ParseNode& other) = delete;
462 : void operator=(const ParseNode& other) = delete;
463 :
464 : public:
465 : ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
466 : : pn_type(kind),
467 : pn_op(op),
468 : pn_arity(arity),
469 : pn_parens(false),
470 : pn_rhs_anon_fun(false),
471 : pn_pos(0, 0),
472 : pn_next(nullptr)
473 : {
474 : MOZ_ASSERT(kind < PNK_LIMIT);
475 : memset(&pn_u, 0, sizeof pn_u);
476 : }
477 :
478 310719 : ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos& pos)
479 310719 : : pn_type(kind),
480 : pn_op(op),
481 : pn_arity(arity),
482 : pn_parens(false),
483 : pn_rhs_anon_fun(false),
484 : pn_pos(pos),
485 310719 : pn_next(nullptr)
486 : {
487 310719 : MOZ_ASSERT(kind < PNK_LIMIT);
488 310719 : memset(&pn_u, 0, sizeof pn_u);
489 310719 : }
490 :
491 316024 : JSOp getOp() const { return JSOp(pn_op); }
492 38310 : void setOp(JSOp op) { pn_op = op; }
493 123224 : bool isOp(JSOp op) const { return getOp() == op; }
494 :
495 4459471 : ParseNodeKind getKind() const {
496 4459471 : MOZ_ASSERT(pn_type < PNK_LIMIT);
497 4459471 : return ParseNodeKind(pn_type);
498 : }
499 2036 : void setKind(ParseNodeKind kind) {
500 2036 : MOZ_ASSERT(kind < PNK_LIMIT);
501 2036 : pn_type = kind;
502 2036 : }
503 2759948 : bool isKind(ParseNodeKind kind) const { return getKind() == kind; }
504 :
505 1557370 : ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); }
506 1557370 : bool isArity(ParseNodeArity a) const { return getArity() == a; }
507 1457 : void setArity(ParseNodeArity a) { pn_arity = a; }
508 :
509 4370 : bool isAssignment() const {
510 4370 : ParseNodeKind kind = getKind();
511 4370 : return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
512 : }
513 :
514 0 : bool isBinaryOperation() const {
515 0 : ParseNodeKind kind = getKind();
516 0 : return PNK_BINOP_FIRST <= kind && kind <= PNK_BINOP_LAST;
517 : }
518 :
519 : /* Boolean attributes. */
520 51835 : bool isInParens() const { return pn_parens; }
521 5479 : bool isLikelyIIFE() const { return isInParens(); }
522 2046 : void setInParens(bool enabled) { pn_parens = enabled; }
523 :
524 17734 : bool isDirectRHSAnonFunction() const {
525 17734 : return pn_rhs_anon_fun;
526 : }
527 491 : void setDirectRHSAnonFunction(bool enabled) {
528 491 : pn_rhs_anon_fun = enabled;
529 491 : }
530 :
531 : TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
532 : ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
533 :
534 : union {
535 : struct { /* list of next-linked nodes */
536 : ParseNode* head; /* first node in list */
537 : ParseNode** tail; /* ptr to ptr to last node in list */
538 : uint32_t count; /* number of nodes in list */
539 : uint32_t xflags; /* see PNX_* below */
540 : } list;
541 : struct { /* ternary: if, for(;;), ?: */
542 : ParseNode* kid1; /* condition, discriminant, etc. */
543 : ParseNode* kid2; /* then-part, case list, etc. */
544 : ParseNode* kid3; /* else-part, default case, etc. */
545 : } ternary;
546 : struct { /* two kids if binary */
547 : ParseNode* left;
548 : ParseNode* right;
549 : union {
550 : unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
551 : bool isStatic; /* only for PNK_CLASSMETHOD */
552 : uint32_t offset; /* for the emitter's use on PNK_CASE nodes */
553 : };
554 : } binary;
555 : struct { /* one kid if unary */
556 : ParseNode* kid;
557 : bool prologue; /* directive prologue member (as
558 : pn_prologue) */
559 : } unary;
560 : struct { /* name, labeled statement, etc. */
561 : union {
562 : JSAtom* atom; /* lexical name or label atom */
563 : ObjectBox* objbox; /* regexp object */
564 : FunctionBox* funbox; /* function object */
565 : };
566 : ParseNode* expr; /* module or function body, var
567 : initializer, argument default, or
568 : base object of PNK_DOT */
569 : } name;
570 : struct {
571 : LexicalScope::Data* bindings;
572 : ParseNode* body;
573 : } scope;
574 : struct {
575 : double value; /* aligned numeric literal value */
576 : DecimalPoint decimalPoint; /* Whether the number has a decimal point */
577 : } number;
578 : class {
579 : friend class LoopControlStatement;
580 : PropertyName* label; /* target of break/continue statement */
581 : } loopControl;
582 : } pn_u;
583 :
584 : #define pn_objbox pn_u.name.objbox
585 : #define pn_funbox pn_u.name.funbox
586 : #define pn_body pn_u.name.expr
587 : #define pn_head pn_u.list.head
588 : #define pn_tail pn_u.list.tail
589 : #define pn_count pn_u.list.count
590 : #define pn_xflags pn_u.list.xflags
591 : #define pn_kid1 pn_u.ternary.kid1
592 : #define pn_kid2 pn_u.ternary.kid2
593 : #define pn_kid3 pn_u.ternary.kid3
594 : #define pn_left pn_u.binary.left
595 : #define pn_right pn_u.binary.right
596 : #define pn_pval pn_u.binary.pval
597 : #define pn_iflags pn_u.binary.iflags
598 : #define pn_kid pn_u.unary.kid
599 : #define pn_prologue pn_u.unary.prologue
600 : #define pn_atom pn_u.name.atom
601 : #define pn_objbox pn_u.name.objbox
602 : #define pn_expr pn_u.name.expr
603 : #define pn_dval pn_u.number.value
604 :
605 :
606 : public:
607 : /*
608 : * If |left| is a list of the given kind/left-associative op, append
609 : * |right| to it and return |left|. Otherwise return a [left, right] list.
610 : */
611 : static ParseNode*
612 : appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
613 : FullParseHandler* handler, ParseContext* pc);
614 :
615 : inline PropertyName* name() const;
616 : inline JSAtom* atom() const;
617 :
618 132881 : ParseNode* expr() const {
619 132881 : MOZ_ASSERT(pn_arity == PN_NAME || pn_arity == PN_CODE);
620 132881 : return pn_expr;
621 : }
622 :
623 15830 : bool isEmptyScope() const {
624 15830 : MOZ_ASSERT(pn_arity == PN_SCOPE);
625 15830 : return !pn_u.scope.bindings;
626 : }
627 :
628 2941 : Handle<LexicalScope::Data*> scopeBindings() const {
629 2941 : MOZ_ASSERT(!isEmptyScope());
630 : // Bindings' GC safety depend on the presence of an AutoKeepAtoms that
631 : // the rest of the frontend also depends on.
632 2941 : return Handle<LexicalScope::Data*>::fromMarkedLocation(&pn_u.scope.bindings);
633 : }
634 :
635 60630 : ParseNode* scopeBody() const {
636 60630 : MOZ_ASSERT(pn_arity == PN_SCOPE);
637 60630 : return pn_u.scope.body;
638 : }
639 :
640 10121 : void setScopeBody(ParseNode* body) {
641 10121 : MOZ_ASSERT(pn_arity == PN_SCOPE);
642 10121 : pn_u.scope.body = body;
643 10121 : }
644 :
645 : /* PN_LIST pn_xflags bits. */
646 : #define PNX_FUNCDEFS 0x01 /* contains top-level function statements */
647 : #define PNX_ARRAYHOLESPREAD 0x02 /* one or more of
648 : 1. array initialiser has holes
649 : 2. array initializer has spread node */
650 : #define PNX_NONCONST 0x04 /* initialiser has non-constants */
651 :
652 5930 : bool functionIsHoisted() const {
653 5930 : MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
654 5930 : MOZ_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr
655 : isOp(JSOP_LAMBDA_ARROW) || // arrow function
656 : isOp(JSOP_DEFFUN) || // non-body-level function statement
657 : isOp(JSOP_NOP) || // body-level function stmt in global code
658 : isOp(JSOP_GETLOCAL) || // body-level function stmt in function code
659 : isOp(JSOP_GETARG) || // body-level function redeclaring formal
660 : isOp(JSOP_INITLEXICAL)); // block-level function stmt
661 5930 : return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN);
662 : }
663 :
664 : /*
665 : * True if this statement node could be a member of a Directive Prologue: an
666 : * expression statement consisting of a single string literal.
667 : *
668 : * This considers only the node and its children, not its context. After
669 : * parsing, check the node's pn_prologue flag to see if it is indeed part of
670 : * a directive prologue.
671 : *
672 : * Note that a Directive Prologue can contain statements that cannot
673 : * themselves be directives (string literals that include escape sequences
674 : * or escaped newlines, say). This member function returns true for such
675 : * nodes; we use it to determine the extent of the prologue.
676 : */
677 5291 : JSAtom* isStringExprStatement() const {
678 5291 : if (getKind() == PNK_SEMI) {
679 1460 : MOZ_ASSERT(pn_arity == PN_UNARY);
680 1460 : ParseNode* kid = pn_kid;
681 1460 : if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
682 113 : return kid->pn_atom;
683 : }
684 5178 : return nullptr;
685 : }
686 :
687 : /* True if pn is a parsenode representing a literal constant. */
688 508 : bool isLiteral() const {
689 1013 : return isKind(PNK_NUMBER) ||
690 585 : isKind(PNK_STRING) ||
691 160 : isKind(PNK_TRUE) ||
692 160 : isKind(PNK_FALSE) ||
693 668 : isKind(PNK_NULL) ||
694 588 : isKind(PNK_RAW_UNDEFINED);
695 : }
696 :
697 : /* Return true if this node appears in a Directive Prologue. */
698 107 : bool isDirectivePrologueMember() const { return pn_prologue; }
699 :
700 : // True iff this is a for-in/of loop variable declaration (var/let/const).
701 766 : bool isForLoopDeclaration() const {
702 766 : if (isKind(PNK_VAR) || isKind(PNK_LET) || isKind(PNK_CONST)) {
703 742 : MOZ_ASSERT(isArity(PN_LIST));
704 742 : MOZ_ASSERT(pn_count > 0);
705 742 : return true;
706 : }
707 :
708 24 : return false;
709 : }
710 :
711 0 : ParseNode* generatorExpr() const {
712 0 : MOZ_ASSERT(isKind(PNK_GENEXP));
713 :
714 0 : ParseNode* callee = this->pn_head;
715 0 : MOZ_ASSERT(callee->isKind(PNK_FUNCTION));
716 :
717 0 : ParseNode* paramsBody = callee->pn_body;
718 0 : MOZ_ASSERT(paramsBody->isKind(PNK_PARAMSBODY));
719 :
720 0 : ParseNode* body = paramsBody->last();
721 0 : MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
722 0 : MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) ||
723 : body->last()->isKind(PNK_COMPREHENSIONFOR));
724 0 : return body->last();
725 : }
726 :
727 : /*
728 : * Compute a pointer to the last element in a singly-linked list. NB: list
729 : * must be non-empty for correct PN_LAST usage -- this is asserted!
730 : */
731 11355 : ParseNode* last() const {
732 11355 : MOZ_ASSERT(pn_arity == PN_LIST);
733 11355 : MOZ_ASSERT(pn_count != 0);
734 11355 : return (ParseNode*)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next));
735 : }
736 :
737 9347 : void initNumber(double value, DecimalPoint decimalPoint) {
738 9347 : MOZ_ASSERT(pn_arity == PN_NULLARY);
739 9347 : MOZ_ASSERT(getKind() == PNK_NUMBER);
740 9347 : pn_u.number.value = value;
741 9347 : pn_u.number.decimalPoint = decimalPoint;
742 9347 : }
743 :
744 54475 : void makeEmpty() {
745 54475 : MOZ_ASSERT(pn_arity == PN_LIST);
746 54475 : pn_head = nullptr;
747 54475 : pn_tail = &pn_head;
748 54475 : pn_count = 0;
749 54475 : pn_xflags = 0;
750 54475 : }
751 :
752 11130 : void initList(ParseNode* pn) {
753 11130 : MOZ_ASSERT(pn_arity == PN_LIST);
754 11130 : if (pn->pn_pos.begin < pn_pos.begin)
755 0 : pn_pos.begin = pn->pn_pos.begin;
756 11130 : pn_pos.end = pn->pn_pos.end;
757 11130 : pn_head = pn;
758 11130 : pn_tail = &pn->pn_next;
759 11130 : pn_count = 1;
760 11130 : pn_xflags = 0;
761 11130 : }
762 :
763 146268 : void append(ParseNode* pn) {
764 146268 : MOZ_ASSERT(pn_arity == PN_LIST);
765 146268 : MOZ_ASSERT(pn->pn_pos.begin >= pn_pos.begin);
766 146268 : pn_pos.end = pn->pn_pos.end;
767 146268 : *pn_tail = pn;
768 146268 : pn_tail = &pn->pn_next;
769 146268 : pn_count++;
770 146268 : }
771 :
772 127 : void prepend(ParseNode* pn) {
773 127 : MOZ_ASSERT(pn_arity == PN_LIST);
774 127 : pn->pn_next = pn_head;
775 127 : pn_head = pn;
776 127 : if (pn_tail == &pn_head)
777 0 : pn_tail = &pn->pn_next;
778 127 : pn_count++;
779 127 : }
780 :
781 : void checkListConsistency()
782 : #ifndef DEBUG
783 : {}
784 : #endif
785 : ;
786 :
787 : enum AllowConstantObjects {
788 : DontAllowObjects = 0,
789 : AllowObjects,
790 : ForCopyOnWriteArray
791 : };
792 :
793 : MOZ_MUST_USE bool getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
794 : MutableHandleValue vp, Value* compare = nullptr,
795 : size_t ncompare = 0, NewObjectKind newKind = TenuredObject);
796 : inline bool isConstant();
797 :
798 : template <class NodeType>
799 43575 : inline bool is() const {
800 43575 : return NodeType::test(*this);
801 : }
802 :
803 : /* Casting operations. */
804 : template <class NodeType>
805 106296 : inline NodeType& as() {
806 106296 : MOZ_ASSERT(NodeType::test(*this));
807 106296 : return *static_cast<NodeType*>(this);
808 : }
809 :
810 : template <class NodeType>
811 : inline const NodeType& as() const {
812 : MOZ_ASSERT(NodeType::test(*this));
813 : return *static_cast<const NodeType*>(this);
814 : }
815 :
816 : #ifdef DEBUG
817 : void dump();
818 : void dump(int indent);
819 : #endif
820 : };
821 :
822 : struct NullaryNode : public ParseNode
823 : {
824 10486 : NullaryNode(ParseNodeKind kind, const TokenPos& pos)
825 10486 : : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {}
826 169 : NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
827 169 : : ParseNode(kind, op, PN_NULLARY, pos) {}
828 :
829 : // This constructor is for a few mad uses in the emitter. It populates
830 : // the pn_atom field even though that field belongs to a branch in pn_u
831 : // that nullary nodes shouldn't use -- bogus.
832 26573 : NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, JSAtom* atom)
833 26573 : : ParseNode(kind, op, PN_NULLARY, pos)
834 : {
835 26573 : pn_atom = atom;
836 26573 : }
837 :
838 : #ifdef DEBUG
839 : void dump();
840 : #endif
841 : };
842 :
843 : struct UnaryNode : public ParseNode
844 : {
845 33459 : UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* kid)
846 33459 : : ParseNode(kind, op, PN_UNARY, pos)
847 : {
848 33459 : pn_kid = kid;
849 33459 : }
850 :
851 : #ifdef DEBUG
852 : void dump(int indent);
853 : #endif
854 : };
855 :
856 : struct BinaryNode : public ParseNode
857 : {
858 17596 : BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* left, ParseNode* right)
859 17596 : : ParseNode(kind, op, PN_BINARY, pos)
860 : {
861 17596 : pn_left = left;
862 17596 : pn_right = right;
863 17596 : }
864 :
865 12 : BinaryNode(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right)
866 12 : : ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
867 : {
868 12 : pn_left = left;
869 12 : pn_right = right;
870 12 : }
871 :
872 : #ifdef DEBUG
873 : void dump(int indent);
874 : #endif
875 : };
876 :
877 : struct TernaryNode : public ParseNode
878 : {
879 7496 : TernaryNode(ParseNodeKind kind, JSOp op, ParseNode* kid1, ParseNode* kid2, ParseNode* kid3)
880 7496 : : ParseNode(kind, op, PN_TERNARY,
881 14992 : TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
882 14992 : (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end))
883 : {
884 7496 : pn_kid1 = kid1;
885 7496 : pn_kid2 = kid2;
886 7496 : pn_kid3 = kid3;
887 7496 : }
888 :
889 1323 : TernaryNode(ParseNodeKind kind, JSOp op, ParseNode* kid1, ParseNode* kid2, ParseNode* kid3,
890 : const TokenPos& pos)
891 1323 : : ParseNode(kind, op, PN_TERNARY, pos)
892 : {
893 1323 : pn_kid1 = kid1;
894 1323 : pn_kid2 = kid2;
895 1323 : pn_kid3 = kid3;
896 1323 : }
897 :
898 : #ifdef DEBUG
899 : void dump(int indent);
900 : #endif
901 : };
902 :
903 : struct ListNode : public ParseNode
904 : {
905 16703 : ListNode(ParseNodeKind kind, const TokenPos& pos)
906 16703 : : ParseNode(kind, JSOP_NOP, PN_LIST, pos)
907 : {
908 16703 : makeEmpty();
909 16703 : }
910 :
911 37713 : ListNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
912 37713 : : ParseNode(kind, op, PN_LIST, pos)
913 : {
914 37713 : makeEmpty();
915 37713 : }
916 :
917 11130 : ListNode(ParseNodeKind kind, JSOp op, ParseNode* kid)
918 11130 : : ParseNode(kind, op, PN_LIST, kid->pn_pos)
919 : {
920 11130 : initList(kid);
921 11130 : }
922 :
923 3013 : static bool test(const ParseNode& node) {
924 3013 : return node.isArity(PN_LIST);
925 : }
926 :
927 : #ifdef DEBUG
928 : void dump(int indent);
929 : #endif
930 : };
931 :
932 : struct CodeNode : public ParseNode
933 : {
934 7161 : CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
935 7161 : : ParseNode(kind, op, PN_CODE, pos)
936 : {
937 7161 : MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE);
938 7161 : MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP);
939 7161 : MOZ_ASSERT(op == JSOP_NOP || // statement, module
940 : op == JSOP_LAMBDA_ARROW || // arrow function
941 : op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c.
942 7161 : MOZ_ASSERT(!pn_body);
943 7161 : MOZ_ASSERT(!pn_objbox);
944 7161 : }
945 :
946 : public:
947 : #ifdef DEBUG
948 : void dump(int indent);
949 : #endif
950 : };
951 :
952 : struct NameNode : public ParseNode
953 : {
954 91188 : NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, const TokenPos& pos)
955 91188 : : ParseNode(kind, op, PN_NAME, pos)
956 : {
957 91188 : pn_atom = atom;
958 91188 : pn_expr = nullptr;
959 91188 : }
960 :
961 : #ifdef DEBUG
962 : void dump(int indent);
963 : #endif
964 : };
965 :
966 : struct LexicalScopeNode : public ParseNode
967 : {
968 12798 : LexicalScopeNode(LexicalScope::Data* bindings, ParseNode* body)
969 12798 : : ParseNode(PNK_LEXICALSCOPE, JSOP_NOP, PN_SCOPE, body->pn_pos)
970 : {
971 12798 : pn_u.scope.bindings = bindings;
972 12798 : pn_u.scope.body = body;
973 12798 : }
974 :
975 84 : static bool test(const ParseNode& node) {
976 84 : return node.isKind(PNK_LEXICALSCOPE);
977 : }
978 :
979 : #ifdef DEBUG
980 : void dump(int indent);
981 : #endif
982 : };
983 :
984 : class LabeledStatement : public ParseNode
985 : {
986 : public:
987 0 : LabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin)
988 0 : : ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos(begin, stmt->pn_pos.end))
989 : {
990 0 : pn_atom = label;
991 0 : pn_expr = stmt;
992 0 : }
993 :
994 0 : PropertyName* label() const {
995 0 : return pn_atom->asPropertyName();
996 : }
997 :
998 0 : ParseNode* statement() const {
999 0 : return pn_expr;
1000 : }
1001 :
1002 0 : static bool test(const ParseNode& node) {
1003 0 : bool match = node.isKind(PNK_LABEL);
1004 0 : MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
1005 0 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1006 0 : return match;
1007 : }
1008 : };
1009 :
1010 : // Inside a switch statement, a CaseClause is a case-label and the subsequent
1011 : // statements. The same node type is used for DefaultClauses. The only
1012 : // difference is that their caseExpression() is null.
1013 : class CaseClause : public BinaryNode
1014 : {
1015 : public:
1016 1112 : CaseClause(ParseNode* expr, ParseNode* stmts, uint32_t begin)
1017 1112 : : BinaryNode(PNK_CASE, JSOP_NOP, TokenPos(begin, stmts->pn_pos.end), expr, stmts) {}
1018 :
1019 4578 : ParseNode* caseExpression() const { return pn_left; }
1020 2770 : bool isDefault() const { return !caseExpression(); }
1021 1116 : ParseNode* statementList() const { return pn_right; }
1022 :
1023 : // The next CaseClause in the same switch statement.
1024 3342 : CaseClause* next() const { return pn_next ? &pn_next->as<CaseClause>() : nullptr; }
1025 :
1026 : // Scratch space used by the emitter.
1027 1059 : uint32_t offset() const { return pn_u.binary.offset; }
1028 1622 : void setOffset(uint32_t u) { pn_u.binary.offset = u; }
1029 :
1030 2926 : static bool test(const ParseNode& node) {
1031 2926 : bool match = node.isKind(PNK_CASE);
1032 2926 : MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
1033 2926 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1034 2926 : return match;
1035 : }
1036 : };
1037 :
1038 : class LoopControlStatement : public ParseNode
1039 : {
1040 : protected:
1041 597 : LoopControlStatement(ParseNodeKind kind, PropertyName* label, const TokenPos& pos)
1042 597 : : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos)
1043 : {
1044 597 : MOZ_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE);
1045 597 : pn_u.loopControl.label = label;
1046 597 : }
1047 :
1048 : public:
1049 : /* Label associated with this break/continue statement, if any. */
1050 600 : PropertyName* label() const {
1051 600 : return pn_u.loopControl.label;
1052 : }
1053 :
1054 0 : static bool test(const ParseNode& node) {
1055 0 : bool match = node.isKind(PNK_BREAK) || node.isKind(PNK_CONTINUE);
1056 0 : MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1057 0 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1058 0 : return match;
1059 : }
1060 : };
1061 :
1062 : class BreakStatement : public LoopControlStatement
1063 : {
1064 : public:
1065 476 : BreakStatement(PropertyName* label, const TokenPos& pos)
1066 476 : : LoopControlStatement(PNK_BREAK, label, pos)
1067 476 : { }
1068 :
1069 479 : static bool test(const ParseNode& node) {
1070 479 : bool match = node.isKind(PNK_BREAK);
1071 479 : MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1072 479 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1073 479 : return match;
1074 : }
1075 : };
1076 :
1077 : class ContinueStatement : public LoopControlStatement
1078 : {
1079 : public:
1080 121 : ContinueStatement(PropertyName* label, const TokenPos& pos)
1081 121 : : LoopControlStatement(PNK_CONTINUE, label, pos)
1082 121 : { }
1083 :
1084 121 : static bool test(const ParseNode& node) {
1085 121 : bool match = node.isKind(PNK_CONTINUE);
1086 121 : MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1087 121 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1088 121 : return match;
1089 : }
1090 : };
1091 :
1092 : class DebuggerStatement : public ParseNode
1093 : {
1094 : public:
1095 0 : explicit DebuggerStatement(const TokenPos& pos)
1096 0 : : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos)
1097 0 : { }
1098 : };
1099 :
1100 : class ConditionalExpression : public ParseNode
1101 : {
1102 : public:
1103 652 : ConditionalExpression(ParseNode* condition, ParseNode* thenExpr, ParseNode* elseExpr)
1104 652 : : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
1105 652 : TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end))
1106 : {
1107 652 : MOZ_ASSERT(condition);
1108 652 : MOZ_ASSERT(thenExpr);
1109 652 : MOZ_ASSERT(elseExpr);
1110 652 : pn_u.ternary.kid1 = condition;
1111 652 : pn_u.ternary.kid2 = thenExpr;
1112 652 : pn_u.ternary.kid3 = elseExpr;
1113 652 : }
1114 :
1115 657 : ParseNode& condition() const {
1116 657 : return *pn_u.ternary.kid1;
1117 : }
1118 :
1119 657 : ParseNode& thenExpression() const {
1120 657 : return *pn_u.ternary.kid2;
1121 : }
1122 :
1123 657 : ParseNode& elseExpression() const {
1124 657 : return *pn_u.ternary.kid3;
1125 : }
1126 :
1127 657 : static bool test(const ParseNode& node) {
1128 657 : bool match = node.isKind(PNK_CONDITIONAL);
1129 657 : MOZ_ASSERT_IF(match, node.isArity(PN_TERNARY));
1130 657 : MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1131 657 : return match;
1132 : }
1133 : };
1134 :
1135 : class ThisLiteral : public UnaryNode
1136 : {
1137 : public:
1138 7628 : ThisLiteral(const TokenPos& pos, ParseNode* thisName)
1139 7628 : : UnaryNode(PNK_THIS, JSOP_NOP, pos, thisName)
1140 7628 : { }
1141 : };
1142 :
1143 : class NullLiteral : public ParseNode
1144 : {
1145 : public:
1146 2043 : explicit NullLiteral(const TokenPos& pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
1147 : };
1148 :
1149 : // This is only used internally, currently just for tagged templates.
1150 : // It represents the value 'undefined' (aka `void 0`), like NullLiteral
1151 : // represents the value 'null'.
1152 : class RawUndefinedLiteral : public ParseNode
1153 : {
1154 : public:
1155 0 : explicit RawUndefinedLiteral(const TokenPos& pos)
1156 0 : : ParseNode(PNK_RAW_UNDEFINED, JSOP_UNDEFINED, PN_NULLARY, pos) { }
1157 : };
1158 :
1159 : class BooleanLiteral : public ParseNode
1160 : {
1161 : public:
1162 2325 : BooleanLiteral(bool b, const TokenPos& pos)
1163 2325 : : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos)
1164 2325 : { }
1165 : };
1166 :
1167 : class RegExpLiteral : public NullaryNode
1168 : {
1169 : public:
1170 169 : RegExpLiteral(ObjectBox* reobj, const TokenPos& pos)
1171 169 : : NullaryNode(PNK_REGEXP, JSOP_REGEXP, pos)
1172 : {
1173 169 : pn_objbox = reobj;
1174 169 : }
1175 :
1176 172 : ObjectBox* objbox() const { return pn_objbox; }
1177 :
1178 172 : static bool test(const ParseNode& node) {
1179 172 : bool match = node.isKind(PNK_REGEXP);
1180 172 : MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1181 172 : MOZ_ASSERT_IF(match, node.isOp(JSOP_REGEXP));
1182 172 : return match;
1183 : }
1184 : };
1185 :
1186 : class PropertyAccess : public ParseNode
1187 : {
1188 : public:
1189 28199 : PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
1190 28199 : : ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end))
1191 : {
1192 28199 : MOZ_ASSERT(lhs != nullptr);
1193 28199 : MOZ_ASSERT(name != nullptr);
1194 28199 : pn_u.name.expr = lhs;
1195 28199 : pn_u.name.atom = name;
1196 28199 : }
1197 :
1198 113719 : static bool test(const ParseNode& node) {
1199 113719 : bool match = node.isKind(PNK_DOT);
1200 113719 : MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
1201 113719 : return match;
1202 : }
1203 :
1204 81781 : ParseNode& expression() const {
1205 81781 : return *pn_u.name.expr;
1206 : }
1207 :
1208 10838 : PropertyName& name() const {
1209 10838 : return *pn_u.name.atom->asPropertyName();
1210 : }
1211 :
1212 81768 : bool isSuper() const {
1213 : // PNK_SUPERBASE cannot result from any expression syntax.
1214 81768 : return expression().isKind(PNK_SUPERBASE);
1215 : }
1216 : };
1217 :
1218 : class PropertyByValue : public ParseNode
1219 : {
1220 : public:
1221 3043 : PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin, uint32_t end)
1222 3043 : : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
1223 : {
1224 3043 : pn_u.binary.left = lhs;
1225 3043 : pn_u.binary.right = propExpr;
1226 3043 : }
1227 :
1228 6011 : static bool test(const ParseNode& node) {
1229 6011 : bool match = node.isKind(PNK_ELEM);
1230 6011 : MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
1231 6011 : return match;
1232 : }
1233 :
1234 6011 : bool isSuper() const {
1235 6011 : return pn_left->isKind(PNK_SUPERBASE);
1236 : }
1237 : };
1238 :
1239 : /*
1240 : * A CallSiteNode represents the implicit call site object argument in a TaggedTemplate.
1241 : */
1242 : struct CallSiteNode : public ListNode {
1243 1 : explicit CallSiteNode(uint32_t begin): ListNode(PNK_CALLSITEOBJ, TokenPos(begin, begin + 1)) {}
1244 :
1245 1 : static bool test(const ParseNode& node) {
1246 1 : return node.isKind(PNK_CALLSITEOBJ);
1247 : }
1248 :
1249 1 : MOZ_MUST_USE bool getRawArrayValue(JSContext* cx, MutableHandleValue vp) {
1250 1 : return pn_head->getConstantValue(cx, AllowObjects, vp);
1251 : }
1252 : };
1253 :
1254 : struct ClassMethod : public BinaryNode {
1255 : /*
1256 : * Method defintions often keep a name and function body that overlap,
1257 : * so explicitly define the beginning and end here.
1258 : */
1259 156 : ClassMethod(ParseNode* name, ParseNode* body, JSOp op, bool isStatic)
1260 156 : : BinaryNode(PNK_CLASSMETHOD, op, TokenPos(name->pn_pos.begin, body->pn_pos.end), name, body)
1261 : {
1262 156 : pn_u.binary.isStatic = isStatic;
1263 156 : }
1264 :
1265 218 : static bool test(const ParseNode& node) {
1266 218 : bool match = node.isKind(PNK_CLASSMETHOD);
1267 218 : MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
1268 218 : return match;
1269 : }
1270 :
1271 31 : ParseNode& name() const {
1272 31 : return *pn_u.binary.left;
1273 : }
1274 31 : ParseNode& method() const {
1275 31 : return *pn_u.binary.right;
1276 : }
1277 218 : bool isStatic() const {
1278 218 : return pn_u.binary.isStatic;
1279 : }
1280 : };
1281 :
1282 : struct ClassNames : public BinaryNode {
1283 26 : ClassNames(ParseNode* outerBinding, ParseNode* innerBinding, const TokenPos& pos)
1284 26 : : BinaryNode(PNK_CLASSNAMES, JSOP_NOP, pos, outerBinding, innerBinding)
1285 : {
1286 26 : MOZ_ASSERT_IF(outerBinding, outerBinding->isKind(PNK_NAME));
1287 26 : MOZ_ASSERT(innerBinding->isKind(PNK_NAME));
1288 26 : MOZ_ASSERT_IF(outerBinding, innerBinding->pn_atom == outerBinding->pn_atom);
1289 26 : }
1290 :
1291 52 : static bool test(const ParseNode& node) {
1292 52 : bool match = node.isKind(PNK_CLASSNAMES);
1293 52 : MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
1294 52 : return match;
1295 : }
1296 :
1297 : /*
1298 : * Classes require two definitions: The first "outer" binding binds the
1299 : * class into the scope in which it was declared. the outer binding is a
1300 : * mutable lexial binding. The second "inner" binding binds the class by
1301 : * name inside a block in which the methods are evaulated. It is immutable,
1302 : * giving the methods access to the static members of the class even if
1303 : * the outer binding has been overwritten.
1304 : */
1305 26 : ParseNode* outerBinding() const {
1306 26 : return pn_u.binary.left;
1307 : }
1308 27 : ParseNode* innerBinding() const {
1309 27 : return pn_u.binary.right;
1310 : }
1311 : };
1312 :
1313 : struct ClassNode : public TernaryNode {
1314 32 : ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock,
1315 : const TokenPos& pos)
1316 32 : : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos)
1317 : {
1318 32 : MOZ_ASSERT_IF(names, names->is<ClassNames>());
1319 32 : MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() ||
1320 : methodsOrBlock->isKind(PNK_CLASSMETHODLIST));
1321 32 : }
1322 :
1323 22448 : static bool test(const ParseNode& node) {
1324 22448 : bool match = node.isKind(PNK_CLASS);
1325 22448 : MOZ_ASSERT_IF(match, node.isArity(PN_TERNARY));
1326 22448 : return match;
1327 : }
1328 :
1329 38 : ClassNames* names() const {
1330 38 : return pn_kid1 ? &pn_kid1->as<ClassNames>() : nullptr;
1331 : }
1332 32 : ParseNode* heritage() const {
1333 32 : return pn_kid2;
1334 : }
1335 32 : ParseNode* methodList() const {
1336 32 : if (pn_kid3->isKind(PNK_CLASSMETHODLIST))
1337 6 : return pn_kid3;
1338 :
1339 26 : MOZ_ASSERT(pn_kid3->is<LexicalScopeNode>());
1340 26 : ParseNode* list = pn_kid3->scopeBody();
1341 26 : MOZ_ASSERT(list->isKind(PNK_CLASSMETHODLIST));
1342 26 : return list;
1343 : }
1344 26 : Handle<LexicalScope::Data*> scopeBindings() const {
1345 26 : MOZ_ASSERT(pn_kid3->is<LexicalScopeNode>());
1346 26 : return pn_kid3->scopeBindings();
1347 : }
1348 : };
1349 :
1350 : #ifdef DEBUG
1351 : void DumpParseTree(ParseNode* pn, int indent = 0);
1352 : #endif
1353 :
1354 : class ParseNodeAllocator
1355 : {
1356 : public:
1357 1690 : explicit ParseNodeAllocator(JSContext* cx, LifoAlloc& alloc)
1358 1690 : : cx(cx), alloc(alloc), freelist(nullptr)
1359 1690 : {}
1360 :
1361 : void* allocNode();
1362 : void freeNode(ParseNode* pn);
1363 : ParseNode* freeTree(ParseNode* pn);
1364 : void prepareNodeForMutation(ParseNode* pn);
1365 :
1366 : private:
1367 : JSContext* cx;
1368 : LifoAlloc& alloc;
1369 : ParseNode* freelist;
1370 : };
1371 :
1372 : inline bool
1373 9258 : ParseNode::isConstant()
1374 : {
1375 9258 : switch (pn_type) {
1376 : case PNK_NUMBER:
1377 : case PNK_STRING:
1378 : case PNK_TEMPLATE_STRING:
1379 : case PNK_NULL:
1380 : case PNK_RAW_UNDEFINED:
1381 : case PNK_FALSE:
1382 : case PNK_TRUE:
1383 5251 : return true;
1384 : case PNK_ARRAY:
1385 : case PNK_OBJECT:
1386 1357 : MOZ_ASSERT(isOp(JSOP_NEWINIT));
1387 1357 : return !(pn_xflags & PNX_NONCONST);
1388 : default:
1389 2650 : return false;
1390 : }
1391 : }
1392 :
1393 : class ObjectBox
1394 : {
1395 : public:
1396 : JSObject* object;
1397 :
1398 : ObjectBox(JSObject* object, ObjectBox* traceLink);
1399 7633 : bool isFunctionBox() { return object->is<JSFunction>(); }
1400 : FunctionBox* asFunctionBox();
1401 : virtual void trace(JSTracer* trc);
1402 :
1403 : static void TraceList(JSTracer* trc, ObjectBox* listHead);
1404 :
1405 : protected:
1406 : friend struct CGObjectList;
1407 :
1408 : ObjectBox* traceLink;
1409 : ObjectBox* emitLink;
1410 :
1411 : ObjectBox(JSFunction* function, ObjectBox* traceLink);
1412 : };
1413 :
1414 : enum ParseReportKind
1415 : {
1416 : ParseError,
1417 : ParseWarning,
1418 : ParseExtraWarning,
1419 : ParseStrictError
1420 : };
1421 :
1422 : enum FunctionSyntaxKind
1423 : {
1424 : Expression,
1425 : Statement,
1426 : Arrow,
1427 : Method,
1428 : ClassConstructor,
1429 : DerivedClassConstructor,
1430 : Getter,
1431 : GetterNoExpressionClosure,
1432 : Setter,
1433 : SetterNoExpressionClosure
1434 : };
1435 :
1436 : static inline bool
1437 4913 : IsConstructorKind(FunctionSyntaxKind kind)
1438 : {
1439 4913 : return kind == ClassConstructor || kind == DerivedClassConstructor;
1440 : }
1441 :
1442 : static inline bool
1443 9765 : IsGetterKind(FunctionSyntaxKind kind)
1444 : {
1445 9765 : return kind == Getter || kind == GetterNoExpressionClosure;
1446 : }
1447 :
1448 : static inline bool
1449 15103 : IsSetterKind(FunctionSyntaxKind kind)
1450 : {
1451 15103 : return kind == Setter || kind == SetterNoExpressionClosure;
1452 : }
1453 :
1454 : static inline bool
1455 7373 : IsMethodDefinitionKind(FunctionSyntaxKind kind)
1456 : {
1457 9787 : return kind == Method || IsConstructorKind(kind) ||
1458 16767 : IsGetterKind(kind) || IsSetterKind(kind);
1459 : }
1460 :
1461 : static inline ParseNode*
1462 0 : FunctionFormalParametersList(ParseNode* fn, unsigned* numFormals)
1463 : {
1464 0 : MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
1465 0 : ParseNode* argsBody = fn->pn_body;
1466 0 : MOZ_ASSERT(argsBody->isKind(PNK_PARAMSBODY));
1467 0 : *numFormals = argsBody->pn_count;
1468 0 : if (*numFormals > 0 &&
1469 0 : argsBody->last()->isKind(PNK_LEXICALSCOPE) &&
1470 0 : argsBody->last()->scopeBody()->isKind(PNK_STATEMENTLIST))
1471 : {
1472 0 : (*numFormals)--;
1473 : }
1474 0 : MOZ_ASSERT(argsBody->isArity(PN_LIST));
1475 0 : return argsBody->pn_head;
1476 : }
1477 :
1478 : bool
1479 : IsAnonymousFunctionDefinition(ParseNode* pn);
1480 :
1481 : } /* namespace frontend */
1482 : } /* namespace js */
1483 :
1484 : #endif /* frontend_ParseNode_h */
|