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