michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef frontend_FullParseHandler_h michael@0: #define frontend_FullParseHandler_h michael@0: michael@0: #include "mozilla/PodOperations.h" michael@0: michael@0: #include "frontend/ParseNode.h" michael@0: #include "frontend/SharedContext.h" michael@0: michael@0: namespace js { michael@0: namespace frontend { michael@0: michael@0: template michael@0: class Parser; michael@0: michael@0: class SyntaxParseHandler; michael@0: michael@0: // Parse handler used when generating a full parse tree for all code which the michael@0: // parser encounters. michael@0: class FullParseHandler michael@0: { michael@0: ParseNodeAllocator allocator; michael@0: TokenStream &tokenStream; michael@0: bool foldConstants; michael@0: michael@0: ParseNode *allocParseNode(size_t size) { michael@0: JS_ASSERT(size == sizeof(ParseNode)); michael@0: return static_cast(allocator.allocNode()); michael@0: } michael@0: michael@0: ParseNode *cloneNode(const ParseNode &other) { michael@0: ParseNode *node = allocParseNode(sizeof(ParseNode)); michael@0: if (!node) michael@0: return nullptr; michael@0: mozilla::PodAssign(node, &other); michael@0: return node; michael@0: } michael@0: michael@0: /* michael@0: * If this is a full parse to construct the bytecode for a function that michael@0: * was previously lazily parsed, that lazy function and the current index michael@0: * into its inner functions. We do not want to reparse the inner functions. michael@0: */ michael@0: LazyScript * const lazyOuterFunction_; michael@0: size_t lazyInnerFunctionIndex; michael@0: michael@0: const TokenPos &pos() { michael@0: return tokenStream.currentToken().pos; michael@0: } michael@0: michael@0: public: michael@0: michael@0: /* michael@0: * If non-nullptr, points to a syntax parser which can be used for inner michael@0: * functions. Cleared if language features not handled by the syntax parser michael@0: * are encountered, in which case all future activity will use the full michael@0: * parser. michael@0: */ michael@0: Parser *syntaxParser; michael@0: michael@0: /* new_ methods for creating parse nodes. These report OOM on context. */ michael@0: JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline) michael@0: michael@0: typedef ParseNode *Node; michael@0: typedef Definition *DefinitionNode; michael@0: michael@0: FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, michael@0: TokenStream &tokenStream, bool foldConstants, michael@0: Parser *syntaxParser, LazyScript *lazyOuterFunction) michael@0: : allocator(cx, alloc), michael@0: tokenStream(tokenStream), michael@0: foldConstants(foldConstants), michael@0: lazyOuterFunction_(lazyOuterFunction), michael@0: lazyInnerFunctionIndex(0), michael@0: syntaxParser(syntaxParser) michael@0: {} michael@0: michael@0: static ParseNode *null() { return nullptr; } michael@0: michael@0: ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); } michael@0: void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); } michael@0: const Token ¤tToken() { return tokenStream.currentToken(); } michael@0: michael@0: ParseNode *newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { michael@0: return new_(PNK_NAME, JSOP_NAME, name, blockid, pos); michael@0: } michael@0: michael@0: Definition *newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { michael@0: Definition *dn = michael@0: (Definition *) new_(PNK_NAME, JSOP_NOP, atom, blockid, pos); michael@0: if (!dn) michael@0: return nullptr; michael@0: dn->setDefn(true); michael@0: dn->pn_dflags |= PND_PLACEHOLDER; michael@0: return dn; michael@0: } michael@0: michael@0: ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) { michael@0: return new_(PNK_NAME, JSOP_NOP, pos, atom); michael@0: } michael@0: michael@0: ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { michael@0: ParseNode *pn = new_(PNK_NUMBER, pos); michael@0: if (!pn) michael@0: return nullptr; michael@0: pn->initNumber(value, decimalPoint); michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newBooleanLiteral(bool cond, const TokenPos &pos) { michael@0: return new_(cond, pos); michael@0: } michael@0: michael@0: ParseNode *newStringLiteral(JSAtom *atom, const TokenPos &pos) { michael@0: return new_(PNK_STRING, JSOP_STRING, pos, atom); michael@0: } michael@0: michael@0: ParseNode *newThisLiteral(const TokenPos &pos) { michael@0: return new_(pos); michael@0: } michael@0: michael@0: ParseNode *newNullLiteral(const TokenPos &pos) { michael@0: return new_(pos); michael@0: } michael@0: michael@0: // The Boxer object here is any object that can allocate ObjectBoxes. michael@0: // Specifically, a Boxer has a .newObjectBox(T) method that accepts a michael@0: // Rooted argument and returns an ObjectBox*. michael@0: template michael@0: ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) { michael@0: ObjectBox *objbox = boxer.newObjectBox(reobj); michael@0: if (!objbox) michael@0: return null(); michael@0: return new_(objbox, pos); michael@0: } michael@0: michael@0: ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) { michael@0: return new_(cond, thenExpr, elseExpr); michael@0: } michael@0: michael@0: void markAsSetCall(ParseNode *pn) { michael@0: pn->pn_xflags |= PNX_SETCALL; michael@0: } michael@0: michael@0: ParseNode *newDelete(uint32_t begin, ParseNode *expr) { michael@0: if (expr->getKind() == PNK_NAME) { michael@0: expr->pn_dflags |= PND_DEOPTIMIZED; michael@0: expr->setOp(JSOP_DELNAME); michael@0: } michael@0: return newUnary(PNK_DELETE, JSOP_NOP, begin, expr); michael@0: } michael@0: michael@0: ParseNode *newNullary(ParseNodeKind kind, JSOp op, const TokenPos &pos) { michael@0: return new_(kind, op, pos); michael@0: } michael@0: michael@0: ParseNode *newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode *kid) { michael@0: TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1); michael@0: return new_(kind, op, pos, kid); michael@0: } michael@0: michael@0: ParseNode *newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { michael@0: return new_(kind, op, pos(), (ParseNode *) nullptr, (ParseNode *) nullptr); michael@0: } michael@0: ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, michael@0: JSOp op = JSOP_NOP) { michael@0: return new_(kind, op, left->pn_pos, left, (ParseNode *) nullptr); michael@0: } michael@0: ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, ParseNode *right, michael@0: JSOp op = JSOP_NOP) { michael@0: TokenPos pos(left->pn_pos.begin, right->pn_pos.end); michael@0: return new_(kind, op, pos, left, right); michael@0: } michael@0: ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right, michael@0: ParseContext *pc, JSOp op = JSOP_NOP) michael@0: { michael@0: return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants); michael@0: } michael@0: michael@0: ParseNode *newTernary(ParseNodeKind kind, michael@0: ParseNode *first, ParseNode *second, ParseNode *third, michael@0: JSOp op = JSOP_NOP) michael@0: { michael@0: return new_(kind, op, first, second, third); michael@0: } michael@0: michael@0: // Expressions michael@0: michael@0: ParseNode *newArrayComprehension(ParseNode *body, unsigned blockid, const TokenPos &pos) { michael@0: JS_ASSERT(pos.begin <= body->pn_pos.begin); michael@0: JS_ASSERT(body->pn_pos.end <= pos.end); michael@0: ParseNode *pn = new_(PNK_ARRAYCOMP, pos); michael@0: if (!pn) michael@0: return nullptr; michael@0: pn->pn_blockid = blockid; michael@0: pn->append(body); michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newArrayLiteral(uint32_t begin, unsigned blockid) { michael@0: ParseNode *literal = new_(PNK_ARRAY, TokenPos(begin, begin + 1)); michael@0: // Later in this stack: remove dependency on this opcode. michael@0: if (literal) { michael@0: literal->setOp(JSOP_NEWINIT); michael@0: literal->pn_blockid = blockid; michael@0: } michael@0: return literal; michael@0: } michael@0: michael@0: bool addElision(ParseNode *literal, const TokenPos &pos) { michael@0: ParseNode *elision = new_(PNK_ELISION, pos); michael@0: if (!elision) michael@0: return false; michael@0: literal->append(elision); michael@0: literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; michael@0: return true; michael@0: } michael@0: michael@0: bool addSpreadElement(ParseNode *literal, uint32_t begin, ParseNode *inner) { michael@0: TokenPos pos(begin, inner->pn_pos.end); michael@0: ParseNode *spread = new_(PNK_SPREAD, JSOP_NOP, pos, inner); michael@0: if (!spread) michael@0: return null(); michael@0: literal->append(spread); michael@0: literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; michael@0: return true; michael@0: } michael@0: michael@0: bool addArrayElement(ParseNode *literal, ParseNode *element) { michael@0: if (!element->isConstant()) michael@0: literal->pn_xflags |= PNX_NONCONST; michael@0: literal->append(element); michael@0: return true; michael@0: } michael@0: michael@0: ParseNode *newObjectLiteral(uint32_t begin) { michael@0: ParseNode *literal = new_(PNK_OBJECT, TokenPos(begin, begin + 1)); michael@0: // Later in this stack: remove dependency on this opcode. michael@0: if (literal) michael@0: literal->setOp(JSOP_NEWINIT); michael@0: return literal; michael@0: } michael@0: michael@0: bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) { michael@0: ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP); michael@0: if (!propdef) michael@0: return false; michael@0: literal->append(propdef); michael@0: return true; michael@0: } michael@0: michael@0: bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) { michael@0: JS_ASSERT(literal->isArity(PN_LIST)); michael@0: literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; // XXX why PNX_DESTRUCT? michael@0: return addPropertyDefinition(literal, name, name); michael@0: } michael@0: michael@0: bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op) michael@0: { michael@0: JS_ASSERT(literal->isArity(PN_LIST)); michael@0: literal->pn_xflags |= PNX_NONCONST; michael@0: michael@0: ParseNode *propdef = newBinary(PNK_COLON, name, fn, op); michael@0: if (!propdef) michael@0: return false; michael@0: literal->append(propdef); michael@0: return true; michael@0: } michael@0: michael@0: // Statements michael@0: michael@0: ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) { michael@0: ParseNode *pn = new_(PNK_STATEMENTLIST, pos); michael@0: if (pn) michael@0: pn->pn_blockid = blockid; michael@0: return pn; michael@0: } michael@0: michael@0: template michael@0: void addStatementToList(ParseNode *list, ParseNode *stmt, PC *pc) { michael@0: JS_ASSERT(list->isKind(PNK_STATEMENTLIST)); michael@0: michael@0: if (stmt->isKind(PNK_FUNCTION)) { michael@0: if (pc->atBodyLevel()) { michael@0: // PNX_FUNCDEFS notifies the emitter that the block contains michael@0: // body-level function definitions that should be processed michael@0: // before the rest of nodes. michael@0: list->pn_xflags |= PNX_FUNCDEFS; michael@0: } else { michael@0: // General deoptimization was done in Parser::functionDef. michael@0: JS_ASSERT_IF(pc->sc->isFunctionBox(), michael@0: pc->sc->asFunctionBox()->hasExtensibleScope()); michael@0: } michael@0: } michael@0: michael@0: list->append(stmt); michael@0: } michael@0: michael@0: ParseNode *newEmptyStatement(const TokenPos &pos) { michael@0: return new_(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr); michael@0: } michael@0: michael@0: ParseNode *newImportDeclaration(ParseNode *importSpecSet, michael@0: ParseNode *moduleSpec, const TokenPos &pos) michael@0: { michael@0: ParseNode *pn = new_(PNK_IMPORT, JSOP_NOP, pos, michael@0: importSpecSet, moduleSpec); michael@0: if (!pn) michael@0: return null(); michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newExportDeclaration(ParseNode *kid, const TokenPos &pos) { michael@0: return new_(PNK_EXPORT, JSOP_NOP, pos, kid); michael@0: } michael@0: michael@0: ParseNode *newExportFromDeclaration(uint32_t begin, ParseNode *exportSpecSet, michael@0: ParseNode *moduleSpec) michael@0: { michael@0: ParseNode *pn = new_(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec); michael@0: if (!pn) michael@0: return null(); michael@0: pn->pn_pos.begin = begin; michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newExprStatement(ParseNode *expr, uint32_t end) { michael@0: JS_ASSERT(expr->pn_pos.end <= end); michael@0: return new_(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr); michael@0: } michael@0: michael@0: ParseNode *newIfStatement(uint32_t begin, ParseNode *cond, ParseNode *thenBranch, michael@0: ParseNode *elseBranch) michael@0: { michael@0: ParseNode *pn = new_(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch); michael@0: if (!pn) michael@0: return null(); michael@0: pn->pn_pos.begin = begin; michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newDoWhileStatement(ParseNode *body, ParseNode *cond, const TokenPos &pos) { michael@0: return new_(PNK_DOWHILE, JSOP_NOP, pos, body, cond); michael@0: } michael@0: michael@0: ParseNode *newWhileStatement(uint32_t begin, ParseNode *cond, ParseNode *body) { michael@0: TokenPos pos(begin, body->pn_pos.end); michael@0: return new_(PNK_WHILE, JSOP_NOP, pos, cond, body); michael@0: } michael@0: michael@0: ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body, michael@0: unsigned iflags) michael@0: { michael@0: /* A FOR node is binary, left is loop control and right is the body. */ michael@0: JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP; michael@0: BinaryNode *pn = new_(PNK_FOR, op, TokenPos(begin, body->pn_pos.end), michael@0: forHead, body); michael@0: if (!pn) michael@0: return null(); michael@0: pn->pn_iflags = iflags; michael@0: return pn; michael@0: } michael@0: michael@0: ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3, michael@0: const TokenPos &pos) michael@0: { michael@0: JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD); michael@0: return new_(kind, JSOP_NOP, pn1, pn2, pn3, pos); michael@0: } michael@0: michael@0: ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) { michael@0: TokenPos pos(begin, caseList->pn_pos.end); michael@0: return new_(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList); michael@0: } michael@0: michael@0: ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) { michael@0: TokenPos pos(begin, body->pn_pos.end); michael@0: return new_(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body); michael@0: } michael@0: michael@0: ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) { michael@0: return new_(label, pos); michael@0: } michael@0: michael@0: ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) { michael@0: return new_(label, pos); michael@0: } michael@0: michael@0: ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) { michael@0: JS_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); michael@0: return new_(PNK_RETURN, JSOP_RETURN, pos, expr); michael@0: } michael@0: michael@0: ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body, michael@0: ObjectBox *staticWith) { michael@0: return new_(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end), michael@0: expr, body, staticWith); michael@0: } michael@0: michael@0: ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) { michael@0: return new_(label, stmt, begin); michael@0: } michael@0: michael@0: ParseNode *newThrowStatement(ParseNode *expr, const TokenPos &pos) { michael@0: JS_ASSERT(pos.encloses(expr->pn_pos)); michael@0: return new_(PNK_THROW, JSOP_THROW, pos, expr); michael@0: } michael@0: michael@0: ParseNode *newTryStatement(uint32_t begin, ParseNode *body, ParseNode *catchList, michael@0: ParseNode *finallyBlock) { michael@0: TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); michael@0: return new_(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos); michael@0: } michael@0: michael@0: ParseNode *newDebuggerStatement(const TokenPos &pos) { michael@0: return new_(pos); michael@0: } michael@0: michael@0: ParseNode *newPropertyAccess(ParseNode *pn, PropertyName *name, uint32_t end) { michael@0: return new_(pn, name, pn->pn_pos.begin, end); michael@0: } michael@0: michael@0: ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) { michael@0: return new_(lhs, index, lhs->pn_pos.begin, end); michael@0: } michael@0: michael@0: inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock, michael@0: ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody); michael@0: michael@0: inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn); michael@0: inline ParseNode *newFunctionDefinition(); michael@0: void setFunctionBody(ParseNode *pn, ParseNode *kid) { michael@0: pn->pn_body = kid; michael@0: } michael@0: void setFunctionBox(ParseNode *pn, FunctionBox *funbox) { michael@0: JS_ASSERT(pn->isKind(PNK_FUNCTION)); michael@0: pn->pn_funbox = funbox; michael@0: } michael@0: void addFunctionArgument(ParseNode *pn, ParseNode *argpn) { michael@0: pn->pn_body->append(argpn); michael@0: } michael@0: michael@0: inline ParseNode *newLexicalScope(ObjectBox *blockbox); michael@0: inline void setLexicalScopeBody(ParseNode *block, ParseNode *body); michael@0: michael@0: bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) { michael@0: return pn->isKind(kind) && !pn->isInParens(); michael@0: } michael@0: michael@0: inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op); michael@0: michael@0: void setBeginPosition(ParseNode *pn, ParseNode *oth) { michael@0: setBeginPosition(pn, oth->pn_pos.begin); michael@0: } michael@0: void setBeginPosition(ParseNode *pn, uint32_t begin) { michael@0: pn->pn_pos.begin = begin; michael@0: JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); michael@0: } michael@0: michael@0: void setEndPosition(ParseNode *pn, ParseNode *oth) { michael@0: setEndPosition(pn, oth->pn_pos.end); michael@0: } michael@0: void setEndPosition(ParseNode *pn, uint32_t end) { michael@0: pn->pn_pos.end = end; michael@0: JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); michael@0: } michael@0: michael@0: void setPosition(ParseNode *pn, const TokenPos &pos) { michael@0: pn->pn_pos = pos; michael@0: } michael@0: TokenPos getPosition(ParseNode *pn) { michael@0: return pn->pn_pos; michael@0: } michael@0: michael@0: ParseNode *newList(ParseNodeKind kind, ParseNode *kid = nullptr, JSOp op = JSOP_NOP) { michael@0: ParseNode *pn = ListNode::create(kind, this); michael@0: if (!pn) michael@0: return nullptr; michael@0: pn->setOp(op); michael@0: pn->makeEmpty(); michael@0: if (kid) { michael@0: pn->pn_pos.begin = kid->pn_pos.begin; michael@0: pn->append(kid); michael@0: } michael@0: return pn; michael@0: } michael@0: void addList(ParseNode *pn, ParseNode *kid) { michael@0: pn->append(kid); michael@0: } michael@0: michael@0: bool isUnparenthesizedYield(ParseNode *pn) { michael@0: return pn->isKind(PNK_YIELD) && !pn->isInParens(); michael@0: } michael@0: michael@0: void setOp(ParseNode *pn, JSOp op) { michael@0: pn->setOp(op); michael@0: } michael@0: void setBlockId(ParseNode *pn, unsigned blockid) { michael@0: pn->pn_blockid = blockid; michael@0: } michael@0: void setFlag(ParseNode *pn, unsigned flag) { michael@0: pn->pn_dflags |= flag; michael@0: } michael@0: void setListFlag(ParseNode *pn, unsigned flag) { michael@0: JS_ASSERT(pn->isArity(PN_LIST)); michael@0: pn->pn_xflags |= flag; michael@0: } michael@0: ParseNode *setInParens(ParseNode *pn) { michael@0: pn->setInParens(true); michael@0: return pn; michael@0: } michael@0: void setPrologue(ParseNode *pn) { michael@0: pn->pn_prologue = true; michael@0: } michael@0: michael@0: bool isConstant(ParseNode *pn) { michael@0: return pn->isConstant(); michael@0: } michael@0: PropertyName *isName(ParseNode *pn) { michael@0: return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr; michael@0: } michael@0: bool isCall(ParseNode *pn) { michael@0: return pn->isKind(PNK_CALL); michael@0: } michael@0: PropertyName *isGetProp(ParseNode *pn) { michael@0: return pn->is() ? &pn->as().name() : nullptr; michael@0: } michael@0: JSAtom *isStringExprStatement(ParseNode *pn, TokenPos *pos) { michael@0: if (JSAtom *atom = pn->isStringExprStatement()) { michael@0: *pos = pn->pn_kid->pn_pos; michael@0: return atom; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs); michael@0: michael@0: static Definition *getDefinitionNode(Definition *dn) { michael@0: return dn; michael@0: } michael@0: static Definition::Kind getDefinitionKind(Definition *dn) { michael@0: return dn->kind(); michael@0: } michael@0: void linkUseToDef(ParseNode *pn, Definition *dn) michael@0: { michael@0: JS_ASSERT(!pn->isUsed()); michael@0: JS_ASSERT(!pn->isDefn()); michael@0: JS_ASSERT(pn != dn->dn_uses); michael@0: JS_ASSERT(dn->isDefn()); michael@0: pn->pn_link = dn->dn_uses; michael@0: dn->dn_uses = pn; michael@0: dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS; michael@0: pn->setUsed(true); michael@0: pn->pn_lexdef = dn; michael@0: } michael@0: Definition *resolve(Definition *dn) { michael@0: return dn->resolve(); michael@0: } michael@0: void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos) michael@0: { michael@0: for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { michael@0: JS_ASSERT(pnu->isUsed()); michael@0: JS_ASSERT(!pnu->isDefn()); michael@0: if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) michael@0: pnu->pn_dflags |= PND_DEOPTIMIZED; michael@0: } michael@0: } michael@0: bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) { michael@0: return pn->pn_blockid >= blockid; michael@0: } michael@0: michael@0: static uintptr_t definitionToBits(Definition *dn) { michael@0: return uintptr_t(dn); michael@0: } michael@0: static Definition *definitionFromBits(uintptr_t bits) { michael@0: return (Definition *) bits; michael@0: } michael@0: static Definition *nullDefinition() { michael@0: return nullptr; michael@0: } michael@0: void disableSyntaxParser() { michael@0: syntaxParser = nullptr; michael@0: } michael@0: michael@0: LazyScript *lazyOuterFunction() { michael@0: return lazyOuterFunction_; michael@0: } michael@0: JSFunction *nextLazyInnerFunction() { michael@0: JS_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions()); michael@0: return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++]; michael@0: } michael@0: }; michael@0: michael@0: inline bool michael@0: FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock, michael@0: ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody) michael@0: { michael@0: ParseNode *catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody); michael@0: if (!catchpn) michael@0: return false; michael@0: michael@0: catchList->append(letBlock); michael@0: letBlock->pn_expr = catchpn; michael@0: return true; michael@0: } michael@0: michael@0: inline void michael@0: FullParseHandler::setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *defaultValue) michael@0: { michael@0: ParseNode *arg = funcpn->pn_body->last(); michael@0: arg->pn_dflags |= PND_DEFAULT; michael@0: arg->pn_expr = defaultValue; michael@0: } michael@0: michael@0: inline ParseNode * michael@0: FullParseHandler::newFunctionDefinition() michael@0: { michael@0: ParseNode *pn = CodeNode::create(PNK_FUNCTION, this); michael@0: if (!pn) michael@0: return nullptr; michael@0: pn->pn_body = nullptr; michael@0: pn->pn_funbox = nullptr; michael@0: pn->pn_cookie.makeFree(); michael@0: pn->pn_dflags = 0; michael@0: return pn; michael@0: } michael@0: michael@0: inline ParseNode * michael@0: FullParseHandler::newLexicalScope(ObjectBox *blockbox) michael@0: { michael@0: ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, this); michael@0: if (!pn) michael@0: return nullptr; michael@0: michael@0: pn->pn_objbox = blockbox; michael@0: pn->pn_cookie.makeFree(); michael@0: pn->pn_dflags = 0; michael@0: return pn; michael@0: } michael@0: michael@0: inline void michael@0: FullParseHandler::setLexicalScopeBody(ParseNode *block, ParseNode *kid) michael@0: { michael@0: block->pn_expr = kid; michael@0: } michael@0: michael@0: inline bool michael@0: FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op) michael@0: { michael@0: if (pn->isUsed()) { michael@0: pn = makeAssignment(pn, init); michael@0: if (!pn) michael@0: return false; michael@0: } else { michael@0: pn->pn_expr = init; michael@0: } michael@0: michael@0: pn->setOp((pn->pn_dflags & PND_BOUND) michael@0: ? JSOP_SETLOCAL michael@0: : (op == JSOP_DEFCONST) michael@0: ? JSOP_SETCONST michael@0: : JSOP_SETNAME); michael@0: michael@0: pn->markAsAssigned(); michael@0: michael@0: /* The declarator's position must include the initializer. */ michael@0: pn->pn_pos.end = init->pn_pos.end; michael@0: return true; michael@0: } michael@0: michael@0: inline ParseNode * michael@0: FullParseHandler::makeAssignment(ParseNode *pn, ParseNode *rhs) michael@0: { michael@0: ParseNode *lhs = cloneNode(*pn); michael@0: if (!lhs) michael@0: return nullptr; michael@0: michael@0: if (pn->isUsed()) { michael@0: Definition *dn = pn->pn_lexdef; michael@0: ParseNode **pnup = &dn->dn_uses; michael@0: michael@0: while (*pnup != pn) michael@0: pnup = &(*pnup)->pn_link; michael@0: *pnup = lhs; michael@0: lhs->pn_link = pn->pn_link; michael@0: pn->pn_link = nullptr; michael@0: } michael@0: michael@0: pn->setKind(PNK_ASSIGN); michael@0: pn->setOp(JSOP_NOP); michael@0: pn->setArity(PN_BINARY); michael@0: pn->setInParens(false); michael@0: pn->setUsed(false); michael@0: pn->setDefn(false); michael@0: pn->pn_left = lhs; michael@0: pn->pn_right = rhs; michael@0: pn->pn_pos.end = rhs->pn_pos.end; michael@0: return lhs; michael@0: } michael@0: michael@0: } // frontend michael@0: } // js michael@0: michael@0: #endif /* frontend_FullParseHandler_h */