blob: 388ede9af3bfc98b65496410b96ca4dbdac116dd [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef frontend_SyntaxParseHandler_h
#define frontend_SyntaxParseHandler_h
namespace js {
namespace frontend {
// Parse handler used when processing the syntax in a block of code, to generate
// the minimal information which is required to detect syntax errors and allow
// bytecode to be emitted for outer functions.
//
// When parsing, we start at the top level with a full parse, and when possible
// only check the syntax for inner functions, so that they can be lazily parsed
// into bytecode when/if they first run. Checking the syntax of a function is
// several times faster than doing a full parse/emit, and lazy parsing improves
// both performance and memory usage significantly when pages contain large
// amounts of code that never executes (which happens often).
class SyntaxParseHandler
{
// Remember the last encountered name or string literal during syntax parses.
JSAtom *lastAtom;
TokenPos lastStringPos;
TokenStream &tokenStream;
public:
enum Node {
NodeFailure = 0,
NodeGeneric,
NodeName,
NodeGetProp,
NodeString,
NodeStringExprStatement,
NodeLValue
};
typedef Definition::Kind DefinitionNode;
SyntaxParseHandler(JSContext *cx, TokenStream &tokenStream, bool foldConstants,
Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
: lastAtom(NULL),
tokenStream(tokenStream)
{}
static Node null() { return NodeFailure; }
void trace(JSTracer *trc) {}
Node newName(PropertyName *name, InBlockBool inBlock, uint32_t blockid, const TokenPos &pos) {
lastAtom = name;
return NodeName;
}
DefinitionNode newPlaceholder(JSAtom *atom, InBlockBool inBlock, uint32_t blockid,
const TokenPos &pos)
{
return Definition::PLACEHOLDER;
}
Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; }
Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; }
Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; }
Node newStringLiteral(JSAtom *atom, const TokenPos &pos) {
lastAtom = atom;
lastStringPos = pos;
return NodeString;
}
Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; }
Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; }
template <class Boxer>
Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; }
Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; }
Node newElision() { return NodeGeneric; }
Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; }
Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
return NodeGeneric;
}
Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; }
Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; }
Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newBinaryOrAppend(ParseNodeKind kind, Node left, Node right,
ParseContext<SyntaxParseHandler> *pc, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {}
Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
Node newExprStatement(Node expr, uint32_t end) {
return expr == NodeString ? NodeStringExprStatement : NodeGeneric;
}
Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; }
Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; }
Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; }
Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) {
return NodeGeneric;
}
Node newThrowStatement(Node expr, const TokenPos &pos) { return NodeGeneric; }
Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) {
return NodeGeneric;
}
Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; }
Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) {
lastAtom = name;
return NodeGetProp;
}
Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; }
bool addCatchBlock(Node catchList, Node letBlock,
Node catchName, Node catchGuard, Node catchBody) { return true; }
void setLeaveBlockResult(Node block, Node kid, bool leaveBlockExpr) {}
void setLastFunctionArgumentDefault(Node funcpn, Node pn) {}
Node newFunctionDefinition() { return NodeGeneric; }
void setFunctionBody(Node pn, Node kid) {}
void setFunctionBox(Node pn, FunctionBox *funbox) {}
void addFunctionArgument(Node pn, Node argpn) {}
Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; }
bool isOperationWithoutParens(Node pn, ParseNodeKind kind) {
// It is OK to return false here, callers should only use this method
// for reporting strict option warnings and parsing code which the
// syntax parser does not handle.
return false;
}
bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
void setBeginPosition(Node pn, Node oth) {}
void setBeginPosition(Node pn, uint32_t begin) {}
void setEndPosition(Node pn, Node oth) {}
void setEndPosition(Node pn, uint32_t end) {}
void setPosition(Node pn, const TokenPos &pos) {}
TokenPos getPosition(Node pn) {
return tokenStream.currentToken().pos;
}
Node newList(ParseNodeKind kind, Node kid = NodeGeneric, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
void addList(Node pn, Node kid) {}
void setOp(Node pn, JSOp op) {}
void setBlockId(Node pn, unsigned blockid) {}
void setFlag(Node pn, unsigned flag) {}
void setListFlag(Node pn, unsigned flag) {}
Node setInParens(Node pn) {
// String literals enclosed by parentheses are ignored during
// strict mode parsing.
return NodeGeneric;
}
void setPrologue(Node pn) {}
bool isConstant(Node pn) { return false; }
PropertyName *isName(Node pn) {
return (pn == NodeName) ? lastAtom->asPropertyName() : NULL;
}
PropertyName *isGetProp(Node pn) {
return (pn == NodeGetProp) ? lastAtom->asPropertyName() : NULL;
}
JSAtom *isStringExprStatement(Node pn, TokenPos *pos) {
if (pn == NodeStringExprStatement) {
*pos = lastStringPos;
return lastAtom;
}
return NULL;
}
Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; }
static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; }
static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; }
void linkUseToDef(Node pn, DefinitionNode dn) {}
DefinitionNode resolve(DefinitionNode dn) { return dn; }
void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {}
bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) {
// Only resolve lexical dependencies in cases where a definition covers
// the entire function. Not enough information is kept to compare the
// dependency location with blockid.
return functionScope;
}
static uintptr_t definitionToBits(DefinitionNode dn) {
// Use a shift, as DefinitionList tags the lower bit of its associated union.
return uintptr_t(dn << 1);
}
static DefinitionNode definitionFromBits(uintptr_t bits) {
return (DefinitionNode) (bits >> 1);
}
static DefinitionNode nullDefinition() {
return Definition::MISSING;
}
void disableSyntaxParser() {
}
};
} // namespace frontend
} // namespace js
#endif /* frontend_SyntaxParseHandler_h */