1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/frontend/ParseNode.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1508 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef frontend_ParseNode_h 1.11 +#define frontend_ParseNode_h 1.12 + 1.13 +#include "mozilla/Attributes.h" 1.14 + 1.15 +#include "frontend/TokenStream.h" 1.16 + 1.17 +namespace js { 1.18 +namespace frontend { 1.19 + 1.20 +template <typename ParseHandler> 1.21 +struct ParseContext; 1.22 + 1.23 +class FullParseHandler; 1.24 +class FunctionBox; 1.25 +class ObjectBox; 1.26 + 1.27 +/* 1.28 + * Indicates a location in the stack that an upvar value can be retrieved from 1.29 + * as a two tuple of (level, slot). 1.30 + * 1.31 + * Some existing client code uses the level value as a delta, or level "skip" 1.32 + * quantity. We could probably document that through use of more types at some 1.33 + * point in the future. 1.34 + */ 1.35 +class UpvarCookie 1.36 +{ 1.37 + uint32_t level_ : SCOPECOORD_HOPS_BITS; 1.38 + uint32_t slot_ : SCOPECOORD_SLOT_BITS; 1.39 + 1.40 + void checkInvariants() { 1.41 + static_assert(sizeof(UpvarCookie) == sizeof(uint32_t), 1.42 + "Not necessary for correctness, but good for ParseNode memory use"); 1.43 + } 1.44 + 1.45 + public: 1.46 + // Steal one value to represent the sentinel value for UpvarCookie. 1.47 + static const uint32_t FREE_LEVEL = SCOPECOORD_HOPS_LIMIT - 1; 1.48 + bool isFree() const { return level_ == FREE_LEVEL; } 1.49 + 1.50 + uint32_t level() const { JS_ASSERT(!isFree()); return level_; } 1.51 + uint32_t slot() const { JS_ASSERT(!isFree()); return slot_; } 1.52 + 1.53 + // This fails and issues an error message if newLevel or newSlot are too large. 1.54 + bool set(TokenStream &ts, unsigned newLevel, uint32_t newSlot) { 1.55 + if (newLevel >= FREE_LEVEL) 1.56 + return ts.reportError(JSMSG_TOO_DEEP, js_function_str); 1.57 + 1.58 + if (newSlot >= SCOPECOORD_SLOT_LIMIT) 1.59 + return ts.reportError(JSMSG_TOO_MANY_LOCALS); 1.60 + 1.61 + level_ = newLevel; 1.62 + slot_ = newSlot; 1.63 + return true; 1.64 + } 1.65 + 1.66 + void makeFree() { 1.67 + level_ = FREE_LEVEL; 1.68 + slot_ = 0; // value doesn't matter, won't be used 1.69 + JS_ASSERT(isFree()); 1.70 + } 1.71 +}; 1.72 + 1.73 +#define FOR_EACH_PARSE_NODE_KIND(F) \ 1.74 + F(NOP) \ 1.75 + F(SEMI) \ 1.76 + F(COMMA) \ 1.77 + F(CONDITIONAL) \ 1.78 + F(COLON) \ 1.79 + F(POS) \ 1.80 + F(NEG) \ 1.81 + F(PREINCREMENT) \ 1.82 + F(POSTINCREMENT) \ 1.83 + F(PREDECREMENT) \ 1.84 + F(POSTDECREMENT) \ 1.85 + F(DOT) \ 1.86 + F(ELEM) \ 1.87 + F(ARRAY) \ 1.88 + F(ELISION) \ 1.89 + F(STATEMENTLIST) \ 1.90 + F(LABEL) \ 1.91 + F(OBJECT) \ 1.92 + F(CALL) \ 1.93 + F(NAME) \ 1.94 + F(NUMBER) \ 1.95 + F(STRING) \ 1.96 + F(REGEXP) \ 1.97 + F(TRUE) \ 1.98 + F(FALSE) \ 1.99 + F(NULL) \ 1.100 + F(THIS) \ 1.101 + F(FUNCTION) \ 1.102 + F(IF) \ 1.103 + F(ELSE) \ 1.104 + F(SWITCH) \ 1.105 + F(CASE) \ 1.106 + F(DEFAULT) \ 1.107 + F(WHILE) \ 1.108 + F(DOWHILE) \ 1.109 + F(FOR) \ 1.110 + F(BREAK) \ 1.111 + F(CONTINUE) \ 1.112 + F(VAR) \ 1.113 + F(CONST) \ 1.114 + F(WITH) \ 1.115 + F(RETURN) \ 1.116 + F(NEW) \ 1.117 + F(DELETE) \ 1.118 + F(TRY) \ 1.119 + F(CATCH) \ 1.120 + F(CATCHLIST) \ 1.121 + F(FINALLY) \ 1.122 + F(THROW) \ 1.123 + F(DEBUGGER) \ 1.124 + F(YIELD) \ 1.125 + F(YIELD_STAR) \ 1.126 + F(GENEXP) \ 1.127 + F(ARRAYCOMP) \ 1.128 + F(ARRAYPUSH) \ 1.129 + F(LEXICALSCOPE) \ 1.130 + F(LET) \ 1.131 + F(IMPORT) \ 1.132 + F(IMPORT_SPEC_LIST) \ 1.133 + F(IMPORT_SPEC) \ 1.134 + F(EXPORT) \ 1.135 + F(EXPORT_FROM) \ 1.136 + F(EXPORT_SPEC_LIST) \ 1.137 + F(EXPORT_SPEC) \ 1.138 + F(EXPORT_BATCH_SPEC) \ 1.139 + F(SEQ) \ 1.140 + F(FORIN) \ 1.141 + F(FOROF) \ 1.142 + F(FORHEAD) \ 1.143 + F(ARGSBODY) \ 1.144 + F(SPREAD) \ 1.145 + \ 1.146 + /* Unary operators. */ \ 1.147 + F(TYPEOF) \ 1.148 + F(VOID) \ 1.149 + F(NOT) \ 1.150 + F(BITNOT) \ 1.151 + \ 1.152 + /* \ 1.153 + * Binary operators. \ 1.154 + * These must be in the same order as TOK_OR and friends in TokenStream.h. \ 1.155 + */ \ 1.156 + F(OR) \ 1.157 + F(AND) \ 1.158 + F(BITOR) \ 1.159 + F(BITXOR) \ 1.160 + F(BITAND) \ 1.161 + F(STRICTEQ) \ 1.162 + F(EQ) \ 1.163 + F(STRICTNE) \ 1.164 + F(NE) \ 1.165 + F(LT) \ 1.166 + F(LE) \ 1.167 + F(GT) \ 1.168 + F(GE) \ 1.169 + F(INSTANCEOF) \ 1.170 + F(IN) \ 1.171 + F(LSH) \ 1.172 + F(RSH) \ 1.173 + F(URSH) \ 1.174 + F(ADD) \ 1.175 + F(SUB) \ 1.176 + F(STAR) \ 1.177 + F(DIV) \ 1.178 + F(MOD) \ 1.179 + \ 1.180 + /* Assignment operators (= += -= etc.). */ \ 1.181 + /* ParseNode::isAssignment assumes all these are consecutive. */ \ 1.182 + F(ASSIGN) \ 1.183 + F(ADDASSIGN) \ 1.184 + F(SUBASSIGN) \ 1.185 + F(BITORASSIGN) \ 1.186 + F(BITXORASSIGN) \ 1.187 + F(BITANDASSIGN) \ 1.188 + F(LSHASSIGN) \ 1.189 + F(RSHASSIGN) \ 1.190 + F(URSHASSIGN) \ 1.191 + F(MULASSIGN) \ 1.192 + F(DIVASSIGN) \ 1.193 + F(MODASSIGN) 1.194 + 1.195 +/* 1.196 + * Parsing builds a tree of nodes that directs code generation. This tree is 1.197 + * not a concrete syntax tree in all respects (for example, || and && are left 1.198 + * associative, but (A && B && C) translates into the right-associated tree 1.199 + * <A && <B && C>> so that code generation can emit a left-associative branch 1.200 + * around <B && C> when A is false). Nodes are labeled by kind, with a 1.201 + * secondary JSOp label when needed. 1.202 + * 1.203 + * The long comment after this enum block describes the kinds in detail. 1.204 + */ 1.205 +enum ParseNodeKind 1.206 +{ 1.207 +#define EMIT_ENUM(name) PNK_##name, 1.208 + FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM) 1.209 +#undef EMIT_ENUM 1.210 + PNK_LIMIT, /* domain size */ 1.211 + PNK_BINOP_FIRST = PNK_OR, 1.212 + PNK_BINOP_LAST = PNK_MOD, 1.213 + PNK_ASSIGNMENT_START = PNK_ASSIGN, 1.214 + PNK_ASSIGNMENT_LAST = PNK_MODASSIGN 1.215 +}; 1.216 + 1.217 +/* 1.218 + * Label Variant Members 1.219 + * ----- ------- ------- 1.220 + * <Definitions> 1.221 + * PNK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function 1.222 + * object containing arg and var properties. We 1.223 + * create the function object at parse (not emit) 1.224 + * time to specialize arg and var bytecodes early. 1.225 + * pn_body: PNK_ARGSBODY, ordinarily; 1.226 + * PNK_LEXICALSCOPE for implicit function in genexpr 1.227 + * pn_cookie: static level and var index for function 1.228 + * pn_dflags: PND_* definition/use flags (see below) 1.229 + * pn_blockid: block id number 1.230 + * PNK_ARGSBODY list list of formal parameters followed by: 1.231 + * PNK_STATEMENTLIST node for function body 1.232 + * statements, 1.233 + * PNK_RETURN for expression closure, or 1.234 + * PNK_SEQ for expression closure with 1.235 + * destructured formal parameters 1.236 + * pn_count: 1 + number of formal parameters 1.237 + * pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node 1.238 + * PNK_SPREAD unary pn_kid: expression being spread 1.239 + * 1.240 + * <Statements> 1.241 + * PNK_STATEMENTLIST list pn_head: list of pn_count statements 1.242 + * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null. 1.243 + * In body of a comprehension or desugared generator 1.244 + * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH, 1.245 + * or (if the push was optimized away) empty 1.246 + * PNK_STATEMENTLIST. 1.247 + * PNK_SWITCH binary pn_left: discriminant 1.248 + * pn_right: list of PNK_CASE nodes, with at most one 1.249 + * PNK_DEFAULT node, or if there are let bindings 1.250 + * in the top level of the switch body's cases, a 1.251 + * PNK_LEXICALSCOPE node that contains the list of 1.252 + * PNK_CASE nodes. 1.253 + * PNK_CASE, binary pn_left: case expr 1.254 + * pn_right: PNK_STATEMENTLIST node for this case's 1.255 + * statements 1.256 + * PNK_DEFAULT binary pn_left: null 1.257 + * pn_right: PNK_STATEMENTLIST node for this default's 1.258 + * statements 1.259 + * pn_val: constant value if lookup or table switch 1.260 + * PNK_WHILE binary pn_left: cond, pn_right: body 1.261 + * PNK_DOWHILE binary pn_left: body, pn_right: cond 1.262 + * PNK_FOR binary pn_left: either PNK_FORIN (for-in statement), 1.263 + * PNK_FOROF (for-of) or PNK_FORHEAD (for(;;)) 1.264 + * pn_right: body 1.265 + * PNK_FORIN ternary pn_kid1: PNK_VAR to left of 'in', or nullptr 1.266 + * its pn_xflags may have PNX_POPVAR 1.267 + * bit set 1.268 + * pn_kid2: PNK_NAME or destructuring expr 1.269 + * to left of 'in'; if pn_kid1, then this 1.270 + * is a clone of pn_kid1->pn_head 1.271 + * pn_kid3: object expr to right of 'in' 1.272 + * PNK_FOROF ternary pn_kid1: PNK_VAR to left of 'of', or nullptr 1.273 + * its pn_xflags may have PNX_POPVAR 1.274 + * bit set 1.275 + * pn_kid2: PNK_NAME or destructuring expr 1.276 + * to left of 'of'; if pn_kid1, then this 1.277 + * is a clone of pn_kid1->pn_head 1.278 + * pn_kid3: expr to right of 'of' 1.279 + * PNK_FORHEAD ternary pn_kid1: init expr before first ';' or nullptr 1.280 + * pn_kid2: cond expr before second ';' or nullptr 1.281 + * pn_kid3: update expr after second ';' or nullptr 1.282 + * PNK_THROW unary pn_op: JSOP_THROW, pn_kid: exception 1.283 + * PNK_TRY ternary pn_kid1: try block 1.284 + * pn_kid2: null or PNK_CATCHLIST list of 1.285 + * PNK_LEXICALSCOPE nodes, each with pn_expr pointing 1.286 + * to a PNK_CATCH node 1.287 + * pn_kid3: null or finally block 1.288 + * PNK_CATCH ternary pn_kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch var node 1.289 + * (PNK_ARRAY or PNK_OBJECT if destructuring) 1.290 + * pn_kid2: null or the catch guard expression 1.291 + * pn_kid3: catch block statements 1.292 + * PNK_BREAK name pn_atom: label or null 1.293 + * PNK_CONTINUE name pn_atom: label or null 1.294 + * PNK_WITH binary-obj pn_left: head expr; pn_right: body; pn_binary_obj: StaticWithObject 1.295 + * PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes 1.296 + * PNK_CONST each name node has either 1.297 + * pn_used: false 1.298 + * pn_atom: variable name 1.299 + * pn_expr: initializer or null 1.300 + * or 1.301 + * pn_used: true 1.302 + * pn_atom: variable name 1.303 + * pn_lexdef: def node 1.304 + * each assignment node has 1.305 + * pn_left: PNK_NAME with pn_used true and 1.306 + * pn_lexdef (NOT pn_expr) set 1.307 + * pn_right: initializer 1.308 + * PNK_RETURN unary pn_kid: return expr or null 1.309 + * PNK_SEMI unary pn_kid: expr or null statement 1.310 + * pn_prologue: true if Directive Prologue member 1.311 + * in original source, not introduced via 1.312 + * constant folding or other tree rewriting 1.313 + * PNK_LABEL name pn_atom: label, pn_expr: labeled statement 1.314 + * 1.315 + * <Expressions> 1.316 + * All left-associated binary trees of the same type are optimized into lists 1.317 + * to avoid recursion when processing expression chains. 1.318 + * PNK_COMMA list pn_head: list of pn_count comma-separated exprs 1.319 + * PNK_ASSIGN binary pn_left: lvalue, pn_right: rvalue 1.320 + * PNK_ADDASSIGN, binary pn_left: lvalue, pn_right: rvalue 1.321 + * PNK_SUBASSIGN, pn_op: JSOP_ADD for +=, etc. 1.322 + * PNK_BITORASSIGN, 1.323 + * PNK_BITXORASSIGN, 1.324 + * PNK_BITANDASSIGN, 1.325 + * PNK_LSHASSIGN, 1.326 + * PNK_RSHASSIGN, 1.327 + * PNK_URSHASSIGN, 1.328 + * PNK_MULASSIGN, 1.329 + * PNK_DIVASSIGN, 1.330 + * PNK_MODASSIGN 1.331 + * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr) 1.332 + * pn_kid1: cond, pn_kid2: then, pn_kid3: else 1.333 + * PNK_OR binary pn_left: first in || chain, pn_right: rest of chain 1.334 + * PNK_AND binary pn_left: first in && chain, pn_right: rest of chain 1.335 + * PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr 1.336 + * PNK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr 1.337 + * PNK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr 1.338 + * 1.339 + * PNK_EQ, binary pn_left: left-assoc EQ expr, pn_right: REL expr 1.340 + * PNK_NE, 1.341 + * PNK_STRICTEQ, 1.342 + * PNK_STRICTNE 1.343 + * PNK_LT, binary pn_left: left-assoc REL expr, pn_right: SH expr 1.344 + * PNK_LE, 1.345 + * PNK_GT, 1.346 + * PNK_GE 1.347 + * PNK_LSH, binary pn_left: left-assoc SH expr, pn_right: ADD expr 1.348 + * PNK_RSH, 1.349 + * PNK_URSH 1.350 + * PNK_ADD binary pn_left: left-assoc ADD expr, pn_right: MUL expr 1.351 + * pn_xflags: if a left-associated binary PNK_ADD 1.352 + * tree has been flattened into a list (see above 1.353 + * under <Expressions>), pn_xflags will contain 1.354 + * PNX_STRCAT if at least one list element is a 1.355 + * string literal (PNK_STRING); if such a list has 1.356 + * any non-string, non-number term, pn_xflags will 1.357 + * contain PNX_CANTFOLD. 1.358 + * PNK_SUB binary pn_left: left-assoc SH expr, pn_right: ADD expr 1.359 + * PNK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr 1.360 + * PNK_DIV, pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD 1.361 + * PNK_MOD 1.362 + * PNK_POS, unary pn_kid: UNARY expr 1.363 + * PNK_NEG 1.364 + * PNK_TYPEOF, unary pn_kid: UNARY expr 1.365 + * PNK_VOID, 1.366 + * PNK_NOT, 1.367 + * PNK_BITNOT 1.368 + * PNK_PREINCREMENT, unary pn_kid: MEMBER expr 1.369 + * PNK_POSTINCREMENT, 1.370 + * PNK_PREDECREMENT, 1.371 + * PNK_POSTDECREMENT 1.372 + * PNK_NEW list pn_head: list of ctor, arg1, arg2, ... argN 1.373 + * pn_count: 1 + N (where N is number of args) 1.374 + * ctor is a MEMBER expr 1.375 + * PNK_DELETE unary pn_kid: MEMBER expr 1.376 + * PNK_DOT name pn_expr: MEMBER expr to left of . 1.377 + * pn_atom: name to right of . 1.378 + * PNK_ELEM binary pn_left: MEMBER expr to left of [ 1.379 + * pn_right: expr between [ and ] 1.380 + * PNK_CALL list pn_head: list of call, arg1, arg2, ... argN 1.381 + * pn_count: 1 + N (where N is number of args) 1.382 + * call is a MEMBER expr naming a callable object 1.383 + * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call 1.384 + * in the desugaring of a generator-expression. 1.385 + * PNK_ARRAY list pn_head: list of pn_count array element exprs 1.386 + * [,,] holes are represented by PNK_ELISION nodes 1.387 + * pn_xflags: PN_ENDCOMMA if extra comma at end 1.388 + * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes 1.389 + * PNK_COLON binary key-value pair in object initializer or 1.390 + * destructuring lhs 1.391 + * pn_left: property id, pn_right: value 1.392 + * var {x} = object destructuring shorthand shares 1.393 + * PN_NAME node for x on left and right of PNK_COLON 1.394 + * node in PNK_OBJECT's list, has PNX_DESTRUCT flag 1.395 + * PNK_NAME, name pn_atom: name, string, or object atom 1.396 + * PNK_STRING pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT 1.397 + * If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR 1.398 + * with pn_cookie telling (staticLevel, slot) (see 1.399 + * jsscript.h's UPVAR macros) and pn_dflags telling 1.400 + * const-ness and static analysis results 1.401 + * PNK_REGEXP nullary pn_objbox: RegExp model object 1.402 + * PNK_NAME name If pn_used, PNK_NAME uses the lexdef member instead 1.403 + * of the expr member it overlays 1.404 + * PNK_NUMBER dval pn_dval: double value of numeric literal 1.405 + * PNK_TRUE, nullary pn_op: JSOp bytecode 1.406 + * PNK_FALSE, 1.407 + * PNK_NULL, 1.408 + * PNK_THIS 1.409 + * 1.410 + * PNK_LEXICALSCOPE name pn_objbox: block object in ObjectBox holder 1.411 + * pn_expr: block body 1.412 + * PNK_ARRAYCOMP list pn_count: 1 1.413 + * pn_head: list of 1 element, which is block 1.414 + * enclosing for loop(s) and optionally 1.415 + * if-guarded PNK_ARRAYPUSH 1.416 + * PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP 1.417 + * pn_kid: array comprehension expression 1.418 + * PNK_NOP nullary 1.419 + */ 1.420 +enum ParseNodeArity 1.421 +{ 1.422 + PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */ 1.423 + PN_UNARY, /* one kid, plus a couple of scalars */ 1.424 + PN_BINARY, /* two kids, plus a couple of scalars */ 1.425 + PN_BINARY_OBJ, /* two kids, plus an objbox */ 1.426 + PN_TERNARY, /* three kids */ 1.427 + PN_CODE, /* module or function definition node */ 1.428 + PN_LIST, /* generic singly linked list */ 1.429 + PN_NAME /* name use or definition node */ 1.430 +}; 1.431 + 1.432 +struct Definition; 1.433 + 1.434 +class LabeledStatement; 1.435 +class LoopControlStatement; 1.436 +class BreakStatement; 1.437 +class ContinueStatement; 1.438 +class ConditionalExpression; 1.439 +class PropertyAccess; 1.440 + 1.441 +class ParseNode 1.442 +{ 1.443 + uint32_t pn_type : 16, /* PNK_* type */ 1.444 + pn_op : 8, /* see JSOp enum and jsopcode.tbl */ 1.445 + pn_arity : 5, /* see ParseNodeArity enum */ 1.446 + pn_parens : 1, /* this expr was enclosed in parens */ 1.447 + pn_used : 1, /* name node is on a use-chain */ 1.448 + pn_defn : 1; /* this node is a Definition */ 1.449 + 1.450 + ParseNode(const ParseNode &other) MOZ_DELETE; 1.451 + void operator=(const ParseNode &other) MOZ_DELETE; 1.452 + 1.453 + public: 1.454 + ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity) 1.455 + : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0), 1.456 + pn_pos(0, 0), pn_offset(0), pn_next(nullptr), pn_link(nullptr) 1.457 + { 1.458 + JS_ASSERT(kind < PNK_LIMIT); 1.459 + memset(&pn_u, 0, sizeof pn_u); 1.460 + } 1.461 + 1.462 + ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos &pos) 1.463 + : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0), 1.464 + pn_pos(pos), pn_offset(0), pn_next(nullptr), pn_link(nullptr) 1.465 + { 1.466 + JS_ASSERT(kind < PNK_LIMIT); 1.467 + memset(&pn_u, 0, sizeof pn_u); 1.468 + } 1.469 + 1.470 + JSOp getOp() const { return JSOp(pn_op); } 1.471 + void setOp(JSOp op) { pn_op = op; } 1.472 + bool isOp(JSOp op) const { return getOp() == op; } 1.473 + 1.474 + ParseNodeKind getKind() const { 1.475 + JS_ASSERT(pn_type < PNK_LIMIT); 1.476 + return ParseNodeKind(pn_type); 1.477 + } 1.478 + void setKind(ParseNodeKind kind) { 1.479 + JS_ASSERT(kind < PNK_LIMIT); 1.480 + pn_type = kind; 1.481 + } 1.482 + bool isKind(ParseNodeKind kind) const { return getKind() == kind; } 1.483 + 1.484 + ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); } 1.485 + bool isArity(ParseNodeArity a) const { return getArity() == a; } 1.486 + void setArity(ParseNodeArity a) { pn_arity = a; } 1.487 + 1.488 + bool isAssignment() const { 1.489 + ParseNodeKind kind = getKind(); 1.490 + return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST; 1.491 + } 1.492 + 1.493 + /* Boolean attributes. */ 1.494 + bool isInParens() const { return pn_parens; } 1.495 + void setInParens(bool enabled) { pn_parens = enabled; } 1.496 + bool isUsed() const { return pn_used; } 1.497 + void setUsed(bool enabled) { pn_used = enabled; } 1.498 + bool isDefn() const { return pn_defn; } 1.499 + void setDefn(bool enabled) { pn_defn = enabled; } 1.500 + 1.501 + static const unsigned NumDefinitionFlagBits = 10; 1.502 + static const unsigned NumListFlagBits = 10; 1.503 + static const unsigned NumBlockIdBits = 22; 1.504 + static_assert(NumDefinitionFlagBits == NumListFlagBits, 1.505 + "Assumed below to achieve consistent blockid offset"); 1.506 + static_assert(NumDefinitionFlagBits + NumBlockIdBits <= 32, 1.507 + "This is supposed to fit in a single uint32_t"); 1.508 + 1.509 + TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ 1.510 + int32_t pn_offset; /* first generated bytecode offset */ 1.511 + ParseNode *pn_next; /* intrinsic link in parent PN_LIST */ 1.512 + ParseNode *pn_link; /* def/use link (alignment freebie) */ 1.513 + 1.514 + union { 1.515 + struct { /* list of next-linked nodes */ 1.516 + ParseNode *head; /* first node in list */ 1.517 + ParseNode **tail; /* ptr to ptr to last node in list */ 1.518 + uint32_t count; /* number of nodes in list */ 1.519 + uint32_t xflags:NumListFlagBits, /* see PNX_* below */ 1.520 + blockid:NumBlockIdBits; /* see name variant below */ 1.521 + } list; 1.522 + struct { /* ternary: if, for(;;), ?: */ 1.523 + ParseNode *kid1; /* condition, discriminant, etc. */ 1.524 + ParseNode *kid2; /* then-part, case list, etc. */ 1.525 + ParseNode *kid3; /* else-part, default case, etc. */ 1.526 + } ternary; 1.527 + struct { /* two kids if binary */ 1.528 + ParseNode *left; 1.529 + ParseNode *right; 1.530 + union { 1.531 + unsigned iflags; /* JSITER_* flags for PNK_FOR node */ 1.532 + ObjectBox *objbox; /* Only for PN_BINARY_OBJ */ 1.533 + }; 1.534 + } binary; 1.535 + struct { /* one kid if unary */ 1.536 + ParseNode *kid; 1.537 + bool prologue; /* directive prologue member (as 1.538 + pn_prologue) */ 1.539 + } unary; 1.540 + struct { /* name, labeled statement, etc. */ 1.541 + union { 1.542 + JSAtom *atom; /* lexical name or label atom */ 1.543 + ObjectBox *objbox; /* block or regexp object */ 1.544 + FunctionBox *funbox; /* function object */ 1.545 + }; 1.546 + union { 1.547 + ParseNode *expr; /* module or function body, var 1.548 + initializer, argument default, or 1.549 + base object of PNK_DOT */ 1.550 + Definition *lexdef; /* lexical definition for this use */ 1.551 + }; 1.552 + UpvarCookie cookie; /* upvar cookie with absolute frame 1.553 + level (not relative skip), possibly 1.554 + in current frame */ 1.555 + uint32_t dflags:NumDefinitionFlagBits, /* see PND_* below */ 1.556 + blockid:NumBlockIdBits; /* block number, for subset dominance 1.557 + computation */ 1.558 + } name; 1.559 + struct { 1.560 + double value; /* aligned numeric literal value */ 1.561 + DecimalPoint decimalPoint; /* Whether the number has a decimal point */ 1.562 + } number; 1.563 + class { 1.564 + friend class LoopControlStatement; 1.565 + PropertyName *label; /* target of break/continue statement */ 1.566 + } loopControl; 1.567 + } pn_u; 1.568 + 1.569 +#define pn_modulebox pn_u.name.modulebox 1.570 +#define pn_funbox pn_u.name.funbox 1.571 +#define pn_body pn_u.name.expr 1.572 +#define pn_cookie pn_u.name.cookie 1.573 +#define pn_dflags pn_u.name.dflags 1.574 +#define pn_blockid pn_u.name.blockid 1.575 +#define pn_index pn_u.name.blockid /* reuse as object table index */ 1.576 +#define pn_head pn_u.list.head 1.577 +#define pn_tail pn_u.list.tail 1.578 +#define pn_count pn_u.list.count 1.579 +#define pn_xflags pn_u.list.xflags 1.580 +#define pn_kid1 pn_u.ternary.kid1 1.581 +#define pn_kid2 pn_u.ternary.kid2 1.582 +#define pn_kid3 pn_u.ternary.kid3 1.583 +#define pn_left pn_u.binary.left 1.584 +#define pn_right pn_u.binary.right 1.585 +#define pn_pval pn_u.binary.pval 1.586 +#define pn_iflags pn_u.binary.iflags 1.587 +#define pn_binary_obj pn_u.binary.objbox 1.588 +#define pn_kid pn_u.unary.kid 1.589 +#define pn_prologue pn_u.unary.prologue 1.590 +#define pn_atom pn_u.name.atom 1.591 +#define pn_objbox pn_u.name.objbox 1.592 +#define pn_expr pn_u.name.expr 1.593 +#define pn_lexdef pn_u.name.lexdef 1.594 +#define pn_dval pn_u.number.value 1.595 + 1.596 + protected: 1.597 + void init(TokenKind type, JSOp op, ParseNodeArity arity) { 1.598 + pn_type = type; 1.599 + pn_op = op; 1.600 + pn_arity = arity; 1.601 + pn_parens = false; 1.602 + JS_ASSERT(!pn_used); 1.603 + JS_ASSERT(!pn_defn); 1.604 + pn_next = pn_link = nullptr; 1.605 + } 1.606 + 1.607 + static ParseNode *create(ParseNodeKind kind, ParseNodeArity arity, FullParseHandler *handler); 1.608 + 1.609 + public: 1.610 + /* 1.611 + * Append right to left, forming a list node. |left| must have the given 1.612 + * kind and op, and op must be left-associative. 1.613 + */ 1.614 + static ParseNode * 1.615 + append(ParseNodeKind tt, JSOp op, ParseNode *left, ParseNode *right, FullParseHandler *handler); 1.616 + 1.617 + /* 1.618 + * Either append right to left, if left meets the conditions necessary to 1.619 + * append (see append), or form a binary node whose children are right and 1.620 + * left. 1.621 + */ 1.622 + static ParseNode * 1.623 + newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right, 1.624 + FullParseHandler *handler, ParseContext<FullParseHandler> *pc, 1.625 + bool foldConstants); 1.626 + 1.627 + inline PropertyName *name() const; 1.628 + inline JSAtom *atom() const; 1.629 + 1.630 + /* 1.631 + * The pn_expr and lexdef members are arms of an unsafe union. Unless you 1.632 + * know exactly what you're doing, use only the following methods to access 1.633 + * them. For less overhead and assertions for protection, use pn->expr() 1.634 + * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef(). 1.635 + */ 1.636 + ParseNode *expr() const { 1.637 + JS_ASSERT(!pn_used); 1.638 + JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_CODE); 1.639 + return pn_expr; 1.640 + } 1.641 + 1.642 + Definition *lexdef() const { 1.643 + JS_ASSERT(pn_used || isDeoptimized()); 1.644 + JS_ASSERT(pn_arity == PN_NAME); 1.645 + return pn_lexdef; 1.646 + } 1.647 + 1.648 + ParseNode *maybeExpr() { return pn_used ? nullptr : expr(); } 1.649 + Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; } 1.650 + 1.651 + Definition *resolve(); 1.652 + 1.653 +/* PN_CODE and PN_NAME pn_dflags bits. */ 1.654 +#define PND_LET 0x01 /* let (block-scoped) binding */ 1.655 +#define PND_CONST 0x02 /* const binding (orthogonal to let) */ 1.656 +#define PND_ASSIGNED 0x04 /* set if ever LHS of assignment */ 1.657 +#define PND_PLACEHOLDER 0x08 /* placeholder definition for lexdep */ 1.658 +#define PND_BOUND 0x10 /* bound to a stack or global slot */ 1.659 +#define PND_DEOPTIMIZED 0x20 /* former pn_used name node, pn_lexdef 1.660 + still valid, but this use no longer 1.661 + optimizable via an upvar opcode */ 1.662 +#define PND_CLOSED 0x40 /* variable is closed over */ 1.663 +#define PND_DEFAULT 0x80 /* definition is an arg with a default */ 1.664 +#define PND_IMPLICITARGUMENTS 0x100 /* the definition is a placeholder for 1.665 + 'arguments' that has been converted 1.666 + into a definition after the function 1.667 + body has been parsed. */ 1.668 +#define PND_EMITTEDFUNCTION 0x200 /* hoisted function that was emitted */ 1.669 + 1.670 + static_assert(PND_EMITTEDFUNCTION < (1 << NumDefinitionFlagBits), "Not enough bits"); 1.671 + 1.672 +/* Flags to propagate from uses to definition. */ 1.673 +#define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED) 1.674 + 1.675 +/* PN_LIST pn_xflags bits. */ 1.676 +#define PNX_POPVAR 0x01 /* PNK_VAR or PNK_CONST last result 1.677 + needs popping */ 1.678 +#define PNX_GROUPINIT 0x02 /* var [a, b] = [c, d]; unit list */ 1.679 +#define PNX_FUNCDEFS 0x04 /* contains top-level function statements */ 1.680 +#define PNX_SETCALL 0x08 /* call expression in lvalue context */ 1.681 +#define PNX_DESTRUCT 0x10 /* destructuring special cases: 1.682 + 1. shorthand syntax used, at present 1.683 + object destructuring ({x,y}) only; 1.684 + 2. code evaluating destructuring 1.685 + arguments occurs before function 1.686 + body */ 1.687 +#define PNX_SPECIALARRAYINIT 0x20 /* one or more of 1.688 + 1. array initialiser has holes 1.689 + 2. array initializer has spread node */ 1.690 +#define PNX_NONCONST 0x40 /* initialiser has non-constants */ 1.691 + 1.692 + static_assert(PNX_NONCONST < (1 << NumListFlagBits), "Not enough bits"); 1.693 + 1.694 + unsigned frameLevel() const { 1.695 + JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME); 1.696 + return pn_cookie.level(); 1.697 + } 1.698 + 1.699 + uint32_t frameSlot() const { 1.700 + JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME); 1.701 + return pn_cookie.slot(); 1.702 + } 1.703 + 1.704 + bool functionIsHoisted() const { 1.705 + JS_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION); 1.706 + JS_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr 1.707 + isOp(JSOP_LAMBDA_ARROW) || // arrow function 1.708 + isOp(JSOP_DEFFUN) || // non-body-level function statement 1.709 + isOp(JSOP_NOP) || // body-level function stmt in global code 1.710 + isOp(JSOP_GETLOCAL) || // body-level function stmt in function code 1.711 + isOp(JSOP_GETARG)); // body-level function redeclaring formal 1.712 + return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN); 1.713 + } 1.714 + 1.715 + /* 1.716 + * True if this statement node could be a member of a Directive Prologue: an 1.717 + * expression statement consisting of a single string literal. 1.718 + * 1.719 + * This considers only the node and its children, not its context. After 1.720 + * parsing, check the node's pn_prologue flag to see if it is indeed part of 1.721 + * a directive prologue. 1.722 + * 1.723 + * Note that a Directive Prologue can contain statements that cannot 1.724 + * themselves be directives (string literals that include escape sequences 1.725 + * or escaped newlines, say). This member function returns true for such 1.726 + * nodes; we use it to determine the extent of the prologue. 1.727 + */ 1.728 + JSAtom *isStringExprStatement() const { 1.729 + if (getKind() == PNK_SEMI) { 1.730 + JS_ASSERT(pn_arity == PN_UNARY); 1.731 + ParseNode *kid = pn_kid; 1.732 + if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens) 1.733 + return kid->pn_atom; 1.734 + } 1.735 + return nullptr; 1.736 + } 1.737 + 1.738 + inline bool test(unsigned flag) const; 1.739 + 1.740 + bool isLet() const { return test(PND_LET); } 1.741 + bool isConst() const { return test(PND_CONST); } 1.742 + bool isPlaceholder() const { return test(PND_PLACEHOLDER); } 1.743 + bool isDeoptimized() const { return test(PND_DEOPTIMIZED); } 1.744 + bool isAssigned() const { return test(PND_ASSIGNED); } 1.745 + bool isClosed() const { return test(PND_CLOSED); } 1.746 + bool isBound() const { return test(PND_BOUND); } 1.747 + bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); } 1.748 + 1.749 + /* True if pn is a parsenode representing a literal constant. */ 1.750 + bool isLiteral() const { 1.751 + return isKind(PNK_NUMBER) || 1.752 + isKind(PNK_STRING) || 1.753 + isKind(PNK_TRUE) || 1.754 + isKind(PNK_FALSE) || 1.755 + isKind(PNK_NULL); 1.756 + } 1.757 + 1.758 + /* Return true if this node appears in a Directive Prologue. */ 1.759 + bool isDirectivePrologueMember() const { return pn_prologue; } 1.760 + 1.761 +#ifdef JS_HAS_GENERATOR_EXPRS 1.762 + ParseNode *generatorExpr() const { 1.763 + JS_ASSERT(isKind(PNK_GENEXP)); 1.764 + ParseNode *callee = this->pn_head; 1.765 + ParseNode *body = callee->pn_body; 1.766 + JS_ASSERT(body->isKind(PNK_LEXICALSCOPE)); 1.767 + return body->pn_expr; 1.768 + } 1.769 +#endif 1.770 + 1.771 + inline void markAsAssigned(); 1.772 + 1.773 + /* 1.774 + * Compute a pointer to the last element in a singly-linked list. NB: list 1.775 + * must be non-empty for correct PN_LAST usage -- this is asserted! 1.776 + */ 1.777 + ParseNode *last() const { 1.778 + JS_ASSERT(pn_arity == PN_LIST); 1.779 + JS_ASSERT(pn_count != 0); 1.780 + return (ParseNode *)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next)); 1.781 + } 1.782 + 1.783 + void initNumber(double value, DecimalPoint decimalPoint) { 1.784 + JS_ASSERT(pn_arity == PN_NULLARY); 1.785 + JS_ASSERT(getKind() == PNK_NUMBER); 1.786 + pn_u.number.value = value; 1.787 + pn_u.number.decimalPoint = decimalPoint; 1.788 + } 1.789 + 1.790 + void makeEmpty() { 1.791 + JS_ASSERT(pn_arity == PN_LIST); 1.792 + pn_head = nullptr; 1.793 + pn_tail = &pn_head; 1.794 + pn_count = 0; 1.795 + pn_xflags = 0; 1.796 + pn_blockid = 0; 1.797 + } 1.798 + 1.799 + void initList(ParseNode *pn) { 1.800 + JS_ASSERT(pn_arity == PN_LIST); 1.801 + if (pn->pn_pos.begin < pn_pos.begin) 1.802 + pn_pos.begin = pn->pn_pos.begin; 1.803 + pn_pos.end = pn->pn_pos.end; 1.804 + pn_head = pn; 1.805 + pn_tail = &pn->pn_next; 1.806 + pn_count = 1; 1.807 + pn_xflags = 0; 1.808 + pn_blockid = 0; 1.809 + } 1.810 + 1.811 + void append(ParseNode *pn) { 1.812 + JS_ASSERT(pn_arity == PN_LIST); 1.813 + JS_ASSERT(pn->pn_pos.begin >= pn_pos.begin); 1.814 + pn_pos.end = pn->pn_pos.end; 1.815 + *pn_tail = pn; 1.816 + pn_tail = &pn->pn_next; 1.817 + pn_count++; 1.818 + } 1.819 + 1.820 + void checkListConsistency() 1.821 +#ifndef DEBUG 1.822 + {} 1.823 +#endif 1.824 + ; 1.825 + 1.826 + bool getConstantValue(ExclusiveContext *cx, bool strictChecks, MutableHandleValue vp); 1.827 + inline bool isConstant(); 1.828 + 1.829 + template <class NodeType> 1.830 + inline bool is() const { 1.831 + return NodeType::test(*this); 1.832 + } 1.833 + 1.834 + /* Casting operations. */ 1.835 + template <class NodeType> 1.836 + inline NodeType &as() { 1.837 + JS_ASSERT(NodeType::test(*this)); 1.838 + return *static_cast<NodeType *>(this); 1.839 + } 1.840 + 1.841 + template <class NodeType> 1.842 + inline const NodeType &as() const { 1.843 + JS_ASSERT(NodeType::test(*this)); 1.844 + return *static_cast<const NodeType *>(this); 1.845 + } 1.846 + 1.847 +#ifdef DEBUG 1.848 + void dump(); 1.849 + void dump(int indent); 1.850 +#endif 1.851 +}; 1.852 + 1.853 +struct NullaryNode : public ParseNode 1.854 +{ 1.855 + NullaryNode(ParseNodeKind kind, const TokenPos &pos) 1.856 + : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {} 1.857 + NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos) 1.858 + : ParseNode(kind, op, PN_NULLARY, pos) {} 1.859 + 1.860 + // This constructor is for a few mad uses in the emitter. It populates 1.861 + // the pn_atom field even though that field belongs to a branch in pn_u 1.862 + // that nullary nodes shouldn't use -- bogus. 1.863 + NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, JSAtom *atom) 1.864 + : ParseNode(kind, op, PN_NULLARY, pos) 1.865 + { 1.866 + pn_atom = atom; 1.867 + } 1.868 + 1.869 + static bool test(const ParseNode &node) { 1.870 + return node.isArity(PN_NULLARY); 1.871 + } 1.872 + 1.873 +#ifdef DEBUG 1.874 + void dump(); 1.875 +#endif 1.876 +}; 1.877 + 1.878 +struct UnaryNode : public ParseNode 1.879 +{ 1.880 + UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *kid) 1.881 + : ParseNode(kind, op, PN_UNARY, pos) 1.882 + { 1.883 + pn_kid = kid; 1.884 + } 1.885 + 1.886 + static inline UnaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.887 + return (UnaryNode *) ParseNode::create(kind, PN_UNARY, handler); 1.888 + } 1.889 + 1.890 + static bool test(const ParseNode &node) { 1.891 + return node.isArity(PN_UNARY); 1.892 + } 1.893 + 1.894 +#ifdef DEBUG 1.895 + void dump(int indent); 1.896 +#endif 1.897 +}; 1.898 + 1.899 +struct BinaryNode : public ParseNode 1.900 +{ 1.901 + BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right) 1.902 + : ParseNode(kind, op, PN_BINARY, pos) 1.903 + { 1.904 + pn_left = left; 1.905 + pn_right = right; 1.906 + } 1.907 + 1.908 + BinaryNode(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right) 1.909 + : ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos)) 1.910 + { 1.911 + pn_left = left; 1.912 + pn_right = right; 1.913 + } 1.914 + 1.915 + static inline BinaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.916 + return (BinaryNode *) ParseNode::create(kind, PN_BINARY, handler); 1.917 + } 1.918 + 1.919 + static bool test(const ParseNode &node) { 1.920 + return node.isArity(PN_BINARY); 1.921 + } 1.922 + 1.923 +#ifdef DEBUG 1.924 + void dump(int indent); 1.925 +#endif 1.926 +}; 1.927 + 1.928 +struct BinaryObjNode : public ParseNode 1.929 +{ 1.930 + BinaryObjNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right, 1.931 + ObjectBox *objbox) 1.932 + : ParseNode(kind, op, PN_BINARY_OBJ, pos) 1.933 + { 1.934 + pn_left = left; 1.935 + pn_right = right; 1.936 + pn_binary_obj = objbox; 1.937 + } 1.938 + 1.939 + static inline BinaryObjNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.940 + return (BinaryObjNode *) ParseNode::create(kind, PN_BINARY_OBJ, handler); 1.941 + } 1.942 + 1.943 + static bool test(const ParseNode &node) { 1.944 + return node.isArity(PN_BINARY_OBJ); 1.945 + } 1.946 + 1.947 +#ifdef DEBUG 1.948 + void dump(int indent); 1.949 +#endif 1.950 +}; 1.951 + 1.952 +struct TernaryNode : public ParseNode 1.953 +{ 1.954 + TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3) 1.955 + : ParseNode(kind, op, PN_TERNARY, 1.956 + TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin, 1.957 + (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end)) 1.958 + { 1.959 + pn_kid1 = kid1; 1.960 + pn_kid2 = kid2; 1.961 + pn_kid3 = kid3; 1.962 + } 1.963 + 1.964 + TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3, 1.965 + const TokenPos &pos) 1.966 + : ParseNode(kind, op, PN_TERNARY, pos) 1.967 + { 1.968 + pn_kid1 = kid1; 1.969 + pn_kid2 = kid2; 1.970 + pn_kid3 = kid3; 1.971 + } 1.972 + 1.973 + static inline TernaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.974 + return (TernaryNode *) ParseNode::create(kind, PN_TERNARY, handler); 1.975 + } 1.976 + 1.977 + static bool test(const ParseNode &node) { 1.978 + return node.isArity(PN_TERNARY); 1.979 + } 1.980 + 1.981 +#ifdef DEBUG 1.982 + void dump(int indent); 1.983 +#endif 1.984 +}; 1.985 + 1.986 +struct ListNode : public ParseNode 1.987 +{ 1.988 + ListNode(ParseNodeKind kind, const TokenPos &pos) 1.989 + : ParseNode(kind, JSOP_NOP, PN_LIST, pos) 1.990 + { 1.991 + makeEmpty(); 1.992 + } 1.993 + 1.994 + ListNode(ParseNodeKind kind, JSOp op, ParseNode *kid) 1.995 + : ParseNode(kind, op, PN_LIST, kid->pn_pos) 1.996 + { 1.997 + initList(kid); 1.998 + } 1.999 + 1.1000 + static inline ListNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.1001 + return (ListNode *) ParseNode::create(kind, PN_LIST, handler); 1.1002 + } 1.1003 + 1.1004 + static bool test(const ParseNode &node) { 1.1005 + return node.isArity(PN_LIST); 1.1006 + } 1.1007 + 1.1008 +#ifdef DEBUG 1.1009 + void dump(int indent); 1.1010 +#endif 1.1011 +}; 1.1012 + 1.1013 +struct CodeNode : public ParseNode 1.1014 +{ 1.1015 + static inline CodeNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.1016 + return (CodeNode *) ParseNode::create(kind, PN_CODE, handler); 1.1017 + } 1.1018 + 1.1019 + static bool test(const ParseNode &node) { 1.1020 + return node.isArity(PN_CODE); 1.1021 + } 1.1022 + 1.1023 +#ifdef DEBUG 1.1024 + void dump(int indent); 1.1025 +#endif 1.1026 +}; 1.1027 + 1.1028 +struct NameNode : public ParseNode 1.1029 +{ 1.1030 + NameNode(ParseNodeKind kind, JSOp op, JSAtom *atom, uint32_t blockid, 1.1031 + const TokenPos &pos) 1.1032 + : ParseNode(kind, op, PN_NAME, pos) 1.1033 + { 1.1034 + pn_atom = atom; 1.1035 + pn_expr = nullptr; 1.1036 + pn_cookie.makeFree(); 1.1037 + pn_dflags = 0; 1.1038 + pn_blockid = blockid; 1.1039 + JS_ASSERT(pn_blockid == blockid); // check for bitfield overflow 1.1040 + } 1.1041 + 1.1042 + static bool test(const ParseNode &node) { 1.1043 + return node.isArity(PN_NAME); 1.1044 + } 1.1045 + 1.1046 +#ifdef DEBUG 1.1047 + void dump(int indent); 1.1048 +#endif 1.1049 +}; 1.1050 + 1.1051 +struct LexicalScopeNode : public ParseNode 1.1052 +{ 1.1053 + static inline LexicalScopeNode *create(ParseNodeKind kind, FullParseHandler *handler) { 1.1054 + return (LexicalScopeNode *) ParseNode::create(kind, PN_NAME, handler); 1.1055 + } 1.1056 +}; 1.1057 + 1.1058 +class LabeledStatement : public ParseNode 1.1059 +{ 1.1060 + public: 1.1061 + LabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) 1.1062 + : ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos(begin, stmt->pn_pos.end)) 1.1063 + { 1.1064 + pn_atom = label; 1.1065 + pn_expr = stmt; 1.1066 + } 1.1067 + 1.1068 + PropertyName *label() const { 1.1069 + return pn_atom->asPropertyName(); 1.1070 + } 1.1071 + 1.1072 + ParseNode *statement() const { 1.1073 + return pn_expr; 1.1074 + } 1.1075 + 1.1076 + static bool test(const ParseNode &node) { 1.1077 + bool match = node.isKind(PNK_LABEL); 1.1078 + JS_ASSERT_IF(match, node.isArity(PN_NAME)); 1.1079 + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); 1.1080 + return match; 1.1081 + } 1.1082 +}; 1.1083 + 1.1084 +class LoopControlStatement : public ParseNode 1.1085 +{ 1.1086 + protected: 1.1087 + LoopControlStatement(ParseNodeKind kind, PropertyName *label, const TokenPos &pos) 1.1088 + : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) 1.1089 + { 1.1090 + JS_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE); 1.1091 + pn_u.loopControl.label = label; 1.1092 + } 1.1093 + 1.1094 + public: 1.1095 + /* Label associated with this break/continue statement, if any. */ 1.1096 + PropertyName *label() const { 1.1097 + return pn_u.loopControl.label; 1.1098 + } 1.1099 + 1.1100 + static bool test(const ParseNode &node) { 1.1101 + bool match = node.isKind(PNK_BREAK) || node.isKind(PNK_CONTINUE); 1.1102 + JS_ASSERT_IF(match, node.isArity(PN_NULLARY)); 1.1103 + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); 1.1104 + return match; 1.1105 + } 1.1106 +}; 1.1107 + 1.1108 +class BreakStatement : public LoopControlStatement 1.1109 +{ 1.1110 + public: 1.1111 + BreakStatement(PropertyName *label, const TokenPos &pos) 1.1112 + : LoopControlStatement(PNK_BREAK, label, pos) 1.1113 + { } 1.1114 + 1.1115 + static bool test(const ParseNode &node) { 1.1116 + bool match = node.isKind(PNK_BREAK); 1.1117 + JS_ASSERT_IF(match, node.isArity(PN_NULLARY)); 1.1118 + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); 1.1119 + return match; 1.1120 + } 1.1121 +}; 1.1122 + 1.1123 +class ContinueStatement : public LoopControlStatement 1.1124 +{ 1.1125 + public: 1.1126 + ContinueStatement(PropertyName *label, const TokenPos &pos) 1.1127 + : LoopControlStatement(PNK_CONTINUE, label, pos) 1.1128 + { } 1.1129 + 1.1130 + static bool test(const ParseNode &node) { 1.1131 + bool match = node.isKind(PNK_CONTINUE); 1.1132 + JS_ASSERT_IF(match, node.isArity(PN_NULLARY)); 1.1133 + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); 1.1134 + return match; 1.1135 + } 1.1136 +}; 1.1137 + 1.1138 +class DebuggerStatement : public ParseNode 1.1139 +{ 1.1140 + public: 1.1141 + DebuggerStatement(const TokenPos &pos) 1.1142 + : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos) 1.1143 + { } 1.1144 +}; 1.1145 + 1.1146 +class ConditionalExpression : public ParseNode 1.1147 +{ 1.1148 + public: 1.1149 + ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr) 1.1150 + : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY, 1.1151 + TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end)) 1.1152 + { 1.1153 + JS_ASSERT(condition); 1.1154 + JS_ASSERT(thenExpr); 1.1155 + JS_ASSERT(elseExpr); 1.1156 + pn_u.ternary.kid1 = condition; 1.1157 + pn_u.ternary.kid2 = thenExpr; 1.1158 + pn_u.ternary.kid3 = elseExpr; 1.1159 + } 1.1160 + 1.1161 + ParseNode &condition() const { 1.1162 + return *pn_u.ternary.kid1; 1.1163 + } 1.1164 + 1.1165 + ParseNode &thenExpression() const { 1.1166 + return *pn_u.ternary.kid2; 1.1167 + } 1.1168 + 1.1169 + ParseNode &elseExpression() const { 1.1170 + return *pn_u.ternary.kid3; 1.1171 + } 1.1172 + 1.1173 + static bool test(const ParseNode &node) { 1.1174 + bool match = node.isKind(PNK_CONDITIONAL); 1.1175 + JS_ASSERT_IF(match, node.isArity(PN_TERNARY)); 1.1176 + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); 1.1177 + return match; 1.1178 + } 1.1179 +}; 1.1180 + 1.1181 +class ThisLiteral : public ParseNode 1.1182 +{ 1.1183 + public: 1.1184 + ThisLiteral(const TokenPos &pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { } 1.1185 +}; 1.1186 + 1.1187 +class NullLiteral : public ParseNode 1.1188 +{ 1.1189 + public: 1.1190 + NullLiteral(const TokenPos &pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { } 1.1191 +}; 1.1192 + 1.1193 +class BooleanLiteral : public ParseNode 1.1194 +{ 1.1195 + public: 1.1196 + BooleanLiteral(bool b, const TokenPos &pos) 1.1197 + : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos) 1.1198 + { } 1.1199 +}; 1.1200 + 1.1201 +class RegExpLiteral : public NullaryNode 1.1202 +{ 1.1203 + public: 1.1204 + RegExpLiteral(ObjectBox *reobj, const TokenPos &pos) 1.1205 + : NullaryNode(PNK_REGEXP, JSOP_REGEXP, pos) 1.1206 + { 1.1207 + pn_objbox = reobj; 1.1208 + } 1.1209 + 1.1210 + ObjectBox *objbox() const { return pn_objbox; } 1.1211 + 1.1212 + static bool test(const ParseNode &node) { 1.1213 + bool match = node.isKind(PNK_REGEXP); 1.1214 + JS_ASSERT_IF(match, node.isArity(PN_NULLARY)); 1.1215 + JS_ASSERT_IF(match, node.isOp(JSOP_REGEXP)); 1.1216 + return match; 1.1217 + } 1.1218 +}; 1.1219 + 1.1220 +class PropertyAccess : public ParseNode 1.1221 +{ 1.1222 + public: 1.1223 + PropertyAccess(ParseNode *lhs, PropertyName *name, uint32_t begin, uint32_t end) 1.1224 + : ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end)) 1.1225 + { 1.1226 + JS_ASSERT(lhs != nullptr); 1.1227 + JS_ASSERT(name != nullptr); 1.1228 + pn_u.name.expr = lhs; 1.1229 + pn_u.name.atom = name; 1.1230 + } 1.1231 + 1.1232 + static bool test(const ParseNode &node) { 1.1233 + bool match = node.isKind(PNK_DOT); 1.1234 + JS_ASSERT_IF(match, node.isArity(PN_NAME)); 1.1235 + return match; 1.1236 + } 1.1237 + 1.1238 + ParseNode &expression() const { 1.1239 + return *pn_u.name.expr; 1.1240 + } 1.1241 + 1.1242 + PropertyName &name() const { 1.1243 + return *pn_u.name.atom->asPropertyName(); 1.1244 + } 1.1245 +}; 1.1246 + 1.1247 +class PropertyByValue : public ParseNode 1.1248 +{ 1.1249 + public: 1.1250 + PropertyByValue(ParseNode *lhs, ParseNode *propExpr, uint32_t begin, uint32_t end) 1.1251 + : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end)) 1.1252 + { 1.1253 + pn_u.binary.left = lhs; 1.1254 + pn_u.binary.right = propExpr; 1.1255 + } 1.1256 +}; 1.1257 + 1.1258 +#ifdef DEBUG 1.1259 +void DumpParseTree(ParseNode *pn, int indent = 0); 1.1260 +#endif 1.1261 + 1.1262 +/* 1.1263 + * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants 1.1264 + * of js::ParseNode, allocated only for function, var, const, and let 1.1265 + * declarations that define truly lexical bindings. This means that a child of 1.1266 + * a PNK_VAR list may be a Definition as well as a ParseNode. The pn_defn bit 1.1267 + * is set for all Definitions, clear otherwise. 1.1268 + * 1.1269 + * In an upvars list, defn->resolve() is the outermost definition the 1.1270 + * name may reference. If a with block or a function that calls eval encloses 1.1271 + * the use, the name may end up referring to something else at runtime. 1.1272 + * 1.1273 + * Note that not all var declarations are definitions: JS allows multiple var 1.1274 + * declarations in a function or script, but only the first creates the hoisted 1.1275 + * binding. JS programmers do redeclare variables for good refactoring reasons, 1.1276 + * for example: 1.1277 + * 1.1278 + * function foo() { 1.1279 + * ... 1.1280 + * for (var i ...) ...; 1.1281 + * ... 1.1282 + * for (var i ...) ...; 1.1283 + * ... 1.1284 + * } 1.1285 + * 1.1286 + * Not all definitions bind lexical variables, alas. In global and eval code 1.1287 + * var may re-declare a pre-existing property having any attributes, with or 1.1288 + * without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through 1.1289 + * 3 require function and var to bind deletable bindings. Global vars thus are 1.1290 + * properties of the global object, so they can be aliased even if they can't 1.1291 + * be deleted. 1.1292 + * 1.1293 + * Only bindings within function code may be treated as lexical, of course with 1.1294 + * the caveat that hoisting means use before initialization is allowed. We deal 1.1295 + * with use before declaration in one pass as follows (error checking elided): 1.1296 + * 1.1297 + * for (each use of unqualified name x in parse order) { 1.1298 + * if (this use of x is a declaration) { 1.1299 + * if (x in pc->decls) { // redeclaring 1.1300 + * pn = allocate a PN_NAME ParseNode; 1.1301 + * } else { // defining 1.1302 + * dn = lookup x in pc->lexdeps; 1.1303 + * if (dn) // use before def 1.1304 + * remove x from pc->lexdeps; 1.1305 + * else // def before use 1.1306 + * dn = allocate a PN_NAME Definition; 1.1307 + * map x to dn via pc->decls; 1.1308 + * pn = dn; 1.1309 + * } 1.1310 + * insert pn into its parent PNK_VAR/PNK_CONST list; 1.1311 + * } else { 1.1312 + * pn = allocate a ParseNode for this reference to x; 1.1313 + * dn = lookup x in pc's lexical scope chain; 1.1314 + * if (!dn) { 1.1315 + * dn = lookup x in pc->lexdeps; 1.1316 + * if (!dn) { 1.1317 + * dn = pre-allocate a Definition for x; 1.1318 + * map x to dn in pc->lexdeps; 1.1319 + * } 1.1320 + * } 1.1321 + * append pn to dn's use chain; 1.1322 + * } 1.1323 + * } 1.1324 + * 1.1325 + * See frontend/BytecodeEmitter.h for js::ParseContext and its top*Stmt, 1.1326 + * decls, and lexdeps members. 1.1327 + * 1.1328 + * Notes: 1.1329 + * 1.1330 + * 0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn 1.1331 + * and set it on a ParseNode instead of allocating a Definition. 1.1332 + * 1.1333 + * 1. Due to hoisting, a definition cannot be eliminated even if its "Variable 1.1334 + * statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in 1.1335 + * ParseNode.cpp will not recycle a node whose pn_defn bit is set. 1.1336 + * 1.1337 + * 2. "lookup x in pc's lexical scope chain" gives up on def/use chaining if a 1.1338 + * with statement is found along the the scope chain, which includes pc, 1.1339 + * pc->parent, etc. Thus we eagerly connect an inner function's use of an 1.1340 + * outer's var x if the var x was parsed before the inner function. 1.1341 + * 1.1342 + * 3. A use may be eliminated as dead by the constant folder, which therefore 1.1343 + * must remove the dead name node from its singly-linked use chain, which 1.1344 + * would mean hashing to find the definition node and searching to update 1.1345 + * the pn_link pointing at the use to be removed. This is costly, so as for 1.1346 + * dead definitions, we do not recycle dead pn_used nodes. 1.1347 + * 1.1348 + * At the end of parsing a function body or global or eval program, pc->lexdeps 1.1349 + * holds the lexical dependencies of the parsed unit. The name to def/use chain 1.1350 + * mappings are then merged into the parent pc->lexdeps. 1.1351 + * 1.1352 + * Thus if a later var x is parsed in the outer function satisfying an earlier 1.1353 + * inner function's use of x, we will remove dn from pc->lexdeps and re-use it 1.1354 + * as the new definition node in the outer function's parse tree. 1.1355 + * 1.1356 + * When the compiler unwinds from the outermost pc, pc->lexdeps contains the 1.1357 + * definition nodes with use chains for all free variables. These are either 1.1358 + * global variables or reference errors. 1.1359 + */ 1.1360 +#define dn_uses pn_link 1.1361 + 1.1362 +struct Definition : public ParseNode 1.1363 +{ 1.1364 + bool isFreeVar() const { 1.1365 + JS_ASSERT(isDefn()); 1.1366 + return pn_cookie.isFree(); 1.1367 + } 1.1368 + 1.1369 + enum Kind { MISSING = 0, VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER }; 1.1370 + 1.1371 + bool canHaveInitializer() { return int(kind()) <= int(ARG); } 1.1372 + 1.1373 + static const char *kindString(Kind kind); 1.1374 + 1.1375 + Kind kind() { 1.1376 + if (getKind() == PNK_FUNCTION) { 1.1377 + if (isOp(JSOP_GETARG)) 1.1378 + return ARG; 1.1379 + return VAR; 1.1380 + } 1.1381 + JS_ASSERT(getKind() == PNK_NAME); 1.1382 + if (isOp(JSOP_CALLEE)) 1.1383 + return NAMED_LAMBDA; 1.1384 + if (isPlaceholder()) 1.1385 + return PLACEHOLDER; 1.1386 + if (isOp(JSOP_GETARG)) 1.1387 + return ARG; 1.1388 + if (isConst()) 1.1389 + return CONST; 1.1390 + if (isLet()) 1.1391 + return LET; 1.1392 + return VAR; 1.1393 + } 1.1394 +}; 1.1395 + 1.1396 +class ParseNodeAllocator 1.1397 +{ 1.1398 + public: 1.1399 + explicit ParseNodeAllocator(ExclusiveContext *cx, LifoAlloc &alloc) 1.1400 + : cx(cx), alloc(alloc), freelist(nullptr) 1.1401 + {} 1.1402 + 1.1403 + void *allocNode(); 1.1404 + void freeNode(ParseNode *pn); 1.1405 + ParseNode *freeTree(ParseNode *pn); 1.1406 + void prepareNodeForMutation(ParseNode *pn); 1.1407 + 1.1408 + private: 1.1409 + ExclusiveContext *cx; 1.1410 + LifoAlloc &alloc; 1.1411 + ParseNode *freelist; 1.1412 +}; 1.1413 + 1.1414 +inline bool 1.1415 +ParseNode::test(unsigned flag) const 1.1416 +{ 1.1417 + JS_ASSERT(pn_defn || pn_arity == PN_CODE || pn_arity == PN_NAME); 1.1418 +#ifdef DEBUG 1.1419 + if ((flag & PND_ASSIGNED) && pn_defn && !(pn_dflags & flag)) { 1.1420 + for (ParseNode *pn = ((Definition *) this)->dn_uses; pn; pn = pn->pn_link) { 1.1421 + JS_ASSERT(!pn->pn_defn); 1.1422 + JS_ASSERT(!(pn->pn_dflags & flag)); 1.1423 + } 1.1424 + } 1.1425 +#endif 1.1426 + return !!(pn_dflags & flag); 1.1427 +} 1.1428 + 1.1429 +inline void 1.1430 +ParseNode::markAsAssigned() 1.1431 +{ 1.1432 + JS_ASSERT(js_CodeSpec[pn_op].format & JOF_NAME); 1.1433 + if (isUsed()) 1.1434 + pn_lexdef->pn_dflags |= PND_ASSIGNED; 1.1435 + pn_dflags |= PND_ASSIGNED; 1.1436 +} 1.1437 + 1.1438 +inline Definition * 1.1439 +ParseNode::resolve() 1.1440 +{ 1.1441 + if (isDefn()) 1.1442 + return (Definition *)this; 1.1443 + JS_ASSERT(lexdef()->isDefn()); 1.1444 + return (Definition *)lexdef(); 1.1445 +} 1.1446 + 1.1447 +inline bool 1.1448 +ParseNode::isConstant() 1.1449 +{ 1.1450 + switch (pn_type) { 1.1451 + case PNK_NUMBER: 1.1452 + case PNK_STRING: 1.1453 + case PNK_NULL: 1.1454 + case PNK_FALSE: 1.1455 + case PNK_TRUE: 1.1456 + return true; 1.1457 + case PNK_ARRAY: 1.1458 + case PNK_OBJECT: 1.1459 + JS_ASSERT(isOp(JSOP_NEWINIT)); 1.1460 + return !(pn_xflags & PNX_NONCONST); 1.1461 + default: 1.1462 + return false; 1.1463 + } 1.1464 +} 1.1465 + 1.1466 +class ObjectBox 1.1467 +{ 1.1468 + public: 1.1469 + JSObject *object; 1.1470 + 1.1471 + ObjectBox(JSObject *object, ObjectBox *traceLink); 1.1472 + bool isFunctionBox() { return object->is<JSFunction>(); } 1.1473 + FunctionBox *asFunctionBox(); 1.1474 + void trace(JSTracer *trc); 1.1475 + 1.1476 + protected: 1.1477 + friend struct CGObjectList; 1.1478 + 1.1479 + ObjectBox *traceLink; 1.1480 + ObjectBox *emitLink; 1.1481 + 1.1482 + ObjectBox(JSFunction *function, ObjectBox *traceLink); 1.1483 +}; 1.1484 + 1.1485 +enum ParseReportKind 1.1486 +{ 1.1487 + ParseError, 1.1488 + ParseWarning, 1.1489 + ParseExtraWarning, 1.1490 + ParseStrictError 1.1491 +}; 1.1492 + 1.1493 +enum FunctionSyntaxKind { Expression, Statement, Arrow }; 1.1494 + 1.1495 +static inline ParseNode * 1.1496 +FunctionArgsList(ParseNode *fn, unsigned *numFormals) 1.1497 +{ 1.1498 + JS_ASSERT(fn->isKind(PNK_FUNCTION)); 1.1499 + ParseNode *argsBody = fn->pn_body; 1.1500 + JS_ASSERT(argsBody->isKind(PNK_ARGSBODY)); 1.1501 + *numFormals = argsBody->pn_count; 1.1502 + if (*numFormals > 0 && argsBody->last()->isKind(PNK_STATEMENTLIST)) 1.1503 + (*numFormals)--; 1.1504 + JS_ASSERT(argsBody->isArity(PN_LIST)); 1.1505 + return argsBody->pn_head; 1.1506 +} 1.1507 + 1.1508 +} /* namespace frontend */ 1.1509 +} /* namespace js */ 1.1510 + 1.1511 +#endif /* frontend_ParseNode_h */