js/src/frontend/FullParseHandler.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef frontend_FullParseHandler_h
michael@0 8 #define frontend_FullParseHandler_h
michael@0 9
michael@0 10 #include "mozilla/PodOperations.h"
michael@0 11
michael@0 12 #include "frontend/ParseNode.h"
michael@0 13 #include "frontend/SharedContext.h"
michael@0 14
michael@0 15 namespace js {
michael@0 16 namespace frontend {
michael@0 17
michael@0 18 template <typename ParseHandler>
michael@0 19 class Parser;
michael@0 20
michael@0 21 class SyntaxParseHandler;
michael@0 22
michael@0 23 // Parse handler used when generating a full parse tree for all code which the
michael@0 24 // parser encounters.
michael@0 25 class FullParseHandler
michael@0 26 {
michael@0 27 ParseNodeAllocator allocator;
michael@0 28 TokenStream &tokenStream;
michael@0 29 bool foldConstants;
michael@0 30
michael@0 31 ParseNode *allocParseNode(size_t size) {
michael@0 32 JS_ASSERT(size == sizeof(ParseNode));
michael@0 33 return static_cast<ParseNode *>(allocator.allocNode());
michael@0 34 }
michael@0 35
michael@0 36 ParseNode *cloneNode(const ParseNode &other) {
michael@0 37 ParseNode *node = allocParseNode(sizeof(ParseNode));
michael@0 38 if (!node)
michael@0 39 return nullptr;
michael@0 40 mozilla::PodAssign(node, &other);
michael@0 41 return node;
michael@0 42 }
michael@0 43
michael@0 44 /*
michael@0 45 * If this is a full parse to construct the bytecode for a function that
michael@0 46 * was previously lazily parsed, that lazy function and the current index
michael@0 47 * into its inner functions. We do not want to reparse the inner functions.
michael@0 48 */
michael@0 49 LazyScript * const lazyOuterFunction_;
michael@0 50 size_t lazyInnerFunctionIndex;
michael@0 51
michael@0 52 const TokenPos &pos() {
michael@0 53 return tokenStream.currentToken().pos;
michael@0 54 }
michael@0 55
michael@0 56 public:
michael@0 57
michael@0 58 /*
michael@0 59 * If non-nullptr, points to a syntax parser which can be used for inner
michael@0 60 * functions. Cleared if language features not handled by the syntax parser
michael@0 61 * are encountered, in which case all future activity will use the full
michael@0 62 * parser.
michael@0 63 */
michael@0 64 Parser<SyntaxParseHandler> *syntaxParser;
michael@0 65
michael@0 66 /* new_ methods for creating parse nodes. These report OOM on context. */
michael@0 67 JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
michael@0 68
michael@0 69 typedef ParseNode *Node;
michael@0 70 typedef Definition *DefinitionNode;
michael@0 71
michael@0 72 FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc,
michael@0 73 TokenStream &tokenStream, bool foldConstants,
michael@0 74 Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
michael@0 75 : allocator(cx, alloc),
michael@0 76 tokenStream(tokenStream),
michael@0 77 foldConstants(foldConstants),
michael@0 78 lazyOuterFunction_(lazyOuterFunction),
michael@0 79 lazyInnerFunctionIndex(0),
michael@0 80 syntaxParser(syntaxParser)
michael@0 81 {}
michael@0 82
michael@0 83 static ParseNode *null() { return nullptr; }
michael@0 84
michael@0 85 ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); }
michael@0 86 void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); }
michael@0 87 const Token &currentToken() { return tokenStream.currentToken(); }
michael@0 88
michael@0 89 ParseNode *newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) {
michael@0 90 return new_<NameNode>(PNK_NAME, JSOP_NAME, name, blockid, pos);
michael@0 91 }
michael@0 92
michael@0 93 Definition *newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) {
michael@0 94 Definition *dn =
michael@0 95 (Definition *) new_<NameNode>(PNK_NAME, JSOP_NOP, atom, blockid, pos);
michael@0 96 if (!dn)
michael@0 97 return nullptr;
michael@0 98 dn->setDefn(true);
michael@0 99 dn->pn_dflags |= PND_PLACEHOLDER;
michael@0 100 return dn;
michael@0 101 }
michael@0 102
michael@0 103 ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) {
michael@0 104 return new_<NullaryNode>(PNK_NAME, JSOP_NOP, pos, atom);
michael@0 105 }
michael@0 106
michael@0 107 ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) {
michael@0 108 ParseNode *pn = new_<NullaryNode>(PNK_NUMBER, pos);
michael@0 109 if (!pn)
michael@0 110 return nullptr;
michael@0 111 pn->initNumber(value, decimalPoint);
michael@0 112 return pn;
michael@0 113 }
michael@0 114
michael@0 115 ParseNode *newBooleanLiteral(bool cond, const TokenPos &pos) {
michael@0 116 return new_<BooleanLiteral>(cond, pos);
michael@0 117 }
michael@0 118
michael@0 119 ParseNode *newStringLiteral(JSAtom *atom, const TokenPos &pos) {
michael@0 120 return new_<NullaryNode>(PNK_STRING, JSOP_STRING, pos, atom);
michael@0 121 }
michael@0 122
michael@0 123 ParseNode *newThisLiteral(const TokenPos &pos) {
michael@0 124 return new_<ThisLiteral>(pos);
michael@0 125 }
michael@0 126
michael@0 127 ParseNode *newNullLiteral(const TokenPos &pos) {
michael@0 128 return new_<NullLiteral>(pos);
michael@0 129 }
michael@0 130
michael@0 131 // The Boxer object here is any object that can allocate ObjectBoxes.
michael@0 132 // Specifically, a Boxer has a .newObjectBox(T) method that accepts a
michael@0 133 // Rooted<RegExpObject*> argument and returns an ObjectBox*.
michael@0 134 template <class Boxer>
michael@0 135 ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) {
michael@0 136 ObjectBox *objbox = boxer.newObjectBox(reobj);
michael@0 137 if (!objbox)
michael@0 138 return null();
michael@0 139 return new_<RegExpLiteral>(objbox, pos);
michael@0 140 }
michael@0 141
michael@0 142 ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) {
michael@0 143 return new_<ConditionalExpression>(cond, thenExpr, elseExpr);
michael@0 144 }
michael@0 145
michael@0 146 void markAsSetCall(ParseNode *pn) {
michael@0 147 pn->pn_xflags |= PNX_SETCALL;
michael@0 148 }
michael@0 149
michael@0 150 ParseNode *newDelete(uint32_t begin, ParseNode *expr) {
michael@0 151 if (expr->getKind() == PNK_NAME) {
michael@0 152 expr->pn_dflags |= PND_DEOPTIMIZED;
michael@0 153 expr->setOp(JSOP_DELNAME);
michael@0 154 }
michael@0 155 return newUnary(PNK_DELETE, JSOP_NOP, begin, expr);
michael@0 156 }
michael@0 157
michael@0 158 ParseNode *newNullary(ParseNodeKind kind, JSOp op, const TokenPos &pos) {
michael@0 159 return new_<NullaryNode>(kind, op, pos);
michael@0 160 }
michael@0 161
michael@0 162 ParseNode *newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode *kid) {
michael@0 163 TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1);
michael@0 164 return new_<UnaryNode>(kind, op, pos, kid);
michael@0 165 }
michael@0 166
michael@0 167 ParseNode *newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) {
michael@0 168 return new_<BinaryNode>(kind, op, pos(), (ParseNode *) nullptr, (ParseNode *) nullptr);
michael@0 169 }
michael@0 170 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left,
michael@0 171 JSOp op = JSOP_NOP) {
michael@0 172 return new_<BinaryNode>(kind, op, left->pn_pos, left, (ParseNode *) nullptr);
michael@0 173 }
michael@0 174 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, ParseNode *right,
michael@0 175 JSOp op = JSOP_NOP) {
michael@0 176 TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
michael@0 177 return new_<BinaryNode>(kind, op, pos, left, right);
michael@0 178 }
michael@0 179 ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right,
michael@0 180 ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
michael@0 181 {
michael@0 182 return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants);
michael@0 183 }
michael@0 184
michael@0 185 ParseNode *newTernary(ParseNodeKind kind,
michael@0 186 ParseNode *first, ParseNode *second, ParseNode *third,
michael@0 187 JSOp op = JSOP_NOP)
michael@0 188 {
michael@0 189 return new_<TernaryNode>(kind, op, first, second, third);
michael@0 190 }
michael@0 191
michael@0 192 // Expressions
michael@0 193
michael@0 194 ParseNode *newArrayComprehension(ParseNode *body, unsigned blockid, const TokenPos &pos) {
michael@0 195 JS_ASSERT(pos.begin <= body->pn_pos.begin);
michael@0 196 JS_ASSERT(body->pn_pos.end <= pos.end);
michael@0 197 ParseNode *pn = new_<ListNode>(PNK_ARRAYCOMP, pos);
michael@0 198 if (!pn)
michael@0 199 return nullptr;
michael@0 200 pn->pn_blockid = blockid;
michael@0 201 pn->append(body);
michael@0 202 return pn;
michael@0 203 }
michael@0 204
michael@0 205 ParseNode *newArrayLiteral(uint32_t begin, unsigned blockid) {
michael@0 206 ParseNode *literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
michael@0 207 // Later in this stack: remove dependency on this opcode.
michael@0 208 if (literal) {
michael@0 209 literal->setOp(JSOP_NEWINIT);
michael@0 210 literal->pn_blockid = blockid;
michael@0 211 }
michael@0 212 return literal;
michael@0 213 }
michael@0 214
michael@0 215 bool addElision(ParseNode *literal, const TokenPos &pos) {
michael@0 216 ParseNode *elision = new_<NullaryNode>(PNK_ELISION, pos);
michael@0 217 if (!elision)
michael@0 218 return false;
michael@0 219 literal->append(elision);
michael@0 220 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST;
michael@0 221 return true;
michael@0 222 }
michael@0 223
michael@0 224 bool addSpreadElement(ParseNode *literal, uint32_t begin, ParseNode *inner) {
michael@0 225 TokenPos pos(begin, inner->pn_pos.end);
michael@0 226 ParseNode *spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner);
michael@0 227 if (!spread)
michael@0 228 return null();
michael@0 229 literal->append(spread);
michael@0 230 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST;
michael@0 231 return true;
michael@0 232 }
michael@0 233
michael@0 234 bool addArrayElement(ParseNode *literal, ParseNode *element) {
michael@0 235 if (!element->isConstant())
michael@0 236 literal->pn_xflags |= PNX_NONCONST;
michael@0 237 literal->append(element);
michael@0 238 return true;
michael@0 239 }
michael@0 240
michael@0 241 ParseNode *newObjectLiteral(uint32_t begin) {
michael@0 242 ParseNode *literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
michael@0 243 // Later in this stack: remove dependency on this opcode.
michael@0 244 if (literal)
michael@0 245 literal->setOp(JSOP_NEWINIT);
michael@0 246 return literal;
michael@0 247 }
michael@0 248
michael@0 249 bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) {
michael@0 250 ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP);
michael@0 251 if (!propdef)
michael@0 252 return false;
michael@0 253 literal->append(propdef);
michael@0 254 return true;
michael@0 255 }
michael@0 256
michael@0 257 bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) {
michael@0 258 JS_ASSERT(literal->isArity(PN_LIST));
michael@0 259 literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; // XXX why PNX_DESTRUCT?
michael@0 260 return addPropertyDefinition(literal, name, name);
michael@0 261 }
michael@0 262
michael@0 263 bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op)
michael@0 264 {
michael@0 265 JS_ASSERT(literal->isArity(PN_LIST));
michael@0 266 literal->pn_xflags |= PNX_NONCONST;
michael@0 267
michael@0 268 ParseNode *propdef = newBinary(PNK_COLON, name, fn, op);
michael@0 269 if (!propdef)
michael@0 270 return false;
michael@0 271 literal->append(propdef);
michael@0 272 return true;
michael@0 273 }
michael@0 274
michael@0 275 // Statements
michael@0 276
michael@0 277 ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) {
michael@0 278 ParseNode *pn = new_<ListNode>(PNK_STATEMENTLIST, pos);
michael@0 279 if (pn)
michael@0 280 pn->pn_blockid = blockid;
michael@0 281 return pn;
michael@0 282 }
michael@0 283
michael@0 284 template <typename PC>
michael@0 285 void addStatementToList(ParseNode *list, ParseNode *stmt, PC *pc) {
michael@0 286 JS_ASSERT(list->isKind(PNK_STATEMENTLIST));
michael@0 287
michael@0 288 if (stmt->isKind(PNK_FUNCTION)) {
michael@0 289 if (pc->atBodyLevel()) {
michael@0 290 // PNX_FUNCDEFS notifies the emitter that the block contains
michael@0 291 // body-level function definitions that should be processed
michael@0 292 // before the rest of nodes.
michael@0 293 list->pn_xflags |= PNX_FUNCDEFS;
michael@0 294 } else {
michael@0 295 // General deoptimization was done in Parser::functionDef.
michael@0 296 JS_ASSERT_IF(pc->sc->isFunctionBox(),
michael@0 297 pc->sc->asFunctionBox()->hasExtensibleScope());
michael@0 298 }
michael@0 299 }
michael@0 300
michael@0 301 list->append(stmt);
michael@0 302 }
michael@0 303
michael@0 304 ParseNode *newEmptyStatement(const TokenPos &pos) {
michael@0 305 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
michael@0 306 }
michael@0 307
michael@0 308 ParseNode *newImportDeclaration(ParseNode *importSpecSet,
michael@0 309 ParseNode *moduleSpec, const TokenPos &pos)
michael@0 310 {
michael@0 311 ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos,
michael@0 312 importSpecSet, moduleSpec);
michael@0 313 if (!pn)
michael@0 314 return null();
michael@0 315 return pn;
michael@0 316 }
michael@0 317
michael@0 318 ParseNode *newExportDeclaration(ParseNode *kid, const TokenPos &pos) {
michael@0 319 return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid);
michael@0 320 }
michael@0 321
michael@0 322 ParseNode *newExportFromDeclaration(uint32_t begin, ParseNode *exportSpecSet,
michael@0 323 ParseNode *moduleSpec)
michael@0 324 {
michael@0 325 ParseNode *pn = new_<BinaryNode>(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec);
michael@0 326 if (!pn)
michael@0 327 return null();
michael@0 328 pn->pn_pos.begin = begin;
michael@0 329 return pn;
michael@0 330 }
michael@0 331
michael@0 332 ParseNode *newExprStatement(ParseNode *expr, uint32_t end) {
michael@0 333 JS_ASSERT(expr->pn_pos.end <= end);
michael@0 334 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr);
michael@0 335 }
michael@0 336
michael@0 337 ParseNode *newIfStatement(uint32_t begin, ParseNode *cond, ParseNode *thenBranch,
michael@0 338 ParseNode *elseBranch)
michael@0 339 {
michael@0 340 ParseNode *pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch);
michael@0 341 if (!pn)
michael@0 342 return null();
michael@0 343 pn->pn_pos.begin = begin;
michael@0 344 return pn;
michael@0 345 }
michael@0 346
michael@0 347 ParseNode *newDoWhileStatement(ParseNode *body, ParseNode *cond, const TokenPos &pos) {
michael@0 348 return new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, pos, body, cond);
michael@0 349 }
michael@0 350
michael@0 351 ParseNode *newWhileStatement(uint32_t begin, ParseNode *cond, ParseNode *body) {
michael@0 352 TokenPos pos(begin, body->pn_pos.end);
michael@0 353 return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body);
michael@0 354 }
michael@0 355
michael@0 356 ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body,
michael@0 357 unsigned iflags)
michael@0 358 {
michael@0 359 /* A FOR node is binary, left is loop control and right is the body. */
michael@0 360 JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
michael@0 361 BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end),
michael@0 362 forHead, body);
michael@0 363 if (!pn)
michael@0 364 return null();
michael@0 365 pn->pn_iflags = iflags;
michael@0 366 return pn;
michael@0 367 }
michael@0 368
michael@0 369 ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
michael@0 370 const TokenPos &pos)
michael@0 371 {
michael@0 372 JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD);
michael@0 373 return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
michael@0 374 }
michael@0 375
michael@0 376 ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) {
michael@0 377 TokenPos pos(begin, caseList->pn_pos.end);
michael@0 378 return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
michael@0 379 }
michael@0 380
michael@0 381 ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) {
michael@0 382 TokenPos pos(begin, body->pn_pos.end);
michael@0 383 return new_<BinaryNode>(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body);
michael@0 384 }
michael@0 385
michael@0 386 ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) {
michael@0 387 return new_<ContinueStatement>(label, pos);
michael@0 388 }
michael@0 389
michael@0 390 ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) {
michael@0 391 return new_<BreakStatement>(label, pos);
michael@0 392 }
michael@0 393
michael@0 394 ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) {
michael@0 395 JS_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
michael@0 396 return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
michael@0 397 }
michael@0 398
michael@0 399 ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body,
michael@0 400 ObjectBox *staticWith) {
michael@0 401 return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
michael@0 402 expr, body, staticWith);
michael@0 403 }
michael@0 404
michael@0 405 ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) {
michael@0 406 return new_<LabeledStatement>(label, stmt, begin);
michael@0 407 }
michael@0 408
michael@0 409 ParseNode *newThrowStatement(ParseNode *expr, const TokenPos &pos) {
michael@0 410 JS_ASSERT(pos.encloses(expr->pn_pos));
michael@0 411 return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr);
michael@0 412 }
michael@0 413
michael@0 414 ParseNode *newTryStatement(uint32_t begin, ParseNode *body, ParseNode *catchList,
michael@0 415 ParseNode *finallyBlock) {
michael@0 416 TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end);
michael@0 417 return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos);
michael@0 418 }
michael@0 419
michael@0 420 ParseNode *newDebuggerStatement(const TokenPos &pos) {
michael@0 421 return new_<DebuggerStatement>(pos);
michael@0 422 }
michael@0 423
michael@0 424 ParseNode *newPropertyAccess(ParseNode *pn, PropertyName *name, uint32_t end) {
michael@0 425 return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end);
michael@0 426 }
michael@0 427
michael@0 428 ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) {
michael@0 429 return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
michael@0 430 }
michael@0 431
michael@0 432 inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock,
michael@0 433 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody);
michael@0 434
michael@0 435 inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn);
michael@0 436 inline ParseNode *newFunctionDefinition();
michael@0 437 void setFunctionBody(ParseNode *pn, ParseNode *kid) {
michael@0 438 pn->pn_body = kid;
michael@0 439 }
michael@0 440 void setFunctionBox(ParseNode *pn, FunctionBox *funbox) {
michael@0 441 JS_ASSERT(pn->isKind(PNK_FUNCTION));
michael@0 442 pn->pn_funbox = funbox;
michael@0 443 }
michael@0 444 void addFunctionArgument(ParseNode *pn, ParseNode *argpn) {
michael@0 445 pn->pn_body->append(argpn);
michael@0 446 }
michael@0 447
michael@0 448 inline ParseNode *newLexicalScope(ObjectBox *blockbox);
michael@0 449 inline void setLexicalScopeBody(ParseNode *block, ParseNode *body);
michael@0 450
michael@0 451 bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) {
michael@0 452 return pn->isKind(kind) && !pn->isInParens();
michael@0 453 }
michael@0 454
michael@0 455 inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op);
michael@0 456
michael@0 457 void setBeginPosition(ParseNode *pn, ParseNode *oth) {
michael@0 458 setBeginPosition(pn, oth->pn_pos.begin);
michael@0 459 }
michael@0 460 void setBeginPosition(ParseNode *pn, uint32_t begin) {
michael@0 461 pn->pn_pos.begin = begin;
michael@0 462 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
michael@0 463 }
michael@0 464
michael@0 465 void setEndPosition(ParseNode *pn, ParseNode *oth) {
michael@0 466 setEndPosition(pn, oth->pn_pos.end);
michael@0 467 }
michael@0 468 void setEndPosition(ParseNode *pn, uint32_t end) {
michael@0 469 pn->pn_pos.end = end;
michael@0 470 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
michael@0 471 }
michael@0 472
michael@0 473 void setPosition(ParseNode *pn, const TokenPos &pos) {
michael@0 474 pn->pn_pos = pos;
michael@0 475 }
michael@0 476 TokenPos getPosition(ParseNode *pn) {
michael@0 477 return pn->pn_pos;
michael@0 478 }
michael@0 479
michael@0 480 ParseNode *newList(ParseNodeKind kind, ParseNode *kid = nullptr, JSOp op = JSOP_NOP) {
michael@0 481 ParseNode *pn = ListNode::create(kind, this);
michael@0 482 if (!pn)
michael@0 483 return nullptr;
michael@0 484 pn->setOp(op);
michael@0 485 pn->makeEmpty();
michael@0 486 if (kid) {
michael@0 487 pn->pn_pos.begin = kid->pn_pos.begin;
michael@0 488 pn->append(kid);
michael@0 489 }
michael@0 490 return pn;
michael@0 491 }
michael@0 492 void addList(ParseNode *pn, ParseNode *kid) {
michael@0 493 pn->append(kid);
michael@0 494 }
michael@0 495
michael@0 496 bool isUnparenthesizedYield(ParseNode *pn) {
michael@0 497 return pn->isKind(PNK_YIELD) && !pn->isInParens();
michael@0 498 }
michael@0 499
michael@0 500 void setOp(ParseNode *pn, JSOp op) {
michael@0 501 pn->setOp(op);
michael@0 502 }
michael@0 503 void setBlockId(ParseNode *pn, unsigned blockid) {
michael@0 504 pn->pn_blockid = blockid;
michael@0 505 }
michael@0 506 void setFlag(ParseNode *pn, unsigned flag) {
michael@0 507 pn->pn_dflags |= flag;
michael@0 508 }
michael@0 509 void setListFlag(ParseNode *pn, unsigned flag) {
michael@0 510 JS_ASSERT(pn->isArity(PN_LIST));
michael@0 511 pn->pn_xflags |= flag;
michael@0 512 }
michael@0 513 ParseNode *setInParens(ParseNode *pn) {
michael@0 514 pn->setInParens(true);
michael@0 515 return pn;
michael@0 516 }
michael@0 517 void setPrologue(ParseNode *pn) {
michael@0 518 pn->pn_prologue = true;
michael@0 519 }
michael@0 520
michael@0 521 bool isConstant(ParseNode *pn) {
michael@0 522 return pn->isConstant();
michael@0 523 }
michael@0 524 PropertyName *isName(ParseNode *pn) {
michael@0 525 return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr;
michael@0 526 }
michael@0 527 bool isCall(ParseNode *pn) {
michael@0 528 return pn->isKind(PNK_CALL);
michael@0 529 }
michael@0 530 PropertyName *isGetProp(ParseNode *pn) {
michael@0 531 return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr;
michael@0 532 }
michael@0 533 JSAtom *isStringExprStatement(ParseNode *pn, TokenPos *pos) {
michael@0 534 if (JSAtom *atom = pn->isStringExprStatement()) {
michael@0 535 *pos = pn->pn_kid->pn_pos;
michael@0 536 return atom;
michael@0 537 }
michael@0 538 return nullptr;
michael@0 539 }
michael@0 540
michael@0 541 inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
michael@0 542
michael@0 543 static Definition *getDefinitionNode(Definition *dn) {
michael@0 544 return dn;
michael@0 545 }
michael@0 546 static Definition::Kind getDefinitionKind(Definition *dn) {
michael@0 547 return dn->kind();
michael@0 548 }
michael@0 549 void linkUseToDef(ParseNode *pn, Definition *dn)
michael@0 550 {
michael@0 551 JS_ASSERT(!pn->isUsed());
michael@0 552 JS_ASSERT(!pn->isDefn());
michael@0 553 JS_ASSERT(pn != dn->dn_uses);
michael@0 554 JS_ASSERT(dn->isDefn());
michael@0 555 pn->pn_link = dn->dn_uses;
michael@0 556 dn->dn_uses = pn;
michael@0 557 dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
michael@0 558 pn->setUsed(true);
michael@0 559 pn->pn_lexdef = dn;
michael@0 560 }
michael@0 561 Definition *resolve(Definition *dn) {
michael@0 562 return dn->resolve();
michael@0 563 }
michael@0 564 void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
michael@0 565 {
michael@0 566 for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
michael@0 567 JS_ASSERT(pnu->isUsed());
michael@0 568 JS_ASSERT(!pnu->isDefn());
michael@0 569 if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
michael@0 570 pnu->pn_dflags |= PND_DEOPTIMIZED;
michael@0 571 }
michael@0 572 }
michael@0 573 bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
michael@0 574 return pn->pn_blockid >= blockid;
michael@0 575 }
michael@0 576
michael@0 577 static uintptr_t definitionToBits(Definition *dn) {
michael@0 578 return uintptr_t(dn);
michael@0 579 }
michael@0 580 static Definition *definitionFromBits(uintptr_t bits) {
michael@0 581 return (Definition *) bits;
michael@0 582 }
michael@0 583 static Definition *nullDefinition() {
michael@0 584 return nullptr;
michael@0 585 }
michael@0 586 void disableSyntaxParser() {
michael@0 587 syntaxParser = nullptr;
michael@0 588 }
michael@0 589
michael@0 590 LazyScript *lazyOuterFunction() {
michael@0 591 return lazyOuterFunction_;
michael@0 592 }
michael@0 593 JSFunction *nextLazyInnerFunction() {
michael@0 594 JS_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions());
michael@0 595 return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++];
michael@0 596 }
michael@0 597 };
michael@0 598
michael@0 599 inline bool
michael@0 600 FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock,
michael@0 601 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody)
michael@0 602 {
michael@0 603 ParseNode *catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody);
michael@0 604 if (!catchpn)
michael@0 605 return false;
michael@0 606
michael@0 607 catchList->append(letBlock);
michael@0 608 letBlock->pn_expr = catchpn;
michael@0 609 return true;
michael@0 610 }
michael@0 611
michael@0 612 inline void
michael@0 613 FullParseHandler::setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *defaultValue)
michael@0 614 {
michael@0 615 ParseNode *arg = funcpn->pn_body->last();
michael@0 616 arg->pn_dflags |= PND_DEFAULT;
michael@0 617 arg->pn_expr = defaultValue;
michael@0 618 }
michael@0 619
michael@0 620 inline ParseNode *
michael@0 621 FullParseHandler::newFunctionDefinition()
michael@0 622 {
michael@0 623 ParseNode *pn = CodeNode::create(PNK_FUNCTION, this);
michael@0 624 if (!pn)
michael@0 625 return nullptr;
michael@0 626 pn->pn_body = nullptr;
michael@0 627 pn->pn_funbox = nullptr;
michael@0 628 pn->pn_cookie.makeFree();
michael@0 629 pn->pn_dflags = 0;
michael@0 630 return pn;
michael@0 631 }
michael@0 632
michael@0 633 inline ParseNode *
michael@0 634 FullParseHandler::newLexicalScope(ObjectBox *blockbox)
michael@0 635 {
michael@0 636 ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, this);
michael@0 637 if (!pn)
michael@0 638 return nullptr;
michael@0 639
michael@0 640 pn->pn_objbox = blockbox;
michael@0 641 pn->pn_cookie.makeFree();
michael@0 642 pn->pn_dflags = 0;
michael@0 643 return pn;
michael@0 644 }
michael@0 645
michael@0 646 inline void
michael@0 647 FullParseHandler::setLexicalScopeBody(ParseNode *block, ParseNode *kid)
michael@0 648 {
michael@0 649 block->pn_expr = kid;
michael@0 650 }
michael@0 651
michael@0 652 inline bool
michael@0 653 FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op)
michael@0 654 {
michael@0 655 if (pn->isUsed()) {
michael@0 656 pn = makeAssignment(pn, init);
michael@0 657 if (!pn)
michael@0 658 return false;
michael@0 659 } else {
michael@0 660 pn->pn_expr = init;
michael@0 661 }
michael@0 662
michael@0 663 pn->setOp((pn->pn_dflags & PND_BOUND)
michael@0 664 ? JSOP_SETLOCAL
michael@0 665 : (op == JSOP_DEFCONST)
michael@0 666 ? JSOP_SETCONST
michael@0 667 : JSOP_SETNAME);
michael@0 668
michael@0 669 pn->markAsAssigned();
michael@0 670
michael@0 671 /* The declarator's position must include the initializer. */
michael@0 672 pn->pn_pos.end = init->pn_pos.end;
michael@0 673 return true;
michael@0 674 }
michael@0 675
michael@0 676 inline ParseNode *
michael@0 677 FullParseHandler::makeAssignment(ParseNode *pn, ParseNode *rhs)
michael@0 678 {
michael@0 679 ParseNode *lhs = cloneNode(*pn);
michael@0 680 if (!lhs)
michael@0 681 return nullptr;
michael@0 682
michael@0 683 if (pn->isUsed()) {
michael@0 684 Definition *dn = pn->pn_lexdef;
michael@0 685 ParseNode **pnup = &dn->dn_uses;
michael@0 686
michael@0 687 while (*pnup != pn)
michael@0 688 pnup = &(*pnup)->pn_link;
michael@0 689 *pnup = lhs;
michael@0 690 lhs->pn_link = pn->pn_link;
michael@0 691 pn->pn_link = nullptr;
michael@0 692 }
michael@0 693
michael@0 694 pn->setKind(PNK_ASSIGN);
michael@0 695 pn->setOp(JSOP_NOP);
michael@0 696 pn->setArity(PN_BINARY);
michael@0 697 pn->setInParens(false);
michael@0 698 pn->setUsed(false);
michael@0 699 pn->setDefn(false);
michael@0 700 pn->pn_left = lhs;
michael@0 701 pn->pn_right = rhs;
michael@0 702 pn->pn_pos.end = rhs->pn_pos.end;
michael@0 703 return lhs;
michael@0 704 }
michael@0 705
michael@0 706 } // frontend
michael@0 707 } // js
michael@0 708
michael@0 709 #endif /* frontend_FullParseHandler_h */

mercurial