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