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