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_Parser_h michael@0: #define frontend_Parser_h michael@0: michael@0: /* michael@0: * JS parser definitions. michael@0: */ michael@0: michael@0: #include "jspubtd.h" michael@0: michael@0: #include "frontend/BytecodeCompiler.h" michael@0: #include "frontend/FullParseHandler.h" michael@0: #include "frontend/ParseMaps.h" michael@0: #include "frontend/ParseNode.h" michael@0: #include "frontend/SharedContext.h" michael@0: #include "frontend/SyntaxParseHandler.h" michael@0: michael@0: namespace js { michael@0: namespace frontend { michael@0: michael@0: struct StmtInfoPC : public StmtInfoBase { michael@0: StmtInfoPC *down; /* info for enclosing statement */ michael@0: StmtInfoPC *downScope; /* next enclosing lexical scope */ michael@0: michael@0: uint32_t blockid; /* for simplified dominance computation */ michael@0: uint32_t innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */ michael@0: michael@0: StmtInfoPC(ExclusiveContext *cx) : StmtInfoBase(cx), innerBlockScopeDepth(0) {} michael@0: }; michael@0: michael@0: typedef HashSet FuncStmtSet; michael@0: class SharedContext; michael@0: michael@0: typedef Vector DeclVector; michael@0: michael@0: struct GenericParseContext michael@0: { michael@0: // Enclosing function or global context. michael@0: GenericParseContext *parent; michael@0: michael@0: // Context shared between parsing and bytecode generation. michael@0: SharedContext *sc; michael@0: michael@0: // The following flags are set when a particular code feature is detected michael@0: // in a function. michael@0: michael@0: // Function has 'return ;' michael@0: bool funHasReturnExpr:1; michael@0: michael@0: // Function has 'return;' michael@0: bool funHasReturnVoid:1; michael@0: michael@0: // The following flags are set when parsing enters a particular region of michael@0: // source code, and cleared when that region is exited. michael@0: michael@0: // true while parsing init expr of for; exclude 'in' michael@0: bool parsingForInit:1; michael@0: michael@0: // true while we are within a with-statement in the current ParseContext michael@0: // chain (which stops at the top-level or an eval() michael@0: bool parsingWith:1; michael@0: michael@0: GenericParseContext(GenericParseContext *parent, SharedContext *sc) michael@0: : parent(parent), michael@0: sc(sc), michael@0: funHasReturnExpr(false), michael@0: funHasReturnVoid(false), michael@0: parsingForInit(false), michael@0: parsingWith(parent ? parent->parsingWith : false) michael@0: {} michael@0: }; michael@0: michael@0: template michael@0: bool michael@0: GenerateBlockId(TokenStream &ts, ParseContext *pc, uint32_t &blockid); michael@0: michael@0: /* michael@0: * The struct ParseContext stores information about the current parsing context, michael@0: * which is part of the parser state (see the field Parser::pc). The current michael@0: * parsing context is either the global context, or the function currently being michael@0: * parsed. When the parser encounters a function definition, it creates a new michael@0: * ParseContext, makes it the new current context, and sets its parent to the michael@0: * context in which it encountered the definition. michael@0: */ michael@0: template michael@0: struct ParseContext : public GenericParseContext michael@0: { michael@0: typedef StmtInfoPC StmtInfo; michael@0: typedef typename ParseHandler::Node Node; michael@0: typedef typename ParseHandler::DefinitionNode DefinitionNode; michael@0: michael@0: uint32_t bodyid; /* block number of program/function body */ michael@0: uint32_t blockidGen; /* preincremented block number generator */ michael@0: michael@0: StmtInfoPC *topStmt; /* top of statement info stack */ michael@0: StmtInfoPC *topScopeStmt; /* top lexical scope statement */ michael@0: Rooted staticScope; /* compile time scope chain */ michael@0: Node maybeFunction; /* sc->isFunctionBox, the pn where pn->pn_funbox == sc */ michael@0: michael@0: const unsigned staticLevel; /* static compilation unit nesting level */ michael@0: michael@0: // lastYieldOffset stores the offset of the last yield that was parsed. michael@0: // NoYieldOffset is its initial value. michael@0: static const uint32_t NoYieldOffset = UINT32_MAX; michael@0: uint32_t lastYieldOffset; michael@0: michael@0: // Most functions start off being parsed as non-generators. michael@0: // Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7. michael@0: // An ES6 generator is marked as a "star generator" before its body is parsed. michael@0: GeneratorKind generatorKind() const { michael@0: return sc->isFunctionBox() ? sc->asFunctionBox()->generatorKind() : NotGenerator; michael@0: } michael@0: bool isGenerator() const { return generatorKind() != NotGenerator; } michael@0: bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } michael@0: bool isStarGenerator() const { return generatorKind() == StarGenerator; } michael@0: michael@0: bool isArrowFunction() const { michael@0: return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow(); michael@0: } michael@0: michael@0: uint32_t blockScopeDepth; /* maximum depth of nested block scopes, in slots */ michael@0: Node blockNode; /* parse node for a block with let declarations michael@0: (block with its own lexical scope) */ michael@0: private: michael@0: AtomDecls decls_; /* function, const, and var declarations */ michael@0: DeclVector args_; /* argument definitions */ michael@0: DeclVector vars_; /* var/const definitions */ michael@0: michael@0: public: michael@0: const AtomDecls &decls() const { michael@0: return decls_; michael@0: } michael@0: michael@0: uint32_t numArgs() const { michael@0: JS_ASSERT(sc->isFunctionBox()); michael@0: return args_.length(); michael@0: } michael@0: michael@0: /* michael@0: * This function adds a definition to the lexical scope represented by this michael@0: * ParseContext. michael@0: * michael@0: * Pre-conditions: michael@0: * + The caller must have already taken care of name collisions: michael@0: * - For non-let definitions, this means 'name' isn't in 'decls'. michael@0: * - For let definitions, this means 'name' isn't already a name in the michael@0: * current block. michael@0: * + The given 'pn' is either a placeholder (created by a previous unbound michael@0: * use) or an un-bound un-linked name node. michael@0: * + The given 'kind' is one of ARG, CONST, VAR, or LET. In particular, michael@0: * NAMED_LAMBDA is handled in an ad hoc special case manner (see michael@0: * LeaveFunction) that we should consider rewriting. michael@0: * michael@0: * Post-conditions: michael@0: * + pc->decls().lookupFirst(name) == pn michael@0: * + The given name 'pn' has been converted in-place into a michael@0: * non-placeholder definition. michael@0: * + If this is a function scope (sc->inFunction), 'pn' is bound to a michael@0: * particular local/argument slot. michael@0: * + PND_CONST is set for Definition::COSNT michael@0: * + Pre-existing uses of pre-existing placeholders have been linked to michael@0: * 'pn' if they are in the scope of 'pn'. michael@0: * + Pre-existing placeholders in the scope of 'pn' have been removed. michael@0: */ michael@0: bool define(TokenStream &ts, HandlePropertyName name, Node pn, Definition::Kind); michael@0: michael@0: /* michael@0: * Let definitions may shadow same-named definitions in enclosing scopes. michael@0: * To represesent this, 'decls' is not a plain map, but actually: michael@0: * decls :: name -> stack of definitions michael@0: * New bindings are pushed onto the stack, name lookup always refers to the michael@0: * top of the stack, and leaving a block scope calls popLetDecl for each michael@0: * name in the block's scope. michael@0: */ michael@0: void popLetDecl(JSAtom *atom); michael@0: michael@0: /* See the sad story in defineArg. */ michael@0: void prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl); michael@0: michael@0: /* See the sad story in MakeDefIntoUse. */ michael@0: void updateDecl(JSAtom *atom, Node newDecl); michael@0: michael@0: /* michael@0: * After a function body has been parsed, the parser generates the michael@0: * function's "bindings". Bindings are a data-structure, ultimately stored michael@0: * in the compiled JSScript, that serve three purposes: michael@0: * - After parsing, the ParseContext is destroyed and 'decls' along with michael@0: * it. Mostly, the emitter just uses the binding information stored in michael@0: * the use/def nodes, but the emitter occasionally needs 'bindings' for michael@0: * various scope-related queries. michael@0: * - Bindings provide the initial js::Shape to use when creating a dynamic michael@0: * scope object (js::CallObject) for the function. This shape is used michael@0: * during dynamic name lookup. michael@0: * - Sometimes a script's bindings are accessed at runtime to retrieve the michael@0: * contents of the lexical scope (e.g., from the debugger). michael@0: */ michael@0: bool generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts, michael@0: LifoAlloc &alloc, michael@0: InternalHandle bindings) const; michael@0: michael@0: private: michael@0: ParseContext **parserPC; /* this points to the Parser's active pc michael@0: and holds either |this| or one of michael@0: |this|'s descendents */ michael@0: michael@0: // Value for parserPC to restore at the end. Use 'parent' instead for michael@0: // information about the parse chain, this may be nullptr if michael@0: // parent != nullptr. michael@0: ParseContext *oldpc; michael@0: michael@0: public: michael@0: OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */ michael@0: michael@0: FuncStmtSet *funcStmts; /* Set of (non-top-level) function statements michael@0: that will alias any top-level bindings with michael@0: the same name. */ michael@0: michael@0: // All inner functions in this context. Only filled in when parsing syntax. michael@0: AutoFunctionVector innerFunctions; michael@0: michael@0: // In a function context, points to a Directive struct that can be updated michael@0: // to reflect new directives encountered in the Directive Prologue that michael@0: // require reparsing the function. In global/module/generator-tail contexts, michael@0: // we don't need to reparse when encountering a DirectivePrologue so this michael@0: // pointer may be nullptr. michael@0: Directives *newDirectives; michael@0: michael@0: // Set when parsing a declaration-like destructuring pattern. This flag michael@0: // causes PrimaryExpr to create PN_NAME parse nodes for variable references michael@0: // which are not hooked into any definition's use chain, added to any tree michael@0: // context's AtomList, etc. etc. CheckDestructuring will do that work michael@0: // later. michael@0: // michael@0: // The comments atop CheckDestructuring explain the distinction between michael@0: // assignment-like and declaration-like destructuring patterns, and why michael@0: // they need to be treated differently. michael@0: bool inDeclDestructuring:1; michael@0: michael@0: ParseContext(Parser *prs, GenericParseContext *parent, michael@0: Node maybeFunction, SharedContext *sc, michael@0: Directives *newDirectives, michael@0: unsigned staticLevel, uint32_t bodyid, uint32_t blockScopeDepth) michael@0: : GenericParseContext(parent, sc), michael@0: bodyid(0), // initialized in init() michael@0: blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init() michael@0: topStmt(nullptr), michael@0: topScopeStmt(nullptr), michael@0: staticScope(prs->context), michael@0: maybeFunction(maybeFunction), michael@0: staticLevel(staticLevel), michael@0: lastYieldOffset(NoYieldOffset), michael@0: blockScopeDepth(blockScopeDepth), michael@0: blockNode(ParseHandler::null()), michael@0: decls_(prs->context, prs->alloc), michael@0: args_(prs->context), michael@0: vars_(prs->context), michael@0: parserPC(&prs->pc), michael@0: oldpc(prs->pc), michael@0: lexdeps(prs->context), michael@0: funcStmts(nullptr), michael@0: innerFunctions(prs->context), michael@0: newDirectives(newDirectives), michael@0: inDeclDestructuring(false) michael@0: { michael@0: prs->pc = this; michael@0: } michael@0: michael@0: ~ParseContext(); michael@0: michael@0: bool init(TokenStream &ts); michael@0: michael@0: unsigned blockid() { return topStmt ? topStmt->blockid : bodyid; } michael@0: michael@0: // True if we are at the topmost level of a entire script or function body. michael@0: // For example, while parsing this code we would encounter f1 and f2 at michael@0: // body level, but we would not encounter f3 or f4 at body level: michael@0: // michael@0: // function f1() { function f2() { } } michael@0: // if (cond) { function f3() { if (cond) { function f4() { } } } } michael@0: // michael@0: bool atBodyLevel() { return !topStmt; } michael@0: michael@0: // True if this is the ParseContext for the body of a function created by michael@0: // the Function constructor. michael@0: bool isFunctionConstructorBody() const { michael@0: return sc->isFunctionBox() && staticLevel == 0; michael@0: } michael@0: michael@0: inline bool useAsmOrInsideUseAsm() const { michael@0: return sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm(); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: Directives::Directives(ParseContext *parent) michael@0: : strict_(parent->sc->strict), michael@0: asmJS_(parent->useAsmOrInsideUseAsm()) michael@0: {} michael@0: michael@0: template michael@0: struct BindData; michael@0: michael@0: class CompExprTransplanter; michael@0: michael@0: enum LetContext { LetExpresion, LetStatement }; michael@0: enum VarContext { HoistVars, DontHoistVars }; michael@0: enum FunctionType { Getter, Setter, Normal }; michael@0: michael@0: template michael@0: class Parser : private AutoGCRooter, public StrictModeGetter michael@0: { michael@0: public: michael@0: ExclusiveContext *const context; michael@0: LifoAlloc &alloc; michael@0: michael@0: TokenStream tokenStream; michael@0: LifoAlloc::Mark tempPoolMark; michael@0: michael@0: /* list of parsed objects for GC tracing */ michael@0: ObjectBox *traceListHead; michael@0: michael@0: /* innermost parse context (stack-allocated) */ michael@0: ParseContext *pc; michael@0: michael@0: /* Compression token for aborting. */ michael@0: SourceCompressionTask *sct; michael@0: michael@0: ScriptSource *ss; michael@0: michael@0: /* Root atoms and objects allocated for the parsed tree. */ michael@0: AutoKeepAtoms keepAtoms; michael@0: michael@0: /* Perform constant-folding; must be true when interfacing with the emitter. */ michael@0: const bool foldConstants:1; michael@0: michael@0: private: michael@0: /* michael@0: * Not all language constructs can be handled during syntax parsing. If it michael@0: * is not known whether the parse succeeds or fails, this bit is set and michael@0: * the parse will return false. michael@0: */ michael@0: bool abortedSyntaxParse:1; michael@0: michael@0: /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ michael@0: bool isUnexpectedEOF_:1; michael@0: michael@0: typedef typename ParseHandler::Node Node; michael@0: typedef typename ParseHandler::DefinitionNode DefinitionNode; michael@0: michael@0: public: michael@0: /* State specific to the kind of parse being performed. */ michael@0: ParseHandler handler; michael@0: michael@0: private: michael@0: bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset, michael@0: unsigned errorNumber, va_list args); michael@0: public: michael@0: bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...); michael@0: bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); michael@0: bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber, michael@0: ...); michael@0: michael@0: Parser(ExclusiveContext *cx, LifoAlloc *alloc, const ReadOnlyCompileOptions &options, michael@0: const jschar *chars, size_t length, bool foldConstants, michael@0: Parser *syntaxParser, michael@0: LazyScript *lazyOuterFunction); michael@0: ~Parser(); michael@0: michael@0: // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire michael@0: // Parser's state. Note: clients must still take care that any ParseContext michael@0: // that points into released ParseNodes is destroyed. michael@0: class Mark michael@0: { michael@0: friend class Parser; michael@0: LifoAlloc::Mark mark; michael@0: ObjectBox *traceListHead; michael@0: }; michael@0: Mark mark() const { michael@0: Mark m; michael@0: m.mark = alloc.mark(); michael@0: m.traceListHead = traceListHead; michael@0: return m; michael@0: } michael@0: void release(Mark m) { michael@0: alloc.release(m.mark); michael@0: traceListHead = m.traceListHead; michael@0: } michael@0: michael@0: friend void js::frontend::MarkParser(JSTracer *trc, AutoGCRooter *parser); michael@0: michael@0: const char *getFilename() const { return tokenStream.getFilename(); } michael@0: JSVersion versionNumber() const { return tokenStream.versionNumber(); } michael@0: michael@0: /* michael@0: * Parse a top-level JS script. michael@0: */ michael@0: Node parse(JSObject *chain); michael@0: michael@0: /* michael@0: * Allocate a new parsed object or function container from michael@0: * cx->tempLifoAlloc. michael@0: */ michael@0: ObjectBox *newObjectBox(JSObject *obj); michael@0: FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext *pc, michael@0: Directives directives, GeneratorKind generatorKind); michael@0: michael@0: /* michael@0: * Create a new function object given parse context (pc) and a name (which michael@0: * is optional if this is a function expression). michael@0: */ michael@0: JSFunction *newFunction(GenericParseContext *pc, HandleAtom atom, FunctionSyntaxKind kind, michael@0: JSObject *proto = nullptr); michael@0: michael@0: void trace(JSTracer *trc); michael@0: michael@0: bool hadAbortedSyntaxParse() { michael@0: return abortedSyntaxParse; michael@0: } michael@0: void clearAbortedSyntaxParse() { michael@0: abortedSyntaxParse = false; michael@0: } michael@0: michael@0: bool isUnexpectedEOF() const { return isUnexpectedEOF_; } michael@0: michael@0: private: michael@0: Parser *thisForCtor() { return this; } michael@0: michael@0: Node stringLiteral(); michael@0: inline Node newName(PropertyName *name); michael@0: michael@0: inline bool abortIfSyntaxParser(); michael@0: michael@0: public: michael@0: michael@0: /* Public entry points for parsing. */ michael@0: Node statement(bool canHaveDirectives = false); michael@0: bool maybeParseDirective(Node list, Node pn, bool *cont); michael@0: michael@0: // Parse a function, given only its body. Used for the Function and michael@0: // Generator constructors. michael@0: Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals, michael@0: GeneratorKind generatorKind, michael@0: Directives inheritedDirectives, Directives *newDirectives); michael@0: michael@0: // Parse a function, given only its arguments and body. Used for lazily michael@0: // parsed functions. michael@0: Node standaloneLazyFunction(HandleFunction fun, unsigned staticLevel, bool strict, michael@0: GeneratorKind generatorKind); michael@0: michael@0: /* michael@0: * Parse a function body. Pass StatementListBody if the body is a list of michael@0: * statements; pass ExpressionBody if the body is a single expression. michael@0: */ michael@0: enum FunctionBodyType { StatementListBody, ExpressionBody }; michael@0: Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type); michael@0: michael@0: bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type, michael@0: FunctionSyntaxKind kind, Directives *newDirectives); michael@0: michael@0: // Determine whether |yield| is a valid name in the current context, or michael@0: // whether it's prohibited due to strictness, JS version, or occurrence michael@0: // inside a star generator. michael@0: bool checkYieldNameValidity(); michael@0: michael@0: virtual bool strictMode() { return pc->sc->strict; } michael@0: michael@0: const ReadOnlyCompileOptions &options() const { michael@0: return tokenStream.options(); michael@0: } michael@0: michael@0: private: michael@0: /* michael@0: * JS parsers, from lowest to highest precedence. michael@0: * michael@0: * Each parser must be called during the dynamic scope of a ParseContext michael@0: * object, pointed to by this->pc. michael@0: * michael@0: * Each returns a parse node tree or null on error. michael@0: * michael@0: * Parsers whose name has a '1' suffix leave the TokenStream state michael@0: * pointing to the token one past the end of the parsed fragment. For a michael@0: * number of the parsers this is convenient and avoids a lot of michael@0: * unnecessary ungetting and regetting of tokens. michael@0: * michael@0: * Some parsers have two versions: an always-inlined version (with an 'i' michael@0: * suffix) and a never-inlined version (with an 'n' suffix). michael@0: */ michael@0: Node functionStmt(); michael@0: Node functionExpr(); michael@0: Node statements(); michael@0: michael@0: Node blockStatement(); michael@0: Node ifStatement(); michael@0: Node doWhileStatement(); michael@0: Node whileStatement(); michael@0: Node forStatement(); michael@0: Node switchStatement(); michael@0: Node continueStatement(); michael@0: Node breakStatement(); michael@0: Node returnStatement(); michael@0: Node withStatement(); michael@0: Node labeledStatement(); michael@0: Node throwStatement(); michael@0: Node tryStatement(); michael@0: Node debuggerStatement(); michael@0: michael@0: Node letDeclaration(); michael@0: Node letStatement(); michael@0: Node importDeclaration(); michael@0: Node exportDeclaration(); michael@0: Node expressionStatement(); michael@0: Node variables(ParseNodeKind kind, bool *psimple = nullptr, michael@0: StaticBlockObject *blockObj = nullptr, michael@0: VarContext varContext = HoistVars); michael@0: Node expr(); michael@0: Node assignExpr(); michael@0: Node assignExprWithoutYield(unsigned err); michael@0: Node yieldExpression(); michael@0: Node condExpr1(); michael@0: Node orExpr1(); michael@0: Node unaryExpr(); michael@0: Node memberExpr(TokenKind tt, bool allowCallSyntax); michael@0: Node primaryExpr(TokenKind tt); michael@0: Node parenExprOrGeneratorComprehension(); michael@0: Node exprInParens(); michael@0: michael@0: /* michael@0: * Additional JS parsers. michael@0: */ michael@0: bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool *hasRest); michael@0: michael@0: Node functionDef(HandlePropertyName name, const TokenStream::Position &start, michael@0: FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind); michael@0: bool functionArgsAndBody(Node pn, HandleFunction fun, michael@0: FunctionType type, FunctionSyntaxKind kind, michael@0: GeneratorKind generatorKind, michael@0: Directives inheritedDirectives, Directives *newDirectives); michael@0: michael@0: Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin); michael@0: michael@0: Node condition(); michael@0: michael@0: Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin, michael@0: Node innerStmt); michael@0: michael@0: Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind, michael@0: ParseContext *outerpc, michael@0: unsigned innerBlockScopeDepth); michael@0: Node legacyArrayComprehension(Node array); michael@0: Node legacyGeneratorExpr(Node kid); michael@0: michael@0: Node comprehensionTail(GeneratorKind comprehensionKind); michael@0: Node comprehensionIf(GeneratorKind comprehensionKind); michael@0: Node comprehensionFor(GeneratorKind comprehensionKind); michael@0: Node comprehension(GeneratorKind comprehensionKind); michael@0: Node arrayComprehension(uint32_t begin); michael@0: Node generatorComprehension(uint32_t begin); michael@0: michael@0: bool argumentList(Node listNode, bool *isSpread); michael@0: Node letBlock(LetContext letContext); michael@0: Node destructuringExpr(BindData *data, TokenKind tt); michael@0: michael@0: Node identifierName(); michael@0: michael@0: bool matchLabel(MutableHandle label); michael@0: michael@0: bool allowsForEachIn() { michael@0: #if !JS_HAS_FOR_EACH_IN michael@0: return false; michael@0: #else michael@0: return versionNumber() >= JSVERSION_1_6; michael@0: #endif michael@0: } michael@0: michael@0: enum AssignmentFlavor { michael@0: PlainAssignment, michael@0: CompoundAssignment, michael@0: KeyedDestructuringAssignment, michael@0: IncDecAssignment michael@0: }; michael@0: michael@0: bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor); michael@0: bool matchInOrOf(bool *isForOfp); michael@0: michael@0: bool checkFunctionArguments(); michael@0: bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom); michael@0: bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind, michael@0: bool *pbodyProcessed); michael@0: bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body); michael@0: bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext *pc); michael@0: michael@0: bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach, michael@0: ParseNodeKind headKind); michael@0: bool checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder); michael@0: bool checkStrictAssignment(Node lhs, AssignmentFlavor flavor); michael@0: bool checkStrictBinding(PropertyName *name, Node pn); michael@0: bool defineArg(Node funcpn, HandlePropertyName name, michael@0: bool disallowDuplicateArgs = false, Node *duplicatedArg = nullptr); michael@0: Node pushLexicalScope(StmtInfoPC *stmt); michael@0: Node pushLexicalScope(Handle blockObj, StmtInfoPC *stmt); michael@0: Node pushLetScope(Handle blockObj, StmtInfoPC *stmt); michael@0: bool noteNameUse(HandlePropertyName name, Node pn); michael@0: Node objectLiteral(); michael@0: Node arrayInitializer(); michael@0: Node newRegExp(); michael@0: michael@0: Node newBindingNode(PropertyName *name, bool functionScope, VarContext varContext = HoistVars); michael@0: bool checkDestructuring(BindData *data, Node left, bool toplevel = true); michael@0: bool bindDestructuringVar(BindData *data, Node pn); michael@0: bool bindDestructuringLHS(Node pn); michael@0: bool makeSetCall(Node pn, unsigned msg); michael@0: Node cloneLeftHandSide(Node opn); michael@0: Node cloneParseTree(Node opn); michael@0: michael@0: Node newNumber(const Token &tok) { michael@0: return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); michael@0: } michael@0: michael@0: static bool michael@0: bindDestructuringArg(BindData *data, michael@0: HandlePropertyName name, Parser *parser); michael@0: michael@0: static bool michael@0: bindLet(BindData *data, michael@0: HandlePropertyName name, Parser *parser); michael@0: michael@0: static bool michael@0: bindVarOrConst(BindData *data, michael@0: HandlePropertyName name, Parser *parser); michael@0: michael@0: static Node null() { return ParseHandler::null(); } michael@0: michael@0: bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom); michael@0: bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum); michael@0: bool checkFinalReturn(Node pn); michael@0: DefinitionNode getOrCreateLexicalDependency(ParseContext *pc, JSAtom *atom); michael@0: michael@0: bool leaveFunction(Node fn, ParseContext *outerpc, michael@0: FunctionSyntaxKind kind = Expression); michael@0: michael@0: TokenPos pos() const { return tokenStream.currentToken().pos; } michael@0: michael@0: bool asmJS(Node list); michael@0: michael@0: friend class LegacyCompExprTransplanter; michael@0: friend struct BindData; michael@0: }; michael@0: michael@0: /* Declare some required template specializations. */ michael@0: michael@0: template <> michael@0: bool michael@0: Parser::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentFlavor flavor); michael@0: michael@0: template <> michael@0: bool michael@0: Parser::checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor); michael@0: michael@0: } /* namespace frontend */ michael@0: } /* namespace js */ michael@0: michael@0: /* michael@0: * Convenience macro to access Parser.tokenStream as a pointer. michael@0: */ michael@0: #define TS(p) (&(p)->tokenStream) michael@0: michael@0: #endif /* frontend_Parser_h */