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"
17 template <typename ParseHandler
>
20 class FullParseHandler
;
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.
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");
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
);
65 slot_
= 0; // value doesn't matter, won't be used
70 #define FOR_EACH_PARSE_NODE_KIND(F) \
95 F(TEMPLATE_STRING_LIST) \
137 F(IMPORT_SPEC_LIST) \
141 F(EXPORT_SPEC_LIST) \
143 F(EXPORT_BATCH_SPEC) \
152 /* Unary operators. */ \
159 * Binary operators. \
160 * These must be in the same order as TOK_OR and friends in TokenStream.h. \
186 /* Assignment operators (= += -= etc.). */ \
187 /* ParseNode::isAssignment assumes all these are consecutive. */ \
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.
213 #define EMIT_ENUM(name) PNK_##name,
214 FOR_EACH_PARSE_NODE_KIND(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 * ----- ------- -------
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
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
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
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
259 * PNK_CASE, binary pn_left: case expr
260 * pn_right: PNK_STATEMENTLIST node for this case's
262 * PNK_DEFAULT binary pn_left: null
263 * pn_right: PNK_STATEMENTLIST node for this default's
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(;;))
271 * PNK_FORIN ternary pn_kid1: PNK_VAR to left of 'in', or nullptr
272 * its pn_xflags may have PNX_POPVAR
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
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
304 * pn_atom: variable name
305 * pn_expr: initializer or null
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
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.
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
350 * PNK_LT, binary pn_left: left-assoc REL expr, pn_right: SH expr
354 * PNK_LSH, binary pn_left: left-assoc SH expr, pn_right: ADD expr
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
369 * PNK_POS, unary pn_kid: UNARY expr
371 * PNK_TYPEOF, unary pn_kid: UNARY expr
375 * PNK_PREINCREMENT, unary pn_kid: MEMBER expr
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
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
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
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
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
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 */
453 class LabeledStatement
;
454 class LoopControlStatement
;
455 class BreakStatement
;
456 class ContinueStatement
;
457 class ConditionalExpression
;
458 class PropertyAccess
;
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;
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
);
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.
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 */
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. */
560 struct { /* two kids if binary */
564 unsigned iflags
; /* JSITER_* flags for PNK_FOR node */
565 ObjectBox
* objbox
; /* Only for PN_BINARY_OBJ */
568 struct { /* one kid if unary */
570 bool prologue
; /* directive prologue member (as
573 struct { /* name, labeled statement, etc. */
575 JSAtom
* atom
; /* lexical name or label atom */
576 ObjectBox
* objbox
; /* block or regexp object */
577 FunctionBox
* funbox
; /* function object */
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
588 uint32_t dflags
:NumDefinitionFlagBits
, /* see PND_* below */
589 blockid
:NumBlockIdBits
; /* block number, for subset dominance
593 double value
; /* aligned numeric literal value */
594 DecimalPoint decimalPoint
; /* Whether the number has a decimal point */
597 friend class LoopControlStatement
;
598 PropertyName
* label
; /* target of break/continue statement */
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
630 void init(TokenKind type
, JSOp op
, ParseNodeArity arity
) {
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
);
644 * Append right to left, forming a list node. |left| must have the given
645 * kind and op, and op must be left-associative.
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
656 newBinaryOrAppend(ParseNodeKind kind
, JSOp op
, ParseNode
* left
, ParseNode
* right
,
657 FullParseHandler
* handler
, ParseContext
<FullParseHandler
>* pc
,
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
);
675 Definition
* lexdef() const {
676 MOZ_ASSERT(pn_used
|| isDeoptimized());
677 MOZ_ASSERT(pn_arity
== PN_NAME
);
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
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
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
)
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
) ||
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
));
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
;
823 MOZ_ASSERT(pn_arity
== PN_LIST
);
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
;
837 pn_tail
= &pn
->pn_next
;
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
;
848 pn_tail
= &pn
->pn_next
;
852 void checkListConsistency()
858 enum AllowConstantObjects
{
859 DontAllowObjects
= 0,
860 DontAllowNestedObjects
,
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);
887 void dump(int indent
);
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
)
907 static bool test(const ParseNode
& node
) {
908 return node
.isArity(PN_NULLARY
);
916 struct UnaryNode
: public ParseNode
918 UnaryNode(ParseNodeKind kind
, JSOp op
, const TokenPos
& pos
, ParseNode
* kid
)
919 : ParseNode(kind
, op
, PN_UNARY
, pos
)
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
);
933 void dump(int indent
);
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
)
946 BinaryNode(ParseNodeKind kind
, JSOp op
, ParseNode
* left
, ParseNode
* right
)
947 : ParseNode(kind
, op
, PN_BINARY
, TokenPos::box(left
->pn_pos
, right
->pn_pos
))
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
);
962 void dump(int indent
);
966 struct BinaryObjNode
: public ParseNode
968 BinaryObjNode(ParseNodeKind kind
, JSOp op
, const TokenPos
& pos
, ParseNode
* left
, ParseNode
* right
,
970 : ParseNode(kind
, op
, PN_BINARY_OBJ
, pos
)
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
);
986 void dump(int indent
);
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
))
1002 TernaryNode(ParseNodeKind kind
, JSOp op
, ParseNode
* kid1
, ParseNode
* kid2
, ParseNode
* kid3
,
1003 const TokenPos
& pos
)
1004 : ParseNode(kind
, op
, PN_TERNARY
, pos
)
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
);
1020 void dump(int indent
);
1024 struct ListNode
: public ParseNode
1026 ListNode(ParseNodeKind kind
, const TokenPos
& pos
)
1027 : ParseNode(kind
, JSOP_NOP
, PN_LIST
, pos
)
1032 ListNode(ParseNodeKind kind
, JSOp op
, ParseNode
* kid
)
1033 : ParseNode(kind
, op
, PN_LIST
, kid
->pn_pos
)
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
);
1047 void dump(int indent
);
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
);
1062 void dump(int indent
);
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
)
1074 pn_cookie
.makeFree();
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
);
1085 void dump(int indent
);
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
1099 LabeledStatement(PropertyName
* label
, ParseNode
* stmt
, uint32_t begin
)
1100 : ParseNode(PNK_LABEL
, JSOP_NOP
, PN_NAME
, TokenPos(begin
, stmt
->pn_pos
.end
))
1106 PropertyName
* label() const {
1107 return pn_atom
->asPropertyName();
1110 ParseNode
* statement() const {
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
));
1122 class LoopControlStatement
: public ParseNode
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
;
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
));
1146 class BreakStatement
: public LoopControlStatement
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
));
1161 class ContinueStatement
: public LoopControlStatement
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
));
1176 class DebuggerStatement
: public ParseNode
1179 explicit DebuggerStatement(const TokenPos
& pos
)
1180 : ParseNode(PNK_DEBUGGER
, JSOP_NOP
, PN_NULLARY
, pos
)
1184 class ConditionalExpression
: public ParseNode
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
));
1219 class ThisLiteral
: public ParseNode
1222 explicit ThisLiteral(const TokenPos
& pos
) : ParseNode(PNK_THIS
, JSOP_THIS
, PN_NULLARY
, pos
) { }
1225 class NullLiteral
: public ParseNode
1228 explicit NullLiteral(const TokenPos
& pos
) : ParseNode(PNK_NULL
, JSOP_NULL
, PN_NULLARY
, pos
) { }
1231 class BooleanLiteral
: public ParseNode
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
1242 RegExpLiteral(ObjectBox
* reobj
, const TokenPos
& pos
)
1243 : NullaryNode(PNK_REGEXP
, JSOP_REGEXP
, pos
)
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
));
1258 class PropertyAccess
: public ParseNode
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
));
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
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
);
1312 void DumpParseTree(ParseNode
* pn
, int indent
= 0);
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,
1333 * for (var i ...) ...;
1335 * for (var i ...) ...;
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
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;
1363 * insert pn into its parent PNK_VAR/PNK_CONST list;
1365 * pn = allocate a ParseNode for this reference to x;
1366 * dn = lookup x in pc's lexical scope chain;
1368 * dn = lookup x in pc->lexdeps;
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.
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
);
1427 if (getKind() == PNK_FUNCTION
) {
1428 if (isOp(JSOP_GETARG
))
1432 MOZ_ASSERT(getKind() == PNK_NAME
);
1433 if (isOp(JSOP_CALLEE
))
1434 return NAMED_LAMBDA
;
1435 if (isPlaceholder())
1437 if (isOp(JSOP_GETARG
))
1440 return isConst() ? CONST
: LET
;
1447 class ParseNodeAllocator
1450 explicit ParseNodeAllocator(ExclusiveContext
* cx
, LifoAlloc
& alloc
)
1451 : cx(cx
), alloc(alloc
), freelist(nullptr)
1455 void freeNode(ParseNode
* pn
);
1456 ParseNode
* freeTree(ParseNode
* pn
);
1457 void prepareNodeForMutation(ParseNode
* pn
);
1460 ExclusiveContext
* cx
;
1462 ParseNode
* freelist
;
1466 ParseNode::test(unsigned flag
) const
1468 MOZ_ASSERT(pn_defn
|| pn_arity
== PN_CODE
|| pn_arity
== PN_NAME
);
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
));
1477 return !!(pn_dflags
& flag
);
1481 ParseNode::markAsAssigned()
1483 MOZ_ASSERT(js_CodeSpec
[pn_op
].format
& JOF_NAME
);
1485 pn_lexdef
->pn_dflags
|= PND_ASSIGNED
;
1486 pn_dflags
|= PND_ASSIGNED
;
1490 ParseNode::resolve()
1493 return (Definition
*)this;
1494 MOZ_ASSERT(lexdef()->isDefn());
1495 return (Definition
*)lexdef();
1499 ParseNode::isConstant()
1504 case PNK_TEMPLATE_STRING
:
1511 MOZ_ASSERT(isOp(JSOP_NEWINIT
));
1512 return !(pn_xflags
& PNX_NONCONST
);
1521 NativeObject
* object
;
1523 ObjectBox(NativeObject
* object
, ObjectBox
* traceLink
);
1524 bool isFunctionBox() { return object
->is
<JSFunction
>(); }
1525 FunctionBox
* asFunctionBox();
1526 void trace(JSTracer
* trc
);
1529 friend struct CGObjectList
;
1531 ObjectBox
* traceLink
;
1532 ObjectBox
* emitLink
;
1534 ObjectBox(JSFunction
* function
, ObjectBox
* traceLink
);
1537 enum ParseReportKind
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
))
1556 MOZ_ASSERT(argsBody
->isArity(PN_LIST
));
1557 return argsBody
->pn_head
;
1560 } /* namespace frontend */
1561 } /* namespace js */
1563 #endif /* frontend_ParseNode_h */