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_SyntaxParseHandler_h michael@0: #define frontend_SyntaxParseHandler_h michael@0: michael@0: #include "frontend/ParseNode.h" michael@0: #include "frontend/TokenStream.h" michael@0: michael@0: namespace js { michael@0: namespace frontend { michael@0: michael@0: template michael@0: class Parser; michael@0: michael@0: // Parse handler used when processing the syntax in a block of code, to generate michael@0: // the minimal information which is required to detect syntax errors and allow michael@0: // bytecode to be emitted for outer functions. michael@0: // michael@0: // When parsing, we start at the top level with a full parse, and when possible michael@0: // only check the syntax for inner functions, so that they can be lazily parsed michael@0: // into bytecode when/if they first run. Checking the syntax of a function is michael@0: // several times faster than doing a full parse/emit, and lazy parsing improves michael@0: // both performance and memory usage significantly when pages contain large michael@0: // amounts of code that never executes (which happens often). michael@0: class SyntaxParseHandler michael@0: { michael@0: // Remember the last encountered name or string literal during syntax parses. michael@0: JSAtom *lastAtom; michael@0: TokenPos lastStringPos; michael@0: TokenStream &tokenStream; michael@0: michael@0: public: michael@0: enum Node { michael@0: NodeFailure = 0, michael@0: NodeGeneric, michael@0: NodeName, michael@0: NodeGetProp, michael@0: NodeString, michael@0: NodeStringExprStatement, michael@0: NodeLValue michael@0: }; michael@0: typedef Definition::Kind DefinitionNode; michael@0: michael@0: SyntaxParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, michael@0: TokenStream &tokenStream, bool foldConstants, michael@0: Parser *syntaxParser, LazyScript *lazyOuterFunction) michael@0: : lastAtom(nullptr), michael@0: tokenStream(tokenStream) michael@0: {} michael@0: michael@0: static Node null() { return NodeFailure; } michael@0: michael@0: void trace(JSTracer *trc) {} michael@0: michael@0: Node newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { michael@0: lastAtom = name; michael@0: return NodeName; michael@0: } michael@0: michael@0: DefinitionNode newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { michael@0: return Definition::PLACEHOLDER; michael@0: } michael@0: michael@0: Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; } michael@0: Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; } michael@0: Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; } michael@0: michael@0: Node newStringLiteral(JSAtom *atom, const TokenPos &pos) { michael@0: lastAtom = atom; michael@0: lastStringPos = pos; michael@0: return NodeString; michael@0: } michael@0: michael@0: Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; } michael@0: Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } michael@0: michael@0: template michael@0: Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; } michael@0: michael@0: Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } michael@0: michael@0: Node newElision() { return NodeGeneric; } michael@0: michael@0: Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; } michael@0: michael@0: Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; } michael@0: Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; } michael@0: Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) { michael@0: return NodeGeneric; michael@0: } michael@0: Node newBinaryOrAppend(ParseNodeKind kind, Node left, Node right, michael@0: ParseContext *pc, JSOp op = JSOP_NOP) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: // Expressions michael@0: michael@0: Node newArrayComprehension(Node body, unsigned blockid, const TokenPos &pos) { michael@0: return NodeGeneric; michael@0: } michael@0: Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeGeneric; } michael@0: bool addElision(Node literal, const TokenPos &pos) { return true; } michael@0: bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } michael@0: bool addArrayElement(Node literal, Node element) { return true; } michael@0: michael@0: Node newObjectLiteral(uint32_t begin) { return NodeGeneric; } michael@0: bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } michael@0: bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } michael@0: bool addShorthandPropertyDefinition(Node literal, Node name) { return true; } michael@0: bool addAccessorPropertyDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } michael@0: michael@0: // Statements michael@0: michael@0: Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; } michael@0: void addStatementToList(Node list, Node stmt, ParseContext *pc) {} michael@0: Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; } michael@0: michael@0: Node newExprStatement(Node expr, uint32_t end) { michael@0: return expr == NodeString ? NodeStringExprStatement : NodeGeneric; michael@0: } michael@0: michael@0: Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; } michael@0: Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; } michael@0: Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } michael@0: Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; } michael@0: Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } michael@0: Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } michael@0: Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } michael@0: Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } michael@0: michael@0: Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: Node newThrowStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } michael@0: Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) { michael@0: return NodeGeneric; michael@0: } michael@0: Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; } michael@0: michael@0: Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) { michael@0: lastAtom = name; michael@0: return NodeGetProp; michael@0: } michael@0: michael@0: Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; } michael@0: michael@0: bool addCatchBlock(Node catchList, Node letBlock, michael@0: Node catchName, Node catchGuard, Node catchBody) { return true; } michael@0: michael@0: void setLastFunctionArgumentDefault(Node funcpn, Node pn) {} michael@0: Node newFunctionDefinition() { return NodeGeneric; } michael@0: void setFunctionBody(Node pn, Node kid) {} michael@0: void setFunctionBox(Node pn, FunctionBox *funbox) {} michael@0: void addFunctionArgument(Node pn, Node argpn) {} michael@0: michael@0: Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos &pos) { michael@0: return NodeGeneric; michael@0: } michael@0: michael@0: Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; } michael@0: void setLexicalScopeBody(Node block, Node body) {} michael@0: michael@0: bool isOperationWithoutParens(Node pn, ParseNodeKind kind) { michael@0: // It is OK to return false here, callers should only use this method michael@0: // for reporting strict option warnings and parsing code which the michael@0: // syntax parser does not handle. michael@0: return false; michael@0: } michael@0: michael@0: bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } michael@0: michael@0: void setBeginPosition(Node pn, Node oth) {} michael@0: void setBeginPosition(Node pn, uint32_t begin) {} michael@0: michael@0: void setEndPosition(Node pn, Node oth) {} michael@0: void setEndPosition(Node pn, uint32_t end) {} michael@0: michael@0: michael@0: void setPosition(Node pn, const TokenPos &pos) {} michael@0: TokenPos getPosition(Node pn) { michael@0: return tokenStream.currentToken().pos; michael@0: } michael@0: michael@0: Node newList(ParseNodeKind kind, Node kid = NodeGeneric, JSOp op = JSOP_NOP) { michael@0: return NodeGeneric; michael@0: } michael@0: void addList(Node pn, Node kid) {} michael@0: bool isUnparenthesizedYield(Node pn) { return false; } michael@0: michael@0: void setOp(Node pn, JSOp op) {} michael@0: void setBlockId(Node pn, unsigned blockid) {} michael@0: void setFlag(Node pn, unsigned flag) {} michael@0: void setListFlag(Node pn, unsigned flag) {} michael@0: Node setInParens(Node pn) { michael@0: // String literals enclosed by parentheses are ignored during michael@0: // strict mode parsing. michael@0: return NodeGeneric; michael@0: } michael@0: void setPrologue(Node pn) {} michael@0: michael@0: bool isConstant(Node pn) { return false; } michael@0: PropertyName *isName(Node pn) { michael@0: return (pn == NodeName) ? lastAtom->asPropertyName() : nullptr; michael@0: } michael@0: PropertyName *isGetProp(Node pn) { michael@0: return (pn == NodeGetProp) ? lastAtom->asPropertyName() : nullptr; michael@0: } michael@0: JSAtom *isStringExprStatement(Node pn, TokenPos *pos) { michael@0: if (pn == NodeStringExprStatement) { michael@0: *pos = lastStringPos; michael@0: return lastAtom; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; } michael@0: michael@0: static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; } michael@0: static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; } michael@0: void linkUseToDef(Node pn, DefinitionNode dn) {} michael@0: DefinitionNode resolve(DefinitionNode dn) { return dn; } michael@0: void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {} michael@0: bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) { michael@0: // Only resolve lexical dependencies in cases where a definition covers michael@0: // the entire function. Not enough information is kept to compare the michael@0: // dependency location with blockid. michael@0: return functionScope; michael@0: } michael@0: michael@0: static uintptr_t definitionToBits(DefinitionNode dn) { michael@0: // Use a shift, as DefinitionList tags the lower bit of its associated union. michael@0: return uintptr_t(dn << 1); michael@0: } michael@0: static DefinitionNode definitionFromBits(uintptr_t bits) { michael@0: return (DefinitionNode) (bits >> 1); michael@0: } michael@0: static DefinitionNode nullDefinition() { michael@0: return Definition::MISSING; michael@0: } michael@0: void disableSyntaxParser() { michael@0: } michael@0: }; michael@0: michael@0: } // namespace frontend michael@0: } // namespace js michael@0: michael@0: #endif /* frontend_SyntaxParseHandler_h */