Bumping manifests a=b2g-bump
[gecko.git] / js / src / frontend / ParseNode.h
blobc6c7d65dd17587d1b7b26f5fea88ae54b72b1425
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/. */
7 #ifndef frontend_ParseNode_h
8 #define frontend_ParseNode_h
10 #include "mozilla/Attributes.h"
12 #include "frontend/TokenStream.h"
14 namespace js {
15 namespace frontend {
17 template <typename ParseHandler>
18 struct ParseContext;
20 class FullParseHandler;
21 class FunctionBox;
22 class ObjectBox;
25 * Indicates a location in the stack that an upvar value can be retrieved from
26 * as a two tuple of (level, slot).
28 * Some existing client code uses the level value as a delta, or level "skip"
29 * quantity. We could probably document that through use of more types at some
30 * point in the future.
32 class UpvarCookie
34 uint32_t level_ : SCOPECOORD_HOPS_BITS;
35 uint32_t slot_ : SCOPECOORD_SLOT_BITS;
37 void checkInvariants() {
38 static_assert(sizeof(UpvarCookie) == sizeof(uint32_t),
39 "Not necessary for correctness, but good for ParseNode memory use");
42 public:
43 // Steal one value to represent the sentinel value for UpvarCookie.
44 static const uint32_t FREE_LEVEL = SCOPECOORD_HOPS_LIMIT - 1;
45 bool isFree() const { return level_ == FREE_LEVEL; }
47 uint32_t level() const { MOZ_ASSERT(!isFree()); return level_; }
48 uint32_t slot() const { MOZ_ASSERT(!isFree()); return slot_; }
50 // This fails and issues an error message if newLevel or newSlot are too large.
51 bool set(TokenStream& ts, unsigned newLevel, uint32_t newSlot) {
52 if (newLevel >= FREE_LEVEL)
53 return ts.reportError(JSMSG_TOO_DEEP, js_function_str);
55 if (newSlot >= SCOPECOORD_SLOT_LIMIT)
56 return ts.reportError(JSMSG_TOO_MANY_LOCALS);
58 level_ = newLevel;
59 slot_ = newSlot;
60 return true;
63 void makeFree() {
64 level_ = FREE_LEVEL;
65 slot_ = 0; // value doesn't matter, won't be used
66 MOZ_ASSERT(isFree());
70 #define FOR_EACH_PARSE_NODE_KIND(F) \
71 F(NOP) \
72 F(SEMI) \
73 F(COMMA) \
74 F(CONDITIONAL) \
75 F(COLON) \
76 F(SHORTHAND) \
77 F(POS) \
78 F(NEG) \
79 F(PREINCREMENT) \
80 F(POSTINCREMENT) \
81 F(PREDECREMENT) \
82 F(POSTDECREMENT) \
83 F(DOT) \
84 F(ELEM) \
85 F(ARRAY) \
86 F(ELISION) \
87 F(STATEMENTLIST) \
88 F(LABEL) \
89 F(OBJECT) \
90 F(CALL) \
91 F(NAME) \
92 F(COMPUTED_NAME) \
93 F(NUMBER) \
94 F(STRING) \
95 F(TEMPLATE_STRING_LIST) \
96 F(TEMPLATE_STRING) \
97 F(TAGGED_TEMPLATE) \
98 F(CALLSITEOBJ) \
99 F(REGEXP) \
100 F(TRUE) \
101 F(FALSE) \
102 F(NULL) \
103 F(THIS) \
104 F(FUNCTION) \
105 F(IF) \
106 F(ELSE) \
107 F(SWITCH) \
108 F(CASE) \
109 F(DEFAULT) \
110 F(WHILE) \
111 F(DOWHILE) \
112 F(FOR) \
113 F(BREAK) \
114 F(CONTINUE) \
115 F(VAR) \
116 F(CONST) \
117 F(GLOBALCONST) \
118 F(WITH) \
119 F(RETURN) \
120 F(NEW) \
121 F(DELETE) \
122 F(TRY) \
123 F(CATCH) \
124 F(CATCHLIST) \
125 F(FINALLY) \
126 F(THROW) \
127 F(DEBUGGER) \
128 F(GENERATOR) \
129 F(YIELD) \
130 F(YIELD_STAR) \
131 F(GENEXP) \
132 F(ARRAYCOMP) \
133 F(ARRAYPUSH) \
134 F(LEXICALSCOPE) \
135 F(LET) \
136 F(IMPORT) \
137 F(IMPORT_SPEC_LIST) \
138 F(IMPORT_SPEC) \
139 F(EXPORT) \
140 F(EXPORT_FROM) \
141 F(EXPORT_SPEC_LIST) \
142 F(EXPORT_SPEC) \
143 F(EXPORT_BATCH_SPEC) \
144 F(SEQ) \
145 F(FORIN) \
146 F(FOROF) \
147 F(FORHEAD) \
148 F(ARGSBODY) \
149 F(SPREAD) \
150 F(MUTATEPROTO) \
152 /* Unary operators. */ \
153 F(TYPEOF) \
154 F(VOID) \
155 F(NOT) \
156 F(BITNOT) \
158 /* \
159 * Binary operators. \
160 * These must be in the same order as TOK_OR and friends in TokenStream.h. \
161 */ \
162 F(OR) \
163 F(AND) \
164 F(BITOR) \
165 F(BITXOR) \
166 F(BITAND) \
167 F(STRICTEQ) \
168 F(EQ) \
169 F(STRICTNE) \
170 F(NE) \
171 F(LT) \
172 F(LE) \
173 F(GT) \
174 F(GE) \
175 F(INSTANCEOF) \
176 F(IN) \
177 F(LSH) \
178 F(RSH) \
179 F(URSH) \
180 F(ADD) \
181 F(SUB) \
182 F(STAR) \
183 F(DIV) \
184 F(MOD) \
186 /* Assignment operators (= += -= etc.). */ \
187 /* ParseNode::isAssignment assumes all these are consecutive. */ \
188 F(ASSIGN) \
189 F(ADDASSIGN) \
190 F(SUBASSIGN) \
191 F(BITORASSIGN) \
192 F(BITXORASSIGN) \
193 F(BITANDASSIGN) \
194 F(LSHASSIGN) \
195 F(RSHASSIGN) \
196 F(URSHASSIGN) \
197 F(MULASSIGN) \
198 F(DIVASSIGN) \
199 F(MODASSIGN)
202 * Parsing builds a tree of nodes that directs code generation. This tree is
203 * not a concrete syntax tree in all respects (for example, || and && are left
204 * associative, but (A && B && C) translates into the right-associated tree
205 * <A && <B && C>> so that code generation can emit a left-associative branch
206 * around <B && C> when A is false). Nodes are labeled by kind, with a
207 * secondary JSOp label when needed.
209 * The long comment after this enum block describes the kinds in detail.
211 enum ParseNodeKind
213 #define EMIT_ENUM(name) PNK_##name,
214 FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
215 #undef EMIT_ENUM
216 PNK_LIMIT, /* domain size */
217 PNK_BINOP_FIRST = PNK_OR,
218 PNK_BINOP_LAST = PNK_MOD,
219 PNK_ASSIGNMENT_START = PNK_ASSIGN,
220 PNK_ASSIGNMENT_LAST = PNK_MODASSIGN
224 * Label Variant Members
225 * ----- ------- -------
226 * <Definitions>
227 * PNK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function
228 * object containing arg and var properties. We
229 * create the function object at parse (not emit)
230 * time to specialize arg and var bytecodes early.
231 * pn_body: PNK_ARGSBODY, ordinarily;
232 * PNK_LEXICALSCOPE for implicit function in genexpr
233 * pn_cookie: static level and var index for function
234 * pn_dflags: PND_* definition/use flags (see below)
235 * pn_blockid: block id number
236 * PNK_ARGSBODY list list of formal parameters followed by:
237 * PNK_STATEMENTLIST node for function body
238 * statements,
239 * PNK_RETURN for expression closure, or
240 * PNK_SEQ for expression closure with
241 * destructured formal parameters
242 * pn_count: 1 + number of formal parameters
243 * pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node
244 * PNK_SPREAD unary pn_kid: expression being spread
246 * <Statements>
247 * PNK_STATEMENTLIST list pn_head: list of pn_count statements
248 * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
249 * In body of a comprehension or desugared generator
250 * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH,
251 * or (if the push was optimized away) empty
252 * PNK_STATEMENTLIST.
253 * PNK_SWITCH binary pn_left: discriminant
254 * pn_right: list of PNK_CASE nodes, with at most one
255 * PNK_DEFAULT node, or if there are let bindings
256 * in the top level of the switch body's cases, a
257 * PNK_LEXICALSCOPE node that contains the list of
258 * PNK_CASE nodes.
259 * PNK_CASE, binary pn_left: case expr
260 * pn_right: PNK_STATEMENTLIST node for this case's
261 * statements
262 * PNK_DEFAULT binary pn_left: null
263 * pn_right: PNK_STATEMENTLIST node for this default's
264 * statements
265 * pn_val: constant value if lookup or table switch
266 * PNK_WHILE binary pn_left: cond, pn_right: body
267 * PNK_DOWHILE binary pn_left: body, pn_right: cond
268 * PNK_FOR binary pn_left: either PNK_FORIN (for-in statement),
269 * PNK_FOROF (for-of) or PNK_FORHEAD (for(;;))
270 * pn_right: body
271 * PNK_FORIN ternary pn_kid1: PNK_VAR to left of 'in', or nullptr
272 * its pn_xflags may have PNX_POPVAR
273 * bit set
274 * pn_kid2: PNK_NAME or destructuring expr
275 * to left of 'in'; if pn_kid1, then this
276 * is a clone of pn_kid1->pn_head
277 * pn_kid3: object expr to right of 'in'
278 * PNK_FOROF ternary pn_kid1: PNK_VAR to left of 'of', or nullptr
279 * its pn_xflags may have PNX_POPVAR
280 * bit set
281 * pn_kid2: PNK_NAME or destructuring expr
282 * to left of 'of'; if pn_kid1, then this
283 * is a clone of pn_kid1->pn_head
284 * pn_kid3: expr to right of 'of'
285 * PNK_FORHEAD ternary pn_kid1: init expr before first ';' or nullptr
286 * pn_kid2: cond expr before second ';' or nullptr
287 * pn_kid3: update expr after second ';' or nullptr
288 * PNK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
289 * PNK_TRY ternary pn_kid1: try block
290 * pn_kid2: null or PNK_CATCHLIST list of
291 * PNK_LEXICALSCOPE nodes, each with pn_expr pointing
292 * to a PNK_CATCH node
293 * pn_kid3: null or finally block
294 * PNK_CATCH ternary pn_kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch var node
295 * (PNK_ARRAY or PNK_OBJECT if destructuring)
296 * pn_kid2: null or the catch guard expression
297 * pn_kid3: catch block statements
298 * PNK_BREAK name pn_atom: label or null
299 * PNK_CONTINUE name pn_atom: label or null
300 * PNK_WITH binary-obj pn_left: head expr; pn_right: body; pn_binary_obj: StaticWithObject
301 * PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes
302 * PNK_CONST each name node has either
303 * pn_used: false
304 * pn_atom: variable name
305 * pn_expr: initializer or null
306 * or
307 * pn_used: true
308 * pn_atom: variable name
309 * pn_lexdef: def node
310 * each assignment node has
311 * pn_left: PNK_NAME with pn_used true and
312 * pn_lexdef (NOT pn_expr) set
313 * pn_right: initializer
314 * PNK_RETURN binary pn_left: return expr or null
315 * pn_right: .genrval name or null
316 * PNK_SEMI unary pn_kid: expr or null statement
317 * pn_prologue: true if Directive Prologue member
318 * in original source, not introduced via
319 * constant folding or other tree rewriting
320 * PNK_LABEL name pn_atom: label, pn_expr: labeled statement
322 * <Expressions>
323 * All left-associated binary trees of the same type are optimized into lists
324 * to avoid recursion when processing expression chains.
325 * PNK_COMMA list pn_head: list of pn_count comma-separated exprs
326 * PNK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
327 * PNK_ADDASSIGN, binary pn_left: lvalue, pn_right: rvalue
328 * PNK_SUBASSIGN, pn_op: JSOP_ADD for +=, etc.
329 * PNK_BITORASSIGN,
330 * PNK_BITXORASSIGN,
331 * PNK_BITANDASSIGN,
332 * PNK_LSHASSIGN,
333 * PNK_RSHASSIGN,
334 * PNK_URSHASSIGN,
335 * PNK_MULASSIGN,
336 * PNK_DIVASSIGN,
337 * PNK_MODASSIGN
338 * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
339 * pn_kid1: cond, pn_kid2: then, pn_kid3: else
340 * PNK_OR binary pn_left: first in || chain, pn_right: rest of chain
341 * PNK_AND binary pn_left: first in && chain, pn_right: rest of chain
342 * PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
343 * PNK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr
344 * PNK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr
346 * PNK_EQ, binary pn_left: left-assoc EQ expr, pn_right: REL expr
347 * PNK_NE,
348 * PNK_STRICTEQ,
349 * PNK_STRICTNE
350 * PNK_LT, binary pn_left: left-assoc REL expr, pn_right: SH expr
351 * PNK_LE,
352 * PNK_GT,
353 * PNK_GE
354 * PNK_LSH, binary pn_left: left-assoc SH expr, pn_right: ADD expr
355 * PNK_RSH,
356 * PNK_URSH
357 * PNK_ADD binary pn_left: left-assoc ADD expr, pn_right: MUL expr
358 * pn_xflags: if a left-associated binary PNK_ADD
359 * tree has been flattened into a list (see above
360 * under <Expressions>), pn_xflags will contain
361 * PNX_STRCAT if at least one list element is a
362 * string literal (PNK_STRING); if such a list has
363 * any non-string, non-number term, pn_xflags will
364 * contain PNX_CANTFOLD.
365 * PNK_SUB binary pn_left: left-assoc SH expr, pn_right: ADD expr
366 * PNK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr
367 * PNK_DIV, pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
368 * PNK_MOD
369 * PNK_POS, unary pn_kid: UNARY expr
370 * PNK_NEG
371 * PNK_TYPEOF, unary pn_kid: UNARY expr
372 * PNK_VOID,
373 * PNK_NOT,
374 * PNK_BITNOT
375 * PNK_PREINCREMENT, unary pn_kid: MEMBER expr
376 * PNK_POSTINCREMENT,
377 * PNK_PREDECREMENT,
378 * PNK_POSTDECREMENT
379 * PNK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
380 * pn_count: 1 + N (where N is number of args)
381 * ctor is a MEMBER expr
382 * PNK_DELETE unary pn_kid: MEMBER expr
383 * PNK_DOT name pn_expr: MEMBER expr to left of .
384 * pn_atom: name to right of .
385 * PNK_ELEM binary pn_left: MEMBER expr to left of [
386 * pn_right: expr between [ and ]
387 * PNK_CALL list pn_head: list of call, arg1, arg2, ... argN
388 * pn_count: 1 + N (where N is number of args)
389 * call is a MEMBER expr naming a callable object
390 * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call
391 * in the desugaring of a generator-expression.
392 * PNK_ARRAY list pn_head: list of pn_count array element exprs
393 * [,,] holes are represented by PNK_ELISION nodes
394 * pn_xflags: PN_ENDCOMMA if extra comma at end
395 * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes
396 * PNK_COLON binary key-value pair in object initializer or
397 * destructuring lhs
398 * pn_left: property id, pn_right: value
399 * PNK_SHORTHAND binary Same fields as PNK_COLON. This is used for object
400 * literal properties using shorthand ({x}).
401 * PNK_COMPUTED_NAME unary ES6 ComputedPropertyName.
402 * pn_kid: the AssignmentExpression inside the square brackets
403 * PNK_NAME, name pn_atom: name, string, or object atom
404 * PNK_STRING pn_op: JSOP_GETNAME, JSOP_STRING, or JSOP_OBJECT
405 * If JSOP_GETNAME, pn_op may be JSOP_*ARG or JSOP_*VAR
406 * with pn_cookie telling (staticLevel, slot) (see
407 * jsscript.h's UPVAR macros) and pn_dflags telling
408 * const-ness and static analysis results
409 * PNK_TEMPLATE_STRING_LIST pn_head: list of alternating expr and template strings
410 * list
411 * PNK_TEMPLATE_STRING pn_atom: template string atom
412 nullary pn_op: JSOP_NOP
413 * PNK_TAGGED_TEMPLATE pn_head: list of call, call site object, arg1, arg2, ... argN
414 * list pn_count: 2 + N (N is the number of substitutions)
415 * PNK_CALLSITEOBJ list pn_head: a PNK_ARRAY node followed by
416 * list of pn_count - 1 PNK_TEMPLATE_STRING nodes
417 * PNK_REGEXP nullary pn_objbox: RegExp model object
418 * PNK_NAME name If pn_used, PNK_NAME uses the lexdef member instead
419 * of the expr member it overlays
420 * PNK_NUMBER dval pn_dval: double value of numeric literal
421 * PNK_TRUE, nullary pn_op: JSOp bytecode
422 * PNK_FALSE,
423 * PNK_NULL,
424 * PNK_THIS
426 * PNK_LEXICALSCOPE name pn_objbox: block object in ObjectBox holder
427 * pn_expr: block body
428 * PNK_GENERATOR nullary
429 * PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
430 * PNK_YIELD_STAR
431 * PNK_ARRAYCOMP list pn_count: 1
432 * pn_head: list of 1 element, which is block
433 * enclosing for loop(s) and optionally
434 * if-guarded PNK_ARRAYPUSH
435 * PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
436 * pn_kid: array comprehension expression
437 * PNK_NOP nullary
439 enum ParseNodeArity
441 PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
442 PN_UNARY, /* one kid, plus a couple of scalars */
443 PN_BINARY, /* two kids, plus a couple of scalars */
444 PN_BINARY_OBJ, /* two kids, plus an objbox */
445 PN_TERNARY, /* three kids */
446 PN_CODE, /* module or function definition node */
447 PN_LIST, /* generic singly linked list */
448 PN_NAME /* name use or definition node */
451 struct Definition;
453 class LabeledStatement;
454 class LoopControlStatement;
455 class BreakStatement;
456 class ContinueStatement;
457 class ConditionalExpression;
458 class PropertyAccess;
460 class ParseNode
462 uint32_t pn_type : 16, /* PNK_* type */
463 pn_op : 8, /* see JSOp enum and jsopcode.tbl */
464 pn_arity : 5, /* see ParseNodeArity enum */
465 pn_parens : 1, /* this expr was enclosed in parens */
466 pn_used : 1, /* name node is on a use-chain */
467 pn_defn : 1; /* this node is a Definition */
469 ParseNode(const ParseNode& other) = delete;
470 void operator=(const ParseNode& other) = delete;
472 public:
473 ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
474 : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
475 pn_pos(0, 0), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
477 MOZ_ASSERT(kind < PNK_LIMIT);
478 memset(&pn_u, 0, sizeof pn_u);
481 ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos& pos)
482 : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
483 pn_pos(pos), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
485 MOZ_ASSERT(kind < PNK_LIMIT);
486 memset(&pn_u, 0, sizeof pn_u);
489 JSOp getOp() const { return JSOp(pn_op); }
490 void setOp(JSOp op) { pn_op = op; }
491 bool isOp(JSOp op) const { return getOp() == op; }
493 ParseNodeKind getKind() const {
494 MOZ_ASSERT(pn_type < PNK_LIMIT);
495 return ParseNodeKind(pn_type);
497 void setKind(ParseNodeKind kind) {
498 MOZ_ASSERT(kind < PNK_LIMIT);
499 pn_type = kind;
501 bool isKind(ParseNodeKind kind) const { return getKind() == kind; }
503 ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); }
504 bool isArity(ParseNodeArity a) const { return getArity() == a; }
505 void setArity(ParseNodeArity a) { pn_arity = a; }
507 bool isAssignment() const {
508 ParseNodeKind kind = getKind();
509 return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
512 /* Boolean attributes. */
513 bool isInParens() const { return pn_parens; }
514 void setInParens(bool enabled) { pn_parens = enabled; }
515 bool isUsed() const { return pn_used; }
516 void setUsed(bool enabled) { pn_used = enabled; }
517 bool isDefn() const { return pn_defn; }
518 void setDefn(bool enabled) { pn_defn = enabled; }
520 static const unsigned NumDefinitionFlagBits = 10;
521 static const unsigned NumListFlagBits = 10;
522 static const unsigned NumBlockIdBits = 22;
523 static_assert(NumDefinitionFlagBits == NumListFlagBits,
524 "Assumed below to achieve consistent blockid offset");
525 static_assert(NumDefinitionFlagBits + NumBlockIdBits <= 32,
526 "This is supposed to fit in a single uint32_t");
528 TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
529 int32_t pn_offset; /* first generated bytecode offset */
530 ParseNode* pn_next; /* intrinsic link in parent PN_LIST */
533 * Nodes that represent lexical bindings may, in addition to being
534 * ParseNodes, also be Definition nodes. (Definition is defined far below,
535 * with a lengthy comment that you should read.) Each binding has one
536 * canonical Definition; all uses of that definition are reached starting
537 * from dn_uses, then following subsequent pn_link pointers.
539 * The dn_uses chain elements are unordered. Any apparent ordering in some
540 * cases, will not be present in all others.
542 union {
543 ParseNode* dn_uses;
544 ParseNode* pn_link;
547 union {
548 struct { /* list of next-linked nodes */
549 ParseNode* head; /* first node in list */
550 ParseNode** tail; /* ptr to ptr to last node in list */
551 uint32_t count; /* number of nodes in list */
552 uint32_t xflags:NumListFlagBits, /* see PNX_* below */
553 blockid:NumBlockIdBits; /* see name variant below */
554 } list;
555 struct { /* ternary: if, for(;;), ?: */
556 ParseNode* kid1; /* condition, discriminant, etc. */
557 ParseNode* kid2; /* then-part, case list, etc. */
558 ParseNode* kid3; /* else-part, default case, etc. */
559 } ternary;
560 struct { /* two kids if binary */
561 ParseNode* left;
562 ParseNode* right;
563 union {
564 unsigned iflags; /* JSITER_* flags for PNK_FOR node */
565 ObjectBox* objbox; /* Only for PN_BINARY_OBJ */
567 } binary;
568 struct { /* one kid if unary */
569 ParseNode* kid;
570 bool prologue; /* directive prologue member (as
571 pn_prologue) */
572 } unary;
573 struct { /* name, labeled statement, etc. */
574 union {
575 JSAtom* atom; /* lexical name or label atom */
576 ObjectBox* objbox; /* block or regexp object */
577 FunctionBox* funbox; /* function object */
579 union {
580 ParseNode* expr; /* module or function body, var
581 initializer, argument default, or
582 base object of PNK_DOT */
583 Definition* lexdef; /* lexical definition for this use */
585 UpvarCookie cookie; /* upvar cookie with absolute frame
586 level (not relative skip), possibly
587 in current frame */
588 uint32_t dflags:NumDefinitionFlagBits, /* see PND_* below */
589 blockid:NumBlockIdBits; /* block number, for subset dominance
590 computation */
591 } name;
592 struct {
593 double value; /* aligned numeric literal value */
594 DecimalPoint decimalPoint; /* Whether the number has a decimal point */
595 } number;
596 class {
597 friend class LoopControlStatement;
598 PropertyName* label; /* target of break/continue statement */
599 } loopControl;
600 } pn_u;
602 #define pn_modulebox pn_u.name.modulebox
603 #define pn_funbox pn_u.name.funbox
604 #define pn_body pn_u.name.expr
605 #define pn_cookie pn_u.name.cookie
606 #define pn_dflags pn_u.name.dflags
607 #define pn_blockid pn_u.name.blockid
608 #define pn_index pn_u.name.blockid /* reuse as object table index */
609 #define pn_head pn_u.list.head
610 #define pn_tail pn_u.list.tail
611 #define pn_count pn_u.list.count
612 #define pn_xflags pn_u.list.xflags
613 #define pn_kid1 pn_u.ternary.kid1
614 #define pn_kid2 pn_u.ternary.kid2
615 #define pn_kid3 pn_u.ternary.kid3
616 #define pn_left pn_u.binary.left
617 #define pn_right pn_u.binary.right
618 #define pn_pval pn_u.binary.pval
619 #define pn_iflags pn_u.binary.iflags
620 #define pn_binary_obj pn_u.binary.objbox
621 #define pn_kid pn_u.unary.kid
622 #define pn_prologue pn_u.unary.prologue
623 #define pn_atom pn_u.name.atom
624 #define pn_objbox pn_u.name.objbox
625 #define pn_expr pn_u.name.expr
626 #define pn_lexdef pn_u.name.lexdef
627 #define pn_dval pn_u.number.value
629 protected:
630 void init(TokenKind type, JSOp op, ParseNodeArity arity) {
631 pn_type = type;
632 pn_op = op;
633 pn_arity = arity;
634 pn_parens = false;
635 MOZ_ASSERT(!pn_used);
636 MOZ_ASSERT(!pn_defn);
637 pn_next = pn_link = nullptr;
640 static ParseNode* create(ParseNodeKind kind, ParseNodeArity arity, FullParseHandler* handler);
642 public:
644 * Append right to left, forming a list node. |left| must have the given
645 * kind and op, and op must be left-associative.
647 static ParseNode*
648 append(ParseNodeKind tt, JSOp op, ParseNode* left, ParseNode* right, FullParseHandler* handler);
651 * Either append right to left, if left meets the conditions necessary to
652 * append (see append), or form a binary node whose children are right and
653 * left.
655 static ParseNode*
656 newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
657 FullParseHandler* handler, ParseContext<FullParseHandler>* pc,
658 bool foldConstants);
660 inline PropertyName* name() const;
661 inline JSAtom* atom() const;
664 * The pn_expr and lexdef members are arms of an unsafe union. Unless you
665 * know exactly what you're doing, use only the following methods to access
666 * them. For less overhead and assertions for protection, use pn->expr()
667 * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
669 ParseNode* expr() const {
670 MOZ_ASSERT(!pn_used);
671 MOZ_ASSERT(pn_arity == PN_NAME || pn_arity == PN_CODE);
672 return pn_expr;
675 Definition* lexdef() const {
676 MOZ_ASSERT(pn_used || isDeoptimized());
677 MOZ_ASSERT(pn_arity == PN_NAME);
678 return pn_lexdef;
681 ParseNode* maybeExpr() { return pn_used ? nullptr : expr(); }
682 Definition* maybeLexDef() { return pn_used ? lexdef() : nullptr; }
684 Definition* resolve();
686 /* PN_CODE and PN_NAME pn_dflags bits. */
687 #define PND_LEXICAL 0x01 /* lexical (block-scoped) binding or use of a hoisted
688 let or const */
689 #define PND_CONST 0x02 /* const binding (orthogonal to let) */
690 #define PND_ASSIGNED 0x04 /* set if ever LHS of assignment */
691 #define PND_PLACEHOLDER 0x08 /* placeholder definition for lexdep */
692 #define PND_BOUND 0x10 /* bound to a stack or global slot */
693 #define PND_DEOPTIMIZED 0x20 /* former pn_used name node, pn_lexdef
694 still valid, but this use no longer
695 optimizable via an upvar opcode */
696 #define PND_CLOSED 0x40 /* variable is closed over */
697 #define PND_DEFAULT 0x80 /* definition is an arg with a default */
698 #define PND_IMPLICITARGUMENTS 0x100 /* the definition is a placeholder for
699 'arguments' that has been converted
700 into a definition after the function
701 body has been parsed. */
702 #define PND_EMITTEDFUNCTION 0x200 /* hoisted function that was emitted */
704 static_assert(PND_EMITTEDFUNCTION < (1 << NumDefinitionFlagBits), "Not enough bits");
706 /* Flags to propagate from uses to definition. */
707 #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
709 /* PN_LIST pn_xflags bits. */
710 #define PNX_POPVAR 0x01 /* PNK_VAR or PNK_CONST last result
711 needs popping */
712 #define PNX_GROUPINIT 0x02 /* var [a, b] = [c, d]; unit list */
713 #define PNX_FUNCDEFS 0x04 /* contains top-level function statements */
714 #define PNX_SETCALL 0x08 /* call expression in lvalue context */
715 #define PNX_DESTRUCT 0x10 /* code evaluating destructuring
716 arguments occurs before function body */
717 #define PNX_SPECIALARRAYINIT 0x20 /* one or more of
718 1. array initialiser has holes
719 2. array initializer has spread node */
720 #define PNX_NONCONST 0x40 /* initialiser has non-constants */
722 static_assert(PNX_NONCONST < (1 << NumListFlagBits), "Not enough bits");
724 unsigned frameLevel() const {
725 MOZ_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
726 return pn_cookie.level();
729 uint32_t frameSlot() const {
730 MOZ_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
731 return pn_cookie.slot();
734 bool functionIsHoisted() const {
735 MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
736 MOZ_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr
737 isOp(JSOP_LAMBDA_ARROW) || // arrow function
738 isOp(JSOP_DEFFUN) || // non-body-level function statement
739 isOp(JSOP_NOP) || // body-level function stmt in global code
740 isOp(JSOP_GETLOCAL) || // body-level function stmt in function code
741 isOp(JSOP_GETARG)); // body-level function redeclaring formal
742 return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN);
746 * True if this statement node could be a member of a Directive Prologue: an
747 * expression statement consisting of a single string literal.
749 * This considers only the node and its children, not its context. After
750 * parsing, check the node's pn_prologue flag to see if it is indeed part of
751 * a directive prologue.
753 * Note that a Directive Prologue can contain statements that cannot
754 * themselves be directives (string literals that include escape sequences
755 * or escaped newlines, say). This member function returns true for such
756 * nodes; we use it to determine the extent of the prologue.
758 JSAtom* isStringExprStatement() const {
759 if (getKind() == PNK_SEMI) {
760 MOZ_ASSERT(pn_arity == PN_UNARY);
761 ParseNode* kid = pn_kid;
762 if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
763 return kid->pn_atom;
765 return nullptr;
768 inline bool test(unsigned flag) const;
770 bool isLexical() const { return test(PND_LEXICAL) && !isUsed(); }
771 bool isConst() const { return test(PND_CONST); }
772 bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
773 bool isDeoptimized() const { return test(PND_DEOPTIMIZED); }
774 bool isAssigned() const { return test(PND_ASSIGNED); }
775 bool isClosed() const { return test(PND_CLOSED); }
776 bool isBound() const { return test(PND_BOUND); }
777 bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
778 bool isHoistedLexicalUse() const { return test(PND_LEXICAL) && isUsed(); }
780 /* True if pn is a parsenode representing a literal constant. */
781 bool isLiteral() const {
782 return isKind(PNK_NUMBER) ||
783 isKind(PNK_STRING) ||
784 isKind(PNK_TRUE) ||
785 isKind(PNK_FALSE) ||
786 isKind(PNK_NULL);
789 /* Return true if this node appears in a Directive Prologue. */
790 bool isDirectivePrologueMember() const { return pn_prologue; }
792 #ifdef JS_HAS_GENERATOR_EXPRS
793 ParseNode* generatorExpr() const {
794 MOZ_ASSERT(isKind(PNK_GENEXP));
795 ParseNode* callee = this->pn_head;
796 ParseNode* body = callee->pn_body;
797 MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
798 MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || body->last()->isKind(PNK_FOR));
799 return body->last();
801 #endif
803 inline void markAsAssigned();
806 * Compute a pointer to the last element in a singly-linked list. NB: list
807 * must be non-empty for correct PN_LAST usage -- this is asserted!
809 ParseNode* last() const {
810 MOZ_ASSERT(pn_arity == PN_LIST);
811 MOZ_ASSERT(pn_count != 0);
812 return (ParseNode*)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next));
815 void initNumber(double value, DecimalPoint decimalPoint) {
816 MOZ_ASSERT(pn_arity == PN_NULLARY);
817 MOZ_ASSERT(getKind() == PNK_NUMBER);
818 pn_u.number.value = value;
819 pn_u.number.decimalPoint = decimalPoint;
822 void makeEmpty() {
823 MOZ_ASSERT(pn_arity == PN_LIST);
824 pn_head = nullptr;
825 pn_tail = &pn_head;
826 pn_count = 0;
827 pn_xflags = 0;
828 pn_blockid = 0;
831 void initList(ParseNode* pn) {
832 MOZ_ASSERT(pn_arity == PN_LIST);
833 if (pn->pn_pos.begin < pn_pos.begin)
834 pn_pos.begin = pn->pn_pos.begin;
835 pn_pos.end = pn->pn_pos.end;
836 pn_head = pn;
837 pn_tail = &pn->pn_next;
838 pn_count = 1;
839 pn_xflags = 0;
840 pn_blockid = 0;
843 void append(ParseNode* pn) {
844 MOZ_ASSERT(pn_arity == PN_LIST);
845 MOZ_ASSERT(pn->pn_pos.begin >= pn_pos.begin);
846 pn_pos.end = pn->pn_pos.end;
847 *pn_tail = pn;
848 pn_tail = &pn->pn_next;
849 pn_count++;
852 void checkListConsistency()
853 #ifndef DEBUG
855 #endif
858 enum AllowConstantObjects {
859 DontAllowObjects = 0,
860 DontAllowNestedObjects,
861 AllowObjects
864 bool getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp);
865 inline bool isConstant();
867 template <class NodeType>
868 inline bool is() const {
869 return NodeType::test(*this);
872 /* Casting operations. */
873 template <class NodeType>
874 inline NodeType& as() {
875 MOZ_ASSERT(NodeType::test(*this));
876 return *static_cast<NodeType*>(this);
879 template <class NodeType>
880 inline const NodeType& as() const {
881 MOZ_ASSERT(NodeType::test(*this));
882 return *static_cast<const NodeType*>(this);
885 #ifdef DEBUG
886 void dump();
887 void dump(int indent);
888 #endif
891 struct NullaryNode : public ParseNode
893 NullaryNode(ParseNodeKind kind, const TokenPos& pos)
894 : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {}
895 NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
896 : ParseNode(kind, op, PN_NULLARY, pos) {}
898 // This constructor is for a few mad uses in the emitter. It populates
899 // the pn_atom field even though that field belongs to a branch in pn_u
900 // that nullary nodes shouldn't use -- bogus.
901 NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, JSAtom* atom)
902 : ParseNode(kind, op, PN_NULLARY, pos)
904 pn_atom = atom;
907 static bool test(const ParseNode& node) {
908 return node.isArity(PN_NULLARY);
911 #ifdef DEBUG
912 void dump();
913 #endif
916 struct UnaryNode : public ParseNode
918 UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* kid)
919 : ParseNode(kind, op, PN_UNARY, pos)
921 pn_kid = kid;
924 static inline UnaryNode* create(ParseNodeKind kind, FullParseHandler* handler) {
925 return (UnaryNode*) ParseNode::create(kind, PN_UNARY, handler);
928 static bool test(const ParseNode& node) {
929 return node.isArity(PN_UNARY);
932 #ifdef DEBUG
933 void dump(int indent);
934 #endif
937 struct BinaryNode : public ParseNode
939 BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* left, ParseNode* right)
940 : ParseNode(kind, op, PN_BINARY, pos)
942 pn_left = left;
943 pn_right = right;
946 BinaryNode(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right)
947 : ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
949 pn_left = left;
950 pn_right = right;
953 static inline BinaryNode* create(ParseNodeKind kind, FullParseHandler* handler) {
954 return (BinaryNode*) ParseNode::create(kind, PN_BINARY, handler);
957 static bool test(const ParseNode& node) {
958 return node.isArity(PN_BINARY);
961 #ifdef DEBUG
962 void dump(int indent);
963 #endif
966 struct BinaryObjNode : public ParseNode
968 BinaryObjNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* left, ParseNode* right,
969 ObjectBox* objbox)
970 : ParseNode(kind, op, PN_BINARY_OBJ, pos)
972 pn_left = left;
973 pn_right = right;
974 pn_binary_obj = objbox;
977 static inline BinaryObjNode* create(ParseNodeKind kind, FullParseHandler* handler) {
978 return (BinaryObjNode*) ParseNode::create(kind, PN_BINARY_OBJ, handler);
981 static bool test(const ParseNode& node) {
982 return node.isArity(PN_BINARY_OBJ);
985 #ifdef DEBUG
986 void dump(int indent);
987 #endif
990 struct TernaryNode : public ParseNode
992 TernaryNode(ParseNodeKind kind, JSOp op, ParseNode* kid1, ParseNode* kid2, ParseNode* kid3)
993 : ParseNode(kind, op, PN_TERNARY,
994 TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
995 (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end))
997 pn_kid1 = kid1;
998 pn_kid2 = kid2;
999 pn_kid3 = kid3;
1002 TernaryNode(ParseNodeKind kind, JSOp op, ParseNode* kid1, ParseNode* kid2, ParseNode* kid3,
1003 const TokenPos& pos)
1004 : ParseNode(kind, op, PN_TERNARY, pos)
1006 pn_kid1 = kid1;
1007 pn_kid2 = kid2;
1008 pn_kid3 = kid3;
1011 static inline TernaryNode* create(ParseNodeKind kind, FullParseHandler* handler) {
1012 return (TernaryNode*) ParseNode::create(kind, PN_TERNARY, handler);
1015 static bool test(const ParseNode& node) {
1016 return node.isArity(PN_TERNARY);
1019 #ifdef DEBUG
1020 void dump(int indent);
1021 #endif
1024 struct ListNode : public ParseNode
1026 ListNode(ParseNodeKind kind, const TokenPos& pos)
1027 : ParseNode(kind, JSOP_NOP, PN_LIST, pos)
1029 makeEmpty();
1032 ListNode(ParseNodeKind kind, JSOp op, ParseNode* kid)
1033 : ParseNode(kind, op, PN_LIST, kid->pn_pos)
1035 initList(kid);
1038 static inline ListNode* create(ParseNodeKind kind, FullParseHandler* handler) {
1039 return (ListNode*) ParseNode::create(kind, PN_LIST, handler);
1042 static bool test(const ParseNode& node) {
1043 return node.isArity(PN_LIST);
1046 #ifdef DEBUG
1047 void dump(int indent);
1048 #endif
1051 struct CodeNode : public ParseNode
1053 static inline CodeNode* create(ParseNodeKind kind, FullParseHandler* handler) {
1054 return (CodeNode*) ParseNode::create(kind, PN_CODE, handler);
1057 static bool test(const ParseNode& node) {
1058 return node.isArity(PN_CODE);
1061 #ifdef DEBUG
1062 void dump(int indent);
1063 #endif
1066 struct NameNode : public ParseNode
1068 NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, uint32_t blockid,
1069 const TokenPos& pos)
1070 : ParseNode(kind, op, PN_NAME, pos)
1072 pn_atom = atom;
1073 pn_expr = nullptr;
1074 pn_cookie.makeFree();
1075 pn_dflags = 0;
1076 pn_blockid = blockid;
1077 MOZ_ASSERT(pn_blockid == blockid); // check for bitfield overflow
1080 static bool test(const ParseNode& node) {
1081 return node.isArity(PN_NAME);
1084 #ifdef DEBUG
1085 void dump(int indent);
1086 #endif
1089 struct LexicalScopeNode : public ParseNode
1091 static inline LexicalScopeNode* create(ParseNodeKind kind, FullParseHandler* handler) {
1092 return (LexicalScopeNode*) ParseNode::create(kind, PN_NAME, handler);
1096 class LabeledStatement : public ParseNode
1098 public:
1099 LabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin)
1100 : ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos(begin, stmt->pn_pos.end))
1102 pn_atom = label;
1103 pn_expr = stmt;
1106 PropertyName* label() const {
1107 return pn_atom->asPropertyName();
1110 ParseNode* statement() const {
1111 return pn_expr;
1114 static bool test(const ParseNode& node) {
1115 bool match = node.isKind(PNK_LABEL);
1116 MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
1117 MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1118 return match;
1122 class LoopControlStatement : public ParseNode
1124 protected:
1125 LoopControlStatement(ParseNodeKind kind, PropertyName* label, const TokenPos& pos)
1126 : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos)
1128 MOZ_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE);
1129 pn_u.loopControl.label = label;
1132 public:
1133 /* Label associated with this break/continue statement, if any. */
1134 PropertyName* label() const {
1135 return pn_u.loopControl.label;
1138 static bool test(const ParseNode& node) {
1139 bool match = node.isKind(PNK_BREAK) || node.isKind(PNK_CONTINUE);
1140 MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1141 MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1142 return match;
1146 class BreakStatement : public LoopControlStatement
1148 public:
1149 BreakStatement(PropertyName* label, const TokenPos& pos)
1150 : LoopControlStatement(PNK_BREAK, label, pos)
1153 static bool test(const ParseNode& node) {
1154 bool match = node.isKind(PNK_BREAK);
1155 MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1156 MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1157 return match;
1161 class ContinueStatement : public LoopControlStatement
1163 public:
1164 ContinueStatement(PropertyName* label, const TokenPos& pos)
1165 : LoopControlStatement(PNK_CONTINUE, label, pos)
1168 static bool test(const ParseNode& node) {
1169 bool match = node.isKind(PNK_CONTINUE);
1170 MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1171 MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1172 return match;
1176 class DebuggerStatement : public ParseNode
1178 public:
1179 explicit DebuggerStatement(const TokenPos& pos)
1180 : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos)
1184 class ConditionalExpression : public ParseNode
1186 public:
1187 ConditionalExpression(ParseNode* condition, ParseNode* thenExpr, ParseNode* elseExpr)
1188 : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
1189 TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end))
1191 MOZ_ASSERT(condition);
1192 MOZ_ASSERT(thenExpr);
1193 MOZ_ASSERT(elseExpr);
1194 pn_u.ternary.kid1 = condition;
1195 pn_u.ternary.kid2 = thenExpr;
1196 pn_u.ternary.kid3 = elseExpr;
1199 ParseNode& condition() const {
1200 return *pn_u.ternary.kid1;
1203 ParseNode& thenExpression() const {
1204 return *pn_u.ternary.kid2;
1207 ParseNode& elseExpression() const {
1208 return *pn_u.ternary.kid3;
1211 static bool test(const ParseNode& node) {
1212 bool match = node.isKind(PNK_CONDITIONAL);
1213 MOZ_ASSERT_IF(match, node.isArity(PN_TERNARY));
1214 MOZ_ASSERT_IF(match, node.isOp(JSOP_NOP));
1215 return match;
1219 class ThisLiteral : public ParseNode
1221 public:
1222 explicit ThisLiteral(const TokenPos& pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { }
1225 class NullLiteral : public ParseNode
1227 public:
1228 explicit NullLiteral(const TokenPos& pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
1231 class BooleanLiteral : public ParseNode
1233 public:
1234 BooleanLiteral(bool b, const TokenPos& pos)
1235 : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos)
1239 class RegExpLiteral : public NullaryNode
1241 public:
1242 RegExpLiteral(ObjectBox* reobj, const TokenPos& pos)
1243 : NullaryNode(PNK_REGEXP, JSOP_REGEXP, pos)
1245 pn_objbox = reobj;
1248 ObjectBox* objbox() const { return pn_objbox; }
1250 static bool test(const ParseNode& node) {
1251 bool match = node.isKind(PNK_REGEXP);
1252 MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
1253 MOZ_ASSERT_IF(match, node.isOp(JSOP_REGEXP));
1254 return match;
1258 class PropertyAccess : public ParseNode
1260 public:
1261 PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
1262 : ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end))
1264 MOZ_ASSERT(lhs != nullptr);
1265 MOZ_ASSERT(name != nullptr);
1266 pn_u.name.expr = lhs;
1267 pn_u.name.atom = name;
1270 static bool test(const ParseNode& node) {
1271 bool match = node.isKind(PNK_DOT);
1272 MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
1273 return match;
1276 ParseNode& expression() const {
1277 return *pn_u.name.expr;
1280 PropertyName& name() const {
1281 return *pn_u.name.atom->asPropertyName();
1285 class PropertyByValue : public ParseNode
1287 public:
1288 PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin, uint32_t end)
1289 : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
1291 pn_u.binary.left = lhs;
1292 pn_u.binary.right = propExpr;
1297 * A CallSiteNode represents the implicit call site object argument in a TaggedTemplate.
1299 struct CallSiteNode : public ListNode {
1300 explicit CallSiteNode(uint32_t begin): ListNode(PNK_CALLSITEOBJ, TokenPos(begin, begin + 1)) {}
1302 static bool test(const ParseNode& node) {
1303 return node.isKind(PNK_CALLSITEOBJ);
1306 bool getRawArrayValue(ExclusiveContext* cx, MutableHandleValue vp) {
1307 return pn_head->getConstantValue(cx, AllowObjects, vp);
1311 #ifdef DEBUG
1312 void DumpParseTree(ParseNode* pn, int indent = 0);
1313 #endif
1316 * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants
1317 * of js::ParseNode, allocated only for function, var, const, and let
1318 * declarations that define truly lexical bindings. This means that a child of
1319 * a PNK_VAR list may be a Definition as well as a ParseNode. The pn_defn bit
1320 * is set for all Definitions, clear otherwise.
1322 * In an upvars list, defn->resolve() is the outermost definition the
1323 * name may reference. If a with block or a function that calls eval encloses
1324 * the use, the name may end up referring to something else at runtime.
1326 * Note that not all var declarations are definitions: JS allows multiple var
1327 * declarations in a function or script, but only the first creates the hoisted
1328 * binding. JS programmers do redeclare variables for good refactoring reasons,
1329 * for example:
1331 * function foo() {
1332 * ...
1333 * for (var i ...) ...;
1334 * ...
1335 * for (var i ...) ...;
1336 * ...
1339 * Not all definitions bind lexical variables, alas. In global and eval code
1340 * var may re-declare a pre-existing property having any attributes, with or
1341 * without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through
1342 * 3 require function and var to bind deletable bindings. Global vars thus are
1343 * properties of the global object, so they can be aliased even if they can't
1344 * be deleted.
1346 * Only bindings within function code may be treated as lexical, of course with
1347 * the caveat that hoisting means use before initialization is allowed. We deal
1348 * with use before declaration in one pass as follows (error checking elided):
1350 * for (each use of unqualified name x in parse order) {
1351 * if (this use of x is a declaration) {
1352 * if (x in pc->decls) { // redeclaring
1353 * pn = allocate a PN_NAME ParseNode;
1354 * } else { // defining
1355 * dn = lookup x in pc->lexdeps;
1356 * if (dn) // use before def
1357 * remove x from pc->lexdeps;
1358 * else // def before use
1359 * dn = allocate a PN_NAME Definition;
1360 * map x to dn via pc->decls;
1361 * pn = dn;
1363 * insert pn into its parent PNK_VAR/PNK_CONST list;
1364 * } else {
1365 * pn = allocate a ParseNode for this reference to x;
1366 * dn = lookup x in pc's lexical scope chain;
1367 * if (!dn) {
1368 * dn = lookup x in pc->lexdeps;
1369 * if (!dn) {
1370 * dn = pre-allocate a Definition for x;
1371 * map x to dn in pc->lexdeps;
1374 * append pn to dn's use chain;
1378 * See frontend/BytecodeEmitter.h for js::ParseContext and its top*Stmt,
1379 * decls, and lexdeps members.
1381 * Notes:
1383 * 0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn
1384 * and set it on a ParseNode instead of allocating a Definition.
1386 * 1. Due to hoisting, a definition cannot be eliminated even if its "Variable
1387 * statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
1388 * ParseNode.cpp will not recycle a node whose pn_defn bit is set.
1390 * 2. "lookup x in pc's lexical scope chain" gives up on def/use chaining if a
1391 * with statement is found along the the scope chain, which includes pc,
1392 * pc->parent, etc. Thus we eagerly connect an inner function's use of an
1393 * outer's var x if the var x was parsed before the inner function.
1395 * 3. A use may be eliminated as dead by the constant folder, which therefore
1396 * must remove the dead name node from its singly-linked use chain, which
1397 * would mean hashing to find the definition node and searching to update
1398 * the pn_link pointing at the use to be removed. This is costly, so as for
1399 * dead definitions, we do not recycle dead pn_used nodes.
1401 * At the end of parsing a function body or global or eval program, pc->lexdeps
1402 * holds the lexical dependencies of the parsed unit. The name to def/use chain
1403 * mappings are then merged into the parent pc->lexdeps.
1405 * Thus if a later var x is parsed in the outer function satisfying an earlier
1406 * inner function's use of x, we will remove dn from pc->lexdeps and re-use it
1407 * as the new definition node in the outer function's parse tree.
1409 * When the compiler unwinds from the outermost pc, pc->lexdeps contains the
1410 * definition nodes with use chains for all free variables. These are either
1411 * global variables or reference errors.
1413 struct Definition : public ParseNode
1415 bool isFreeVar() const {
1416 MOZ_ASSERT(isDefn());
1417 return pn_cookie.isFree();
1420 enum Kind { MISSING = 0, VAR, GLOBALCONST, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
1422 bool canHaveInitializer() { return int(kind()) <= int(ARG); }
1424 static const char* kindString(Kind kind);
1426 Kind kind() {
1427 if (getKind() == PNK_FUNCTION) {
1428 if (isOp(JSOP_GETARG))
1429 return ARG;
1430 return VAR;
1432 MOZ_ASSERT(getKind() == PNK_NAME);
1433 if (isOp(JSOP_CALLEE))
1434 return NAMED_LAMBDA;
1435 if (isPlaceholder())
1436 return PLACEHOLDER;
1437 if (isOp(JSOP_GETARG))
1438 return ARG;
1439 if (isLexical())
1440 return isConst() ? CONST : LET;
1441 if (isConst())
1442 return GLOBALCONST;
1443 return VAR;
1447 class ParseNodeAllocator
1449 public:
1450 explicit ParseNodeAllocator(ExclusiveContext* cx, LifoAlloc& alloc)
1451 : cx(cx), alloc(alloc), freelist(nullptr)
1454 void* allocNode();
1455 void freeNode(ParseNode* pn);
1456 ParseNode* freeTree(ParseNode* pn);
1457 void prepareNodeForMutation(ParseNode* pn);
1459 private:
1460 ExclusiveContext* cx;
1461 LifoAlloc& alloc;
1462 ParseNode* freelist;
1465 inline bool
1466 ParseNode::test(unsigned flag) const
1468 MOZ_ASSERT(pn_defn || pn_arity == PN_CODE || pn_arity == PN_NAME);
1469 #ifdef DEBUG
1470 if ((flag & PND_ASSIGNED) && pn_defn && !(pn_dflags & flag)) {
1471 for (ParseNode* pn = ((Definition*) this)->dn_uses; pn; pn = pn->pn_link) {
1472 MOZ_ASSERT(!pn->pn_defn);
1473 MOZ_ASSERT(!(pn->pn_dflags & flag));
1476 #endif
1477 return !!(pn_dflags & flag);
1480 inline void
1481 ParseNode::markAsAssigned()
1483 MOZ_ASSERT(js_CodeSpec[pn_op].format & JOF_NAME);
1484 if (isUsed())
1485 pn_lexdef->pn_dflags |= PND_ASSIGNED;
1486 pn_dflags |= PND_ASSIGNED;
1489 inline Definition*
1490 ParseNode::resolve()
1492 if (isDefn())
1493 return (Definition*)this;
1494 MOZ_ASSERT(lexdef()->isDefn());
1495 return (Definition*)lexdef();
1498 inline bool
1499 ParseNode::isConstant()
1501 switch (pn_type) {
1502 case PNK_NUMBER:
1503 case PNK_STRING:
1504 case PNK_TEMPLATE_STRING:
1505 case PNK_NULL:
1506 case PNK_FALSE:
1507 case PNK_TRUE:
1508 return true;
1509 case PNK_ARRAY:
1510 case PNK_OBJECT:
1511 MOZ_ASSERT(isOp(JSOP_NEWINIT));
1512 return !(pn_xflags & PNX_NONCONST);
1513 default:
1514 return false;
1518 class ObjectBox
1520 public:
1521 NativeObject* object;
1523 ObjectBox(NativeObject* object, ObjectBox* traceLink);
1524 bool isFunctionBox() { return object->is<JSFunction>(); }
1525 FunctionBox* asFunctionBox();
1526 void trace(JSTracer* trc);
1528 protected:
1529 friend struct CGObjectList;
1531 ObjectBox* traceLink;
1532 ObjectBox* emitLink;
1534 ObjectBox(JSFunction* function, ObjectBox* traceLink);
1537 enum ParseReportKind
1539 ParseError,
1540 ParseWarning,
1541 ParseExtraWarning,
1542 ParseStrictError
1545 enum FunctionSyntaxKind { Expression, Statement, Arrow, Method };
1547 static inline ParseNode*
1548 FunctionArgsList(ParseNode* fn, unsigned* numFormals)
1550 MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
1551 ParseNode* argsBody = fn->pn_body;
1552 MOZ_ASSERT(argsBody->isKind(PNK_ARGSBODY));
1553 *numFormals = argsBody->pn_count;
1554 if (*numFormals > 0 && argsBody->last()->isKind(PNK_STATEMENTLIST))
1555 (*numFormals)--;
1556 MOZ_ASSERT(argsBody->isArity(PN_LIST));
1557 return argsBody->pn_head;
1560 } /* namespace frontend */
1561 } /* namespace js */
1563 #endif /* frontend_ParseNode_h */