js/src/frontend/Parser.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_Parser_h
michael@0 8 #define frontend_Parser_h
michael@0 9
michael@0 10 /*
michael@0 11 * JS parser definitions.
michael@0 12 */
michael@0 13
michael@0 14 #include "jspubtd.h"
michael@0 15
michael@0 16 #include "frontend/BytecodeCompiler.h"
michael@0 17 #include "frontend/FullParseHandler.h"
michael@0 18 #include "frontend/ParseMaps.h"
michael@0 19 #include "frontend/ParseNode.h"
michael@0 20 #include "frontend/SharedContext.h"
michael@0 21 #include "frontend/SyntaxParseHandler.h"
michael@0 22
michael@0 23 namespace js {
michael@0 24 namespace frontend {
michael@0 25
michael@0 26 struct StmtInfoPC : public StmtInfoBase {
michael@0 27 StmtInfoPC *down; /* info for enclosing statement */
michael@0 28 StmtInfoPC *downScope; /* next enclosing lexical scope */
michael@0 29
michael@0 30 uint32_t blockid; /* for simplified dominance computation */
michael@0 31 uint32_t innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */
michael@0 32
michael@0 33 StmtInfoPC(ExclusiveContext *cx) : StmtInfoBase(cx), innerBlockScopeDepth(0) {}
michael@0 34 };
michael@0 35
michael@0 36 typedef HashSet<JSAtom *> FuncStmtSet;
michael@0 37 class SharedContext;
michael@0 38
michael@0 39 typedef Vector<Definition *, 16> DeclVector;
michael@0 40
michael@0 41 struct GenericParseContext
michael@0 42 {
michael@0 43 // Enclosing function or global context.
michael@0 44 GenericParseContext *parent;
michael@0 45
michael@0 46 // Context shared between parsing and bytecode generation.
michael@0 47 SharedContext *sc;
michael@0 48
michael@0 49 // The following flags are set when a particular code feature is detected
michael@0 50 // in a function.
michael@0 51
michael@0 52 // Function has 'return <expr>;'
michael@0 53 bool funHasReturnExpr:1;
michael@0 54
michael@0 55 // Function has 'return;'
michael@0 56 bool funHasReturnVoid:1;
michael@0 57
michael@0 58 // The following flags are set when parsing enters a particular region of
michael@0 59 // source code, and cleared when that region is exited.
michael@0 60
michael@0 61 // true while parsing init expr of for; exclude 'in'
michael@0 62 bool parsingForInit:1;
michael@0 63
michael@0 64 // true while we are within a with-statement in the current ParseContext
michael@0 65 // chain (which stops at the top-level or an eval()
michael@0 66 bool parsingWith:1;
michael@0 67
michael@0 68 GenericParseContext(GenericParseContext *parent, SharedContext *sc)
michael@0 69 : parent(parent),
michael@0 70 sc(sc),
michael@0 71 funHasReturnExpr(false),
michael@0 72 funHasReturnVoid(false),
michael@0 73 parsingForInit(false),
michael@0 74 parsingWith(parent ? parent->parsingWith : false)
michael@0 75 {}
michael@0 76 };
michael@0 77
michael@0 78 template <typename ParseHandler>
michael@0 79 bool
michael@0 80 GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid);
michael@0 81
michael@0 82 /*
michael@0 83 * The struct ParseContext stores information about the current parsing context,
michael@0 84 * which is part of the parser state (see the field Parser::pc). The current
michael@0 85 * parsing context is either the global context, or the function currently being
michael@0 86 * parsed. When the parser encounters a function definition, it creates a new
michael@0 87 * ParseContext, makes it the new current context, and sets its parent to the
michael@0 88 * context in which it encountered the definition.
michael@0 89 */
michael@0 90 template <typename ParseHandler>
michael@0 91 struct ParseContext : public GenericParseContext
michael@0 92 {
michael@0 93 typedef StmtInfoPC StmtInfo;
michael@0 94 typedef typename ParseHandler::Node Node;
michael@0 95 typedef typename ParseHandler::DefinitionNode DefinitionNode;
michael@0 96
michael@0 97 uint32_t bodyid; /* block number of program/function body */
michael@0 98 uint32_t blockidGen; /* preincremented block number generator */
michael@0 99
michael@0 100 StmtInfoPC *topStmt; /* top of statement info stack */
michael@0 101 StmtInfoPC *topScopeStmt; /* top lexical scope statement */
michael@0 102 Rooted<NestedScopeObject *> staticScope; /* compile time scope chain */
michael@0 103 Node maybeFunction; /* sc->isFunctionBox, the pn where pn->pn_funbox == sc */
michael@0 104
michael@0 105 const unsigned staticLevel; /* static compilation unit nesting level */
michael@0 106
michael@0 107 // lastYieldOffset stores the offset of the last yield that was parsed.
michael@0 108 // NoYieldOffset is its initial value.
michael@0 109 static const uint32_t NoYieldOffset = UINT32_MAX;
michael@0 110 uint32_t lastYieldOffset;
michael@0 111
michael@0 112 // Most functions start off being parsed as non-generators.
michael@0 113 // Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7.
michael@0 114 // An ES6 generator is marked as a "star generator" before its body is parsed.
michael@0 115 GeneratorKind generatorKind() const {
michael@0 116 return sc->isFunctionBox() ? sc->asFunctionBox()->generatorKind() : NotGenerator;
michael@0 117 }
michael@0 118 bool isGenerator() const { return generatorKind() != NotGenerator; }
michael@0 119 bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
michael@0 120 bool isStarGenerator() const { return generatorKind() == StarGenerator; }
michael@0 121
michael@0 122 bool isArrowFunction() const {
michael@0 123 return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow();
michael@0 124 }
michael@0 125
michael@0 126 uint32_t blockScopeDepth; /* maximum depth of nested block scopes, in slots */
michael@0 127 Node blockNode; /* parse node for a block with let declarations
michael@0 128 (block with its own lexical scope) */
michael@0 129 private:
michael@0 130 AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
michael@0 131 DeclVector args_; /* argument definitions */
michael@0 132 DeclVector vars_; /* var/const definitions */
michael@0 133
michael@0 134 public:
michael@0 135 const AtomDecls<ParseHandler> &decls() const {
michael@0 136 return decls_;
michael@0 137 }
michael@0 138
michael@0 139 uint32_t numArgs() const {
michael@0 140 JS_ASSERT(sc->isFunctionBox());
michael@0 141 return args_.length();
michael@0 142 }
michael@0 143
michael@0 144 /*
michael@0 145 * This function adds a definition to the lexical scope represented by this
michael@0 146 * ParseContext.
michael@0 147 *
michael@0 148 * Pre-conditions:
michael@0 149 * + The caller must have already taken care of name collisions:
michael@0 150 * - For non-let definitions, this means 'name' isn't in 'decls'.
michael@0 151 * - For let definitions, this means 'name' isn't already a name in the
michael@0 152 * current block.
michael@0 153 * + The given 'pn' is either a placeholder (created by a previous unbound
michael@0 154 * use) or an un-bound un-linked name node.
michael@0 155 * + The given 'kind' is one of ARG, CONST, VAR, or LET. In particular,
michael@0 156 * NAMED_LAMBDA is handled in an ad hoc special case manner (see
michael@0 157 * LeaveFunction) that we should consider rewriting.
michael@0 158 *
michael@0 159 * Post-conditions:
michael@0 160 * + pc->decls().lookupFirst(name) == pn
michael@0 161 * + The given name 'pn' has been converted in-place into a
michael@0 162 * non-placeholder definition.
michael@0 163 * + If this is a function scope (sc->inFunction), 'pn' is bound to a
michael@0 164 * particular local/argument slot.
michael@0 165 * + PND_CONST is set for Definition::COSNT
michael@0 166 * + Pre-existing uses of pre-existing placeholders have been linked to
michael@0 167 * 'pn' if they are in the scope of 'pn'.
michael@0 168 * + Pre-existing placeholders in the scope of 'pn' have been removed.
michael@0 169 */
michael@0 170 bool define(TokenStream &ts, HandlePropertyName name, Node pn, Definition::Kind);
michael@0 171
michael@0 172 /*
michael@0 173 * Let definitions may shadow same-named definitions in enclosing scopes.
michael@0 174 * To represesent this, 'decls' is not a plain map, but actually:
michael@0 175 * decls :: name -> stack of definitions
michael@0 176 * New bindings are pushed onto the stack, name lookup always refers to the
michael@0 177 * top of the stack, and leaving a block scope calls popLetDecl for each
michael@0 178 * name in the block's scope.
michael@0 179 */
michael@0 180 void popLetDecl(JSAtom *atom);
michael@0 181
michael@0 182 /* See the sad story in defineArg. */
michael@0 183 void prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl);
michael@0 184
michael@0 185 /* See the sad story in MakeDefIntoUse. */
michael@0 186 void updateDecl(JSAtom *atom, Node newDecl);
michael@0 187
michael@0 188 /*
michael@0 189 * After a function body has been parsed, the parser generates the
michael@0 190 * function's "bindings". Bindings are a data-structure, ultimately stored
michael@0 191 * in the compiled JSScript, that serve three purposes:
michael@0 192 * - After parsing, the ParseContext is destroyed and 'decls' along with
michael@0 193 * it. Mostly, the emitter just uses the binding information stored in
michael@0 194 * the use/def nodes, but the emitter occasionally needs 'bindings' for
michael@0 195 * various scope-related queries.
michael@0 196 * - Bindings provide the initial js::Shape to use when creating a dynamic
michael@0 197 * scope object (js::CallObject) for the function. This shape is used
michael@0 198 * during dynamic name lookup.
michael@0 199 * - Sometimes a script's bindings are accessed at runtime to retrieve the
michael@0 200 * contents of the lexical scope (e.g., from the debugger).
michael@0 201 */
michael@0 202 bool generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
michael@0 203 LifoAlloc &alloc,
michael@0 204 InternalHandle<Bindings*> bindings) const;
michael@0 205
michael@0 206 private:
michael@0 207 ParseContext **parserPC; /* this points to the Parser's active pc
michael@0 208 and holds either |this| or one of
michael@0 209 |this|'s descendents */
michael@0 210
michael@0 211 // Value for parserPC to restore at the end. Use 'parent' instead for
michael@0 212 // information about the parse chain, this may be nullptr if
michael@0 213 // parent != nullptr.
michael@0 214 ParseContext<ParseHandler> *oldpc;
michael@0 215
michael@0 216 public:
michael@0 217 OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */
michael@0 218
michael@0 219 FuncStmtSet *funcStmts; /* Set of (non-top-level) function statements
michael@0 220 that will alias any top-level bindings with
michael@0 221 the same name. */
michael@0 222
michael@0 223 // All inner functions in this context. Only filled in when parsing syntax.
michael@0 224 AutoFunctionVector innerFunctions;
michael@0 225
michael@0 226 // In a function context, points to a Directive struct that can be updated
michael@0 227 // to reflect new directives encountered in the Directive Prologue that
michael@0 228 // require reparsing the function. In global/module/generator-tail contexts,
michael@0 229 // we don't need to reparse when encountering a DirectivePrologue so this
michael@0 230 // pointer may be nullptr.
michael@0 231 Directives *newDirectives;
michael@0 232
michael@0 233 // Set when parsing a declaration-like destructuring pattern. This flag
michael@0 234 // causes PrimaryExpr to create PN_NAME parse nodes for variable references
michael@0 235 // which are not hooked into any definition's use chain, added to any tree
michael@0 236 // context's AtomList, etc. etc. CheckDestructuring will do that work
michael@0 237 // later.
michael@0 238 //
michael@0 239 // The comments atop CheckDestructuring explain the distinction between
michael@0 240 // assignment-like and declaration-like destructuring patterns, and why
michael@0 241 // they need to be treated differently.
michael@0 242 bool inDeclDestructuring:1;
michael@0 243
michael@0 244 ParseContext(Parser<ParseHandler> *prs, GenericParseContext *parent,
michael@0 245 Node maybeFunction, SharedContext *sc,
michael@0 246 Directives *newDirectives,
michael@0 247 unsigned staticLevel, uint32_t bodyid, uint32_t blockScopeDepth)
michael@0 248 : GenericParseContext(parent, sc),
michael@0 249 bodyid(0), // initialized in init()
michael@0 250 blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init()
michael@0 251 topStmt(nullptr),
michael@0 252 topScopeStmt(nullptr),
michael@0 253 staticScope(prs->context),
michael@0 254 maybeFunction(maybeFunction),
michael@0 255 staticLevel(staticLevel),
michael@0 256 lastYieldOffset(NoYieldOffset),
michael@0 257 blockScopeDepth(blockScopeDepth),
michael@0 258 blockNode(ParseHandler::null()),
michael@0 259 decls_(prs->context, prs->alloc),
michael@0 260 args_(prs->context),
michael@0 261 vars_(prs->context),
michael@0 262 parserPC(&prs->pc),
michael@0 263 oldpc(prs->pc),
michael@0 264 lexdeps(prs->context),
michael@0 265 funcStmts(nullptr),
michael@0 266 innerFunctions(prs->context),
michael@0 267 newDirectives(newDirectives),
michael@0 268 inDeclDestructuring(false)
michael@0 269 {
michael@0 270 prs->pc = this;
michael@0 271 }
michael@0 272
michael@0 273 ~ParseContext();
michael@0 274
michael@0 275 bool init(TokenStream &ts);
michael@0 276
michael@0 277 unsigned blockid() { return topStmt ? topStmt->blockid : bodyid; }
michael@0 278
michael@0 279 // True if we are at the topmost level of a entire script or function body.
michael@0 280 // For example, while parsing this code we would encounter f1 and f2 at
michael@0 281 // body level, but we would not encounter f3 or f4 at body level:
michael@0 282 //
michael@0 283 // function f1() { function f2() { } }
michael@0 284 // if (cond) { function f3() { if (cond) { function f4() { } } } }
michael@0 285 //
michael@0 286 bool atBodyLevel() { return !topStmt; }
michael@0 287
michael@0 288 // True if this is the ParseContext for the body of a function created by
michael@0 289 // the Function constructor.
michael@0 290 bool isFunctionConstructorBody() const {
michael@0 291 return sc->isFunctionBox() && staticLevel == 0;
michael@0 292 }
michael@0 293
michael@0 294 inline bool useAsmOrInsideUseAsm() const {
michael@0 295 return sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
michael@0 296 }
michael@0 297 };
michael@0 298
michael@0 299 template <typename ParseHandler>
michael@0 300 inline
michael@0 301 Directives::Directives(ParseContext<ParseHandler> *parent)
michael@0 302 : strict_(parent->sc->strict),
michael@0 303 asmJS_(parent->useAsmOrInsideUseAsm())
michael@0 304 {}
michael@0 305
michael@0 306 template <typename ParseHandler>
michael@0 307 struct BindData;
michael@0 308
michael@0 309 class CompExprTransplanter;
michael@0 310
michael@0 311 enum LetContext { LetExpresion, LetStatement };
michael@0 312 enum VarContext { HoistVars, DontHoistVars };
michael@0 313 enum FunctionType { Getter, Setter, Normal };
michael@0 314
michael@0 315 template <typename ParseHandler>
michael@0 316 class Parser : private AutoGCRooter, public StrictModeGetter
michael@0 317 {
michael@0 318 public:
michael@0 319 ExclusiveContext *const context;
michael@0 320 LifoAlloc &alloc;
michael@0 321
michael@0 322 TokenStream tokenStream;
michael@0 323 LifoAlloc::Mark tempPoolMark;
michael@0 324
michael@0 325 /* list of parsed objects for GC tracing */
michael@0 326 ObjectBox *traceListHead;
michael@0 327
michael@0 328 /* innermost parse context (stack-allocated) */
michael@0 329 ParseContext<ParseHandler> *pc;
michael@0 330
michael@0 331 /* Compression token for aborting. */
michael@0 332 SourceCompressionTask *sct;
michael@0 333
michael@0 334 ScriptSource *ss;
michael@0 335
michael@0 336 /* Root atoms and objects allocated for the parsed tree. */
michael@0 337 AutoKeepAtoms keepAtoms;
michael@0 338
michael@0 339 /* Perform constant-folding; must be true when interfacing with the emitter. */
michael@0 340 const bool foldConstants:1;
michael@0 341
michael@0 342 private:
michael@0 343 /*
michael@0 344 * Not all language constructs can be handled during syntax parsing. If it
michael@0 345 * is not known whether the parse succeeds or fails, this bit is set and
michael@0 346 * the parse will return false.
michael@0 347 */
michael@0 348 bool abortedSyntaxParse:1;
michael@0 349
michael@0 350 /* Unexpected end of input, i.e. TOK_EOF not at top-level. */
michael@0 351 bool isUnexpectedEOF_:1;
michael@0 352
michael@0 353 typedef typename ParseHandler::Node Node;
michael@0 354 typedef typename ParseHandler::DefinitionNode DefinitionNode;
michael@0 355
michael@0 356 public:
michael@0 357 /* State specific to the kind of parse being performed. */
michael@0 358 ParseHandler handler;
michael@0 359
michael@0 360 private:
michael@0 361 bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
michael@0 362 unsigned errorNumber, va_list args);
michael@0 363 public:
michael@0 364 bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
michael@0 365 bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
michael@0 366 bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
michael@0 367 ...);
michael@0 368
michael@0 369 Parser(ExclusiveContext *cx, LifoAlloc *alloc, const ReadOnlyCompileOptions &options,
michael@0 370 const jschar *chars, size_t length, bool foldConstants,
michael@0 371 Parser<SyntaxParseHandler> *syntaxParser,
michael@0 372 LazyScript *lazyOuterFunction);
michael@0 373 ~Parser();
michael@0 374
michael@0 375 // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
michael@0 376 // Parser's state. Note: clients must still take care that any ParseContext
michael@0 377 // that points into released ParseNodes is destroyed.
michael@0 378 class Mark
michael@0 379 {
michael@0 380 friend class Parser;
michael@0 381 LifoAlloc::Mark mark;
michael@0 382 ObjectBox *traceListHead;
michael@0 383 };
michael@0 384 Mark mark() const {
michael@0 385 Mark m;
michael@0 386 m.mark = alloc.mark();
michael@0 387 m.traceListHead = traceListHead;
michael@0 388 return m;
michael@0 389 }
michael@0 390 void release(Mark m) {
michael@0 391 alloc.release(m.mark);
michael@0 392 traceListHead = m.traceListHead;
michael@0 393 }
michael@0 394
michael@0 395 friend void js::frontend::MarkParser(JSTracer *trc, AutoGCRooter *parser);
michael@0 396
michael@0 397 const char *getFilename() const { return tokenStream.getFilename(); }
michael@0 398 JSVersion versionNumber() const { return tokenStream.versionNumber(); }
michael@0 399
michael@0 400 /*
michael@0 401 * Parse a top-level JS script.
michael@0 402 */
michael@0 403 Node parse(JSObject *chain);
michael@0 404
michael@0 405 /*
michael@0 406 * Allocate a new parsed object or function container from
michael@0 407 * cx->tempLifoAlloc.
michael@0 408 */
michael@0 409 ObjectBox *newObjectBox(JSObject *obj);
michael@0 410 FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *pc,
michael@0 411 Directives directives, GeneratorKind generatorKind);
michael@0 412
michael@0 413 /*
michael@0 414 * Create a new function object given parse context (pc) and a name (which
michael@0 415 * is optional if this is a function expression).
michael@0 416 */
michael@0 417 JSFunction *newFunction(GenericParseContext *pc, HandleAtom atom, FunctionSyntaxKind kind,
michael@0 418 JSObject *proto = nullptr);
michael@0 419
michael@0 420 void trace(JSTracer *trc);
michael@0 421
michael@0 422 bool hadAbortedSyntaxParse() {
michael@0 423 return abortedSyntaxParse;
michael@0 424 }
michael@0 425 void clearAbortedSyntaxParse() {
michael@0 426 abortedSyntaxParse = false;
michael@0 427 }
michael@0 428
michael@0 429 bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
michael@0 430
michael@0 431 private:
michael@0 432 Parser *thisForCtor() { return this; }
michael@0 433
michael@0 434 Node stringLiteral();
michael@0 435 inline Node newName(PropertyName *name);
michael@0 436
michael@0 437 inline bool abortIfSyntaxParser();
michael@0 438
michael@0 439 public:
michael@0 440
michael@0 441 /* Public entry points for parsing. */
michael@0 442 Node statement(bool canHaveDirectives = false);
michael@0 443 bool maybeParseDirective(Node list, Node pn, bool *cont);
michael@0 444
michael@0 445 // Parse a function, given only its body. Used for the Function and
michael@0 446 // Generator constructors.
michael@0 447 Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
michael@0 448 GeneratorKind generatorKind,
michael@0 449 Directives inheritedDirectives, Directives *newDirectives);
michael@0 450
michael@0 451 // Parse a function, given only its arguments and body. Used for lazily
michael@0 452 // parsed functions.
michael@0 453 Node standaloneLazyFunction(HandleFunction fun, unsigned staticLevel, bool strict,
michael@0 454 GeneratorKind generatorKind);
michael@0 455
michael@0 456 /*
michael@0 457 * Parse a function body. Pass StatementListBody if the body is a list of
michael@0 458 * statements; pass ExpressionBody if the body is a single expression.
michael@0 459 */
michael@0 460 enum FunctionBodyType { StatementListBody, ExpressionBody };
michael@0 461 Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
michael@0 462
michael@0 463 bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
michael@0 464 FunctionSyntaxKind kind, Directives *newDirectives);
michael@0 465
michael@0 466 // Determine whether |yield| is a valid name in the current context, or
michael@0 467 // whether it's prohibited due to strictness, JS version, or occurrence
michael@0 468 // inside a star generator.
michael@0 469 bool checkYieldNameValidity();
michael@0 470
michael@0 471 virtual bool strictMode() { return pc->sc->strict; }
michael@0 472
michael@0 473 const ReadOnlyCompileOptions &options() const {
michael@0 474 return tokenStream.options();
michael@0 475 }
michael@0 476
michael@0 477 private:
michael@0 478 /*
michael@0 479 * JS parsers, from lowest to highest precedence.
michael@0 480 *
michael@0 481 * Each parser must be called during the dynamic scope of a ParseContext
michael@0 482 * object, pointed to by this->pc.
michael@0 483 *
michael@0 484 * Each returns a parse node tree or null on error.
michael@0 485 *
michael@0 486 * Parsers whose name has a '1' suffix leave the TokenStream state
michael@0 487 * pointing to the token one past the end of the parsed fragment. For a
michael@0 488 * number of the parsers this is convenient and avoids a lot of
michael@0 489 * unnecessary ungetting and regetting of tokens.
michael@0 490 *
michael@0 491 * Some parsers have two versions: an always-inlined version (with an 'i'
michael@0 492 * suffix) and a never-inlined version (with an 'n' suffix).
michael@0 493 */
michael@0 494 Node functionStmt();
michael@0 495 Node functionExpr();
michael@0 496 Node statements();
michael@0 497
michael@0 498 Node blockStatement();
michael@0 499 Node ifStatement();
michael@0 500 Node doWhileStatement();
michael@0 501 Node whileStatement();
michael@0 502 Node forStatement();
michael@0 503 Node switchStatement();
michael@0 504 Node continueStatement();
michael@0 505 Node breakStatement();
michael@0 506 Node returnStatement();
michael@0 507 Node withStatement();
michael@0 508 Node labeledStatement();
michael@0 509 Node throwStatement();
michael@0 510 Node tryStatement();
michael@0 511 Node debuggerStatement();
michael@0 512
michael@0 513 Node letDeclaration();
michael@0 514 Node letStatement();
michael@0 515 Node importDeclaration();
michael@0 516 Node exportDeclaration();
michael@0 517 Node expressionStatement();
michael@0 518 Node variables(ParseNodeKind kind, bool *psimple = nullptr,
michael@0 519 StaticBlockObject *blockObj = nullptr,
michael@0 520 VarContext varContext = HoistVars);
michael@0 521 Node expr();
michael@0 522 Node assignExpr();
michael@0 523 Node assignExprWithoutYield(unsigned err);
michael@0 524 Node yieldExpression();
michael@0 525 Node condExpr1();
michael@0 526 Node orExpr1();
michael@0 527 Node unaryExpr();
michael@0 528 Node memberExpr(TokenKind tt, bool allowCallSyntax);
michael@0 529 Node primaryExpr(TokenKind tt);
michael@0 530 Node parenExprOrGeneratorComprehension();
michael@0 531 Node exprInParens();
michael@0 532
michael@0 533 /*
michael@0 534 * Additional JS parsers.
michael@0 535 */
michael@0 536 bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool *hasRest);
michael@0 537
michael@0 538 Node functionDef(HandlePropertyName name, const TokenStream::Position &start,
michael@0 539 FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind);
michael@0 540 bool functionArgsAndBody(Node pn, HandleFunction fun,
michael@0 541 FunctionType type, FunctionSyntaxKind kind,
michael@0 542 GeneratorKind generatorKind,
michael@0 543 Directives inheritedDirectives, Directives *newDirectives);
michael@0 544
michael@0 545 Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
michael@0 546
michael@0 547 Node condition();
michael@0 548
michael@0 549 Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
michael@0 550 Node innerStmt);
michael@0 551
michael@0 552 Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
michael@0 553 ParseContext<ParseHandler> *outerpc,
michael@0 554 unsigned innerBlockScopeDepth);
michael@0 555 Node legacyArrayComprehension(Node array);
michael@0 556 Node legacyGeneratorExpr(Node kid);
michael@0 557
michael@0 558 Node comprehensionTail(GeneratorKind comprehensionKind);
michael@0 559 Node comprehensionIf(GeneratorKind comprehensionKind);
michael@0 560 Node comprehensionFor(GeneratorKind comprehensionKind);
michael@0 561 Node comprehension(GeneratorKind comprehensionKind);
michael@0 562 Node arrayComprehension(uint32_t begin);
michael@0 563 Node generatorComprehension(uint32_t begin);
michael@0 564
michael@0 565 bool argumentList(Node listNode, bool *isSpread);
michael@0 566 Node letBlock(LetContext letContext);
michael@0 567 Node destructuringExpr(BindData<ParseHandler> *data, TokenKind tt);
michael@0 568
michael@0 569 Node identifierName();
michael@0 570
michael@0 571 bool matchLabel(MutableHandle<PropertyName*> label);
michael@0 572
michael@0 573 bool allowsForEachIn() {
michael@0 574 #if !JS_HAS_FOR_EACH_IN
michael@0 575 return false;
michael@0 576 #else
michael@0 577 return versionNumber() >= JSVERSION_1_6;
michael@0 578 #endif
michael@0 579 }
michael@0 580
michael@0 581 enum AssignmentFlavor {
michael@0 582 PlainAssignment,
michael@0 583 CompoundAssignment,
michael@0 584 KeyedDestructuringAssignment,
michael@0 585 IncDecAssignment
michael@0 586 };
michael@0 587
michael@0 588 bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
michael@0 589 bool matchInOrOf(bool *isForOfp);
michael@0 590
michael@0 591 bool checkFunctionArguments();
michael@0 592 bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom);
michael@0 593 bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
michael@0 594 bool *pbodyProcessed);
michael@0 595 bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
michael@0 596 bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext<ParseHandler> *pc);
michael@0 597
michael@0 598 bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
michael@0 599 ParseNodeKind headKind);
michael@0 600 bool checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder);
michael@0 601 bool checkStrictAssignment(Node lhs, AssignmentFlavor flavor);
michael@0 602 bool checkStrictBinding(PropertyName *name, Node pn);
michael@0 603 bool defineArg(Node funcpn, HandlePropertyName name,
michael@0 604 bool disallowDuplicateArgs = false, Node *duplicatedArg = nullptr);
michael@0 605 Node pushLexicalScope(StmtInfoPC *stmt);
michael@0 606 Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
michael@0 607 Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
michael@0 608 bool noteNameUse(HandlePropertyName name, Node pn);
michael@0 609 Node objectLiteral();
michael@0 610 Node arrayInitializer();
michael@0 611 Node newRegExp();
michael@0 612
michael@0 613 Node newBindingNode(PropertyName *name, bool functionScope, VarContext varContext = HoistVars);
michael@0 614 bool checkDestructuring(BindData<ParseHandler> *data, Node left, bool toplevel = true);
michael@0 615 bool bindDestructuringVar(BindData<ParseHandler> *data, Node pn);
michael@0 616 bool bindDestructuringLHS(Node pn);
michael@0 617 bool makeSetCall(Node pn, unsigned msg);
michael@0 618 Node cloneLeftHandSide(Node opn);
michael@0 619 Node cloneParseTree(Node opn);
michael@0 620
michael@0 621 Node newNumber(const Token &tok) {
michael@0 622 return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
michael@0 623 }
michael@0 624
michael@0 625 static bool
michael@0 626 bindDestructuringArg(BindData<ParseHandler> *data,
michael@0 627 HandlePropertyName name, Parser<ParseHandler> *parser);
michael@0 628
michael@0 629 static bool
michael@0 630 bindLet(BindData<ParseHandler> *data,
michael@0 631 HandlePropertyName name, Parser<ParseHandler> *parser);
michael@0 632
michael@0 633 static bool
michael@0 634 bindVarOrConst(BindData<ParseHandler> *data,
michael@0 635 HandlePropertyName name, Parser<ParseHandler> *parser);
michael@0 636
michael@0 637 static Node null() { return ParseHandler::null(); }
michael@0 638
michael@0 639 bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom);
michael@0 640 bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
michael@0 641 bool checkFinalReturn(Node pn);
michael@0 642 DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom);
michael@0 643
michael@0 644 bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc,
michael@0 645 FunctionSyntaxKind kind = Expression);
michael@0 646
michael@0 647 TokenPos pos() const { return tokenStream.currentToken().pos; }
michael@0 648
michael@0 649 bool asmJS(Node list);
michael@0 650
michael@0 651 friend class LegacyCompExprTransplanter;
michael@0 652 friend struct BindData<ParseHandler>;
michael@0 653 };
michael@0 654
michael@0 655 /* Declare some required template specializations. */
michael@0 656
michael@0 657 template <>
michael@0 658 bool
michael@0 659 Parser<FullParseHandler>::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentFlavor flavor);
michael@0 660
michael@0 661 template <>
michael@0 662 bool
michael@0 663 Parser<SyntaxParseHandler>::checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
michael@0 664
michael@0 665 } /* namespace frontend */
michael@0 666 } /* namespace js */
michael@0 667
michael@0 668 /*
michael@0 669 * Convenience macro to access Parser.tokenStream as a pointer.
michael@0 670 */
michael@0 671 #define TS(p) (&(p)->tokenStream)
michael@0 672
michael@0 673 #endif /* frontend_Parser_h */

mercurial