1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef frontend_Parser_h
8 #define frontend_Parser_h
9
10 /*
11 * JS parser definitions.
12 */
13
14 #include "jspubtd.h"
15
16 #include "frontend/BytecodeCompiler.h"
17 #include "frontend/FullParseHandler.h"
18 #include "frontend/ParseMaps.h"
19 #include "frontend/ParseNode.h"
20 #include "frontend/SharedContext.h"
21 #include "frontend/SyntaxParseHandler.h"
22
23 namespace js {
24
25 class ModuleObject;
26 class StaticFunctionBoxScopeObject;
27
28 namespace frontend {
29
30 struct StmtInfoPC : public StmtInfoBase
31 {
32 static const unsigned BlockIdLimit = 1 << ParseNode::NumBlockIdBits;
33
34 StmtInfoPC* enclosing;
35 StmtInfoPC* enclosingScope;
36
37 uint32_t blockid; /* for simplified dominance computation */
38 uint32_t innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */
39
40 // Lexical declarations inside switches are tricky because the block id
41 // doesn't convey dominance information. Record what index the current
42 // case's lexical declarations start at so we may generate dead zone
43 // checks for other cases' declarations.
44 //
45 // Only valid if type is StmtType::SWITCH.
46 uint16_t firstDominatingLexicalInCase;
47
StmtInfoPCStmtInfoPC48 explicit StmtInfoPC(ExclusiveContext* cx)
49 : StmtInfoBase(cx),
50 blockid(BlockIdLimit),
51 innerBlockScopeDepth(0),
52 firstDominatingLexicalInCase(0)
53 {}
54 };
55
56 typedef HashSet<JSAtom*, DefaultHasher<JSAtom*>, LifoAllocPolicy<Fallible>> FuncStmtSet;
57 class SharedContext;
58
59 typedef Vector<Definition*, 16> DeclVector;
60
61 struct GenericParseContext
62 {
63 // Enclosing function or global context.
64 GenericParseContext* parent;
65
66 // Context shared between parsing and bytecode generation.
67 SharedContext* sc;
68
69 // The following flags are set when a particular code feature is detected
70 // in a function.
71
72 // Function has 'return <expr>;'
73 bool funHasReturnExpr:1;
74
75 // Function has 'return;'
76 bool funHasReturnVoid:1;
77
GenericParseContextGenericParseContext78 GenericParseContext(GenericParseContext* parent, SharedContext* sc)
79 : parent(parent),
80 sc(sc),
81 funHasReturnExpr(false),
82 funHasReturnVoid(false)
83 {}
84 };
85
86 template <typename ParseHandler>
87 bool
88 GenerateBlockId(TokenStream& ts, ParseContext<ParseHandler>* pc, uint32_t& blockid);
89
90 /*
91 * The struct ParseContext stores information about the current parsing context,
92 * which is part of the parser state (see the field Parser::pc). The current
93 * parsing context is either the global context, or the function currently being
94 * parsed. When the parser encounters a function definition, it creates a new
95 * ParseContext, makes it the new current context, and sets its parent to the
96 * context in which it encountered the definition.
97 */
98 template <typename ParseHandler>
99 struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
100 {
101 typedef typename ParseHandler::Node Node;
102 typedef typename ParseHandler::DefinitionNode DefinitionNode;
103
104 uint32_t bodyid; /* block number of program/function body */
105
106 StmtInfoStack<StmtInfoPC> stmtStack;
107
108 Node maybeFunction; /* sc->isFunctionBox, the pn where pn->pn_funbox == sc */
109
110 // If sc->isFunctionBox(), this is used to temporarily link up the
111 // FunctionBox with the JSFunction so the static scope chain may be walked
112 // without a JSScript.
113 mozilla::Maybe<JSFunction::AutoParseUsingFunctionBox> parseUsingFunctionBox;
114
115 // lastYieldOffset stores the offset of the last yield that was parsed.
116 // NoYieldOffset is its initial value.
117 static const uint32_t NoYieldOffset = UINT32_MAX;
118 uint32_t lastYieldOffset;
119
120 // Most functions start off being parsed as non-generators.
121 // Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7.
122 // An ES6 generator is marked as a "star generator" before its body is parsed.
generatorKindParseContext123 GeneratorKind generatorKind() const {
124 return sc->isFunctionBox() ? sc->asFunctionBox()->generatorKind() : NotGenerator;
125 }
isGeneratorParseContext126 bool isGenerator() const { return generatorKind() != NotGenerator; }
isLegacyGeneratorParseContext127 bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
isStarGeneratorParseContext128 bool isStarGenerator() const { return generatorKind() == StarGenerator; }
129
isArrowFunctionParseContext130 bool isArrowFunction() const {
131 return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow();
132 }
isMethodParseContext133 bool isMethod() const {
134 return sc->isFunctionBox() && sc->asFunctionBox()->function()->isMethod();
135 }
136
137 uint32_t blockScopeDepth; /* maximum depth of nested block scopes, in slots */
138 Node blockNode; /* parse node for a block with let declarations
139 (block with its own lexical scope) */
140
141 private:
142 AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
143 DeclVector args_; /* argument definitions */
144 DeclVector vars_; /* var/const definitions */
145 DeclVector bodyLevelLexicals_; /* lexical definitions at body-level */
146
147 bool checkLocalsOverflow(TokenStream& ts);
148
149 public:
declsParseContext150 const AtomDecls<ParseHandler>& decls() const {
151 return decls_;
152 }
153
numArgsParseContext154 uint32_t numArgs() const {
155 MOZ_ASSERT(sc->isFunctionBox());
156 return args_.length();
157 }
158
159 /*
160 * This function adds a definition to the lexical scope represented by this
161 * ParseContext.
162 *
163 * Pre-conditions:
164 * + The caller must have already taken care of name collisions:
165 * - For non-let definitions, this means 'name' isn't in 'decls'.
166 * - For let definitions, this means 'name' isn't already a name in the
167 * current block.
168 * + The given 'pn' is either a placeholder (created by a previous unbound
169 * use) or an un-bound un-linked name node.
170 * + The given 'kind' is one of ARG, CONST, VAR, or LET. In particular,
171 * NAMED_LAMBDA is handled in an ad hoc special case manner (see
172 * LeaveFunction) that we should consider rewriting.
173 *
174 * Post-conditions:
175 * + pc->decls().lookupFirst(name) == pn
176 * + The given name 'pn' has been converted in-place into a
177 * non-placeholder definition.
178 * + If this is a function scope (sc->inFunction), 'pn' is bound to a
179 * particular local/argument slot.
180 * + PND_CONST is set for Definition::COSNT
181 * + Pre-existing uses of pre-existing placeholders have been linked to
182 * 'pn' if they are in the scope of 'pn'.
183 * + Pre-existing placeholders in the scope of 'pn' have been removed.
184 */
185 bool define(TokenStream& ts, HandlePropertyName name, Node pn, Definition::Kind);
186
187 /*
188 * Let definitions may shadow same-named definitions in enclosing scopes.
189 * To represesent this, 'decls' is not a plain map, but actually:
190 * decls :: name -> stack of definitions
191 * New bindings are pushed onto the stack, name lookup always refers to the
192 * top of the stack, and leaving a block scope calls popLetDecl for each
193 * name in the block's scope.
194 */
195 void popLetDecl(JSAtom* atom);
196
197 /* See the sad story in defineArg. */
198 void prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl);
199
200 /* See the sad story in MakeDefIntoUse. */
201 void updateDecl(TokenStream& ts, JSAtom* atom, Node newDecl);
202
203 // After a script has been parsed, the parser generates the code's
204 // "bindings". Bindings are a data-structure, ultimately stored in the
205 // compiled JSScript, that serve three purposes:
206 //
207 // - After parsing, the ParseContext is destroyed and 'decls' along with
208 // it. Mostly, the emitter just uses the binding information stored in
209 // the use/def nodes, but the emitter occasionally needs 'bindings' for
210 // various scope-related queries.
211 //
212 // - For functions, bindings provide the initial js::Shape to use when
213 // creating a dynamic scope object (js::CallObject). This shape is used
214 // during dynamic name lookup.
215 //
216 // - Sometimes a script's bindings are accessed at runtime to retrieve the
217 // contents of the lexical scope (e.g., from the debugger).
218 //
219 // - For global and eval scripts, ES6 15.1.8 specifies that if there are
220 // name conflicts in the script, *no* bindings from the script are
221 // instantiated. So, record the vars and lexical bindings to check for
222 // redeclarations in the prologue.
223 bool generateBindings(ExclusiveContext* cx, TokenStream& ts, LifoAlloc& alloc,
224 MutableHandle<Bindings> bindings) const;
225
226 private:
227 ParseContext** parserPC; /* this points to the Parser's active pc
228 and holds either |this| or one of
229 |this|'s descendents */
230
231 // Value for parserPC to restore at the end. Use 'parent' instead for
232 // information about the parse chain, this may be nullptr if
233 // parent != nullptr.
234 ParseContext<ParseHandler>* oldpc;
235
236 public:
237 OwnedAtomDefnMapPtr lexdeps; /* unresolved lexical name dependencies */
238
239 FuncStmtSet* funcStmts; /* Set of (non-top-level) function statements
240 that will alias any top-level bindings with
241 the same name. */
242
243 // All inner functions in this context. Only filled in when parsing syntax.
244 Rooted<TraceableVector<JSFunction*>> innerFunctions;
245
246 // In a function context, points to a Directive struct that can be updated
247 // to reflect new directives encountered in the Directive Prologue that
248 // require reparsing the function. In global/module/generator-tail contexts,
249 // we don't need to reparse when encountering a DirectivePrologue so this
250 // pointer may be nullptr.
251 Directives* newDirectives;
252
253 // Set when parsing a declaration-like destructuring pattern. This flag
254 // causes PrimaryExpr to create PN_NAME parse nodes for variable references
255 // which are not hooked into any definition's use chain, added to any tree
256 // context's AtomList, etc. etc. checkDestructuring will do that work
257 // later.
258 //
259 // The comments atop checkDestructuring explain the distinction between
260 // assignment-like and declaration-like destructuring patterns, and why
261 // they need to be treated differently.
262 bool inDeclDestructuring:1;
263
ParseContextParseContext264 ParseContext(Parser<ParseHandler>* prs, GenericParseContext* parent,
265 Node maybeFunction, SharedContext* sc, Directives* newDirectives)
266 : GenericParseContext(parent, sc),
267 bodyid(0), // initialized in init()
268 stmtStack(prs->context),
269 maybeFunction(maybeFunction),
270 lastYieldOffset(NoYieldOffset),
271 blockScopeDepth(0),
272 blockNode(ParseHandler::null()),
273 decls_(prs->context, prs->alloc),
274 args_(prs->context),
275 vars_(prs->context),
276 bodyLevelLexicals_(prs->context),
277 parserPC(&prs->pc),
278 oldpc(prs->pc),
279 lexdeps(prs->context),
280 funcStmts(nullptr),
281 innerFunctions(prs->context, TraceableVector<JSFunction*>(prs->context)),
282 newDirectives(newDirectives),
283 inDeclDestructuring(false)
284 {
285 prs->pc = this;
286 if (sc->isFunctionBox())
287 parseUsingFunctionBox.emplace(prs->context, sc->asFunctionBox());
288 }
289
290 ~ParseContext();
291
292 bool init(Parser<ParseHandler>& parser);
293
blockidParseContext294 unsigned blockid() { return stmtStack.innermost() ? stmtStack.innermost()->blockid : bodyid; }
295
innermostStmtParseContext296 StmtInfoPC* innermostStmt() const { return stmtStack.innermost(); }
innermostScopeStmtParseContext297 StmtInfoPC* innermostScopeStmt() const { return stmtStack.innermostScopeStmt(); }
innermostStaticScopeParseContext298 JSObject* innermostStaticScope() const {
299 if (StmtInfoPC* stmt = innermostScopeStmt())
300 return stmt->staticScope;
301 return sc->staticScope();
302 }
303
304 // True if we are at the topmost level of a entire script or function body.
305 // For example, while parsing this code we would encounter f1 and f2 at
306 // body level, but we would not encounter f3 or f4 at body level:
307 //
308 // function f1() { function f2() { } }
309 // if (cond) { function f3() { if (cond) { function f4() { } } } }
310 //
atBodyLevelParseContext311 bool atBodyLevel() {
312 // 'eval' and non-syntactic scripts are always under an invisible
313 // lexical scope, but since it is not syntactic, it should still be
314 // considered at body level.
315 if (sc->staticScope()->is<StaticEvalObject>()) {
316 bool bl = !innermostStmt()->enclosing;
317 MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
318 MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
319 ->template as<StaticBlockObject>()
320 .enclosingStaticScope() == sc->staticScope());
321 return bl;
322 }
323 return !innermostStmt();
324 }
325
atGlobalLevelParseContext326 bool atGlobalLevel() {
327 return atBodyLevel() && sc->isGlobalContext() && !innermostScopeStmt();
328 }
329
330 // True if we are at the topmost level of a module only.
atModuleLevelParseContext331 bool atModuleLevel() {
332 return atBodyLevel() && sc->isModuleBox();
333 }
334
335 // True if the current lexical scope is the topmost level of a module.
atModuleScopeParseContext336 bool atModuleScope() {
337 return sc->isModuleBox() && !innermostScopeStmt();
338 }
339
340 // True if this is the ParseContext for the body of a function created by
341 // the Function constructor.
isFunctionConstructorBodyParseContext342 bool isFunctionConstructorBody() const {
343 return sc->isFunctionBox() && !parent && sc->asFunctionBox()->function()->isLambda();
344 }
345
useAsmOrInsideUseAsmParseContext346 inline bool useAsmOrInsideUseAsm() const {
347 return sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
348 }
349 };
350
351 template <typename ParseHandler>
352 inline
Directives(ParseContext<ParseHandler> * parent)353 Directives::Directives(ParseContext<ParseHandler>* parent)
354 : strict_(parent->sc->strict()),
355 asmJS_(parent->useAsmOrInsideUseAsm())
356 {}
357
358 template <typename ParseHandler>
359 struct BindData;
360
361 class CompExprTransplanter;
362
363 enum VarContext { HoistVars, DontHoistVars };
364 enum PropListType { ObjectLiteral, ClassBody, DerivedClassBody };
365 enum class PropertyType {
366 Normal,
367 Shorthand,
368 Getter,
369 GetterNoExpressionClosure,
370 Setter,
371 SetterNoExpressionClosure,
372 Method,
373 GeneratorMethod,
374 Constructor,
375 DerivedConstructor
376 };
377
378 // Specify a value for an ES6 grammar parametrization. We have no enum for
379 // [Return] because its behavior is exactly equivalent to checking whether
380 // we're in a function box -- easier and simpler than passing an extra
381 // parameter everywhere.
382 enum YieldHandling { YieldIsName, YieldIsKeyword };
383 enum InHandling { InAllowed, InProhibited };
384 enum DefaultHandling { NameRequired, AllowDefaultName };
385 enum TripledotHandling { TripledotAllowed, TripledotProhibited };
386
387 template <typename ParseHandler>
388 class Parser : private JS::AutoGCRooter, public StrictModeGetter
389 {
390 class MOZ_STACK_CLASS AutoPushStmtInfoPC
391 {
392 Parser<ParseHandler>& parser_;
393 StmtInfoPC stmt_;
394
395 public:
396 AutoPushStmtInfoPC(Parser<ParseHandler>& parser, StmtType type);
397 AutoPushStmtInfoPC(Parser<ParseHandler>& parser, StmtType type,
398 NestedScopeObject& staticScope);
399 ~AutoPushStmtInfoPC();
400
401 bool generateBlockId();
402 bool makeInnermostLexicalScope(StaticBlockObject& blockObj);
403
404 StmtInfoPC& operator*() { return stmt_; }
405 StmtInfoPC* operator->() { return &stmt_; }
406 operator StmtInfoPC*() { return &stmt_; }
407 };
408
409 public:
410 ExclusiveContext* const context;
411 LifoAlloc& alloc;
412
413 TokenStream tokenStream;
414 LifoAlloc::Mark tempPoolMark;
415
416 /* list of parsed objects for GC tracing */
417 ObjectBox* traceListHead;
418
419 /* innermost parse context (stack-allocated) */
420 ParseContext<ParseHandler>* pc;
421
422 // List of all block scopes.
423 AutoObjectVector blockScopes;
424
425 /* Compression token for aborting. */
426 SourceCompressionTask* sct;
427
428 ScriptSource* ss;
429
430 /* Root atoms and objects allocated for the parsed tree. */
431 AutoKeepAtoms keepAtoms;
432
433 /* Perform constant-folding; must be true when interfacing with the emitter. */
434 const bool foldConstants:1;
435
436 private:
437 #if DEBUG
438 /* Our fallible 'checkOptions' member function has been called. */
439 bool checkOptionsCalled:1;
440 #endif
441
442 /*
443 * Not all language constructs can be handled during syntax parsing. If it
444 * is not known whether the parse succeeds or fails, this bit is set and
445 * the parse will return false.
446 */
447 bool abortedSyntaxParse:1;
448
449 /* Unexpected end of input, i.e. TOK_EOF not at top-level. */
450 bool isUnexpectedEOF_:1;
451
452 typedef typename ParseHandler::Node Node;
453 typedef typename ParseHandler::DefinitionNode DefinitionNode;
454
455 public:
456 /* State specific to the kind of parse being performed. */
457 ParseHandler handler;
458
prepareNodeForMutation(Node node)459 void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
freeTree(Node node)460 void freeTree(Node node) { handler.freeTree(node); }
461
462 private:
463 bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
464 unsigned errorNumber, va_list args);
465 public:
466 bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
467 bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
468 bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
469 ...);
470
471 Parser(ExclusiveContext* cx, LifoAlloc* alloc, const ReadOnlyCompileOptions& options,
472 const char16_t* chars, size_t length, bool foldConstants,
473 Parser<SyntaxParseHandler>* syntaxParser,
474 LazyScript* lazyOuterFunction);
475 ~Parser();
476
477 bool checkOptions();
478
479 // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
480 // Parser's state. Note: clients must still take care that any ParseContext
481 // that points into released ParseNodes is destroyed.
482 class Mark
483 {
484 friend class Parser;
485 LifoAlloc::Mark mark;
486 ObjectBox* traceListHead;
487 };
mark()488 Mark mark() const {
489 Mark m;
490 m.mark = alloc.mark();
491 m.traceListHead = traceListHead;
492 return m;
493 }
release(Mark m)494 void release(Mark m) {
495 alloc.release(m.mark);
496 traceListHead = m.traceListHead;
497 }
498
499 friend void js::frontend::MarkParser(JSTracer* trc, JS::AutoGCRooter* parser);
500
getFilename()501 const char* getFilename() const { return tokenStream.getFilename(); }
versionNumber()502 JSVersion versionNumber() const { return tokenStream.versionNumber(); }
503
504 /*
505 * Parse a top-level JS script.
506 */
507 Node parse();
508
509 /*
510 * Allocate a new parsed object or function container from
511 * cx->tempLifoAlloc.
512 */
513 ObjectBox* newObjectBox(JSObject* obj);
514 FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext<ParseHandler>* outerpc,
515 Directives directives, GeneratorKind generatorKind,
516 JSObject* enclosingStaticScope);
517
518 // Use when the funbox is the outermost.
newFunctionBox(Node fn,HandleFunction fun,Directives directives,GeneratorKind generatorKind,HandleObject enclosingStaticScope)519 FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives,
520 GeneratorKind generatorKind, HandleObject enclosingStaticScope)
521 {
522 return newFunctionBox(fn, fun, nullptr, directives, generatorKind,
523 enclosingStaticScope);
524 }
525
526 // Use when the funbox should be linked to the outerpc's innermost scope.
newFunctionBox(Node fn,HandleFunction fun,ParseContext<ParseHandler> * outerpc,Directives directives,GeneratorKind generatorKind)527 FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext<ParseHandler>* outerpc,
528 Directives directives, GeneratorKind generatorKind)
529 {
530 RootedObject enclosing(context, outerpc->innermostStaticScope());
531 return newFunctionBox(fn, fun, outerpc, directives, generatorKind, enclosing);
532 }
533
534 ModuleBox* newModuleBox(Node pn, HandleModuleObject module);
535
536 /*
537 * Create a new function object given a name (which is optional if this is
538 * a function expression).
539 */
540 JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
541 HandleObject proto);
542
generateBlockId(JSObject * staticScope,uint32_t * blockIdOut)543 bool generateBlockId(JSObject* staticScope, uint32_t* blockIdOut) {
544 if (blockScopes.length() == StmtInfoPC::BlockIdLimit) {
545 tokenStream.reportError(JSMSG_NEED_DIET, "program");
546 return false;
547 }
548 MOZ_ASSERT(blockScopes.length() < StmtInfoPC::BlockIdLimit);
549 *blockIdOut = blockScopes.length();
550 return blockScopes.append(staticScope);
551 }
552
553 void trace(JSTracer* trc);
554
hadAbortedSyntaxParse()555 bool hadAbortedSyntaxParse() {
556 return abortedSyntaxParse;
557 }
clearAbortedSyntaxParse()558 void clearAbortedSyntaxParse() {
559 abortedSyntaxParse = false;
560 }
561
isUnexpectedEOF()562 bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
563
564 bool checkUnescapedName();
565
566 private:
thisForCtor()567 Parser* thisForCtor() { return this; }
568
569 JSAtom * stopStringCompression();
570
571 Node stringLiteral();
572 Node noSubstitutionTemplate();
573 Node templateLiteral(YieldHandling yieldHandling);
574 bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt);
575 bool appendToCallSiteObj(Node callSiteObj);
576 bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
577 TokenKind* ttp);
578 bool checkStatementsEOF();
579
580 inline Node newName(PropertyName* name);
581 inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
582
583 inline bool abortIfSyntaxParser();
584
585 public:
586 /* Public entry points for parsing. */
587 Node statement(YieldHandling yieldHandling, bool canHaveDirectives = false);
588
589 bool maybeParseDirective(Node list, Node pn, bool* cont);
590
591 // Parse the body of an eval.
592 //
593 // Eval scripts are distinguished from global scripts in that in ES6, per
594 // 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
595 // lexical scope.
596 Node evalBody();
597
598 // Parse the body of a global script.
599 Node globalBody();
600
601 // Parse a module.
602 Node standaloneModule(Handle<ModuleObject*> module);
603
604 // Parse a function, given only its body. Used for the Function and
605 // Generator constructors.
606 Node standaloneFunctionBody(HandleFunction fun, Handle<PropertyNameVector> formals,
607 GeneratorKind generatorKind,
608 Directives inheritedDirectives, Directives* newDirectives,
609 HandleObject enclosingStaticScope);
610
611 // Parse a function, given only its arguments and body. Used for lazily
612 // parsed functions.
613 Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind);
614
615 /*
616 * Parse a function body. Pass StatementListBody if the body is a list of
617 * statements; pass ExpressionBody if the body is a single expression.
618 */
619 enum FunctionBodyType { StatementListBody, ExpressionBody };
620 Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
621 FunctionBodyType type);
622
623 bool functionArgsAndBodyGeneric(InHandling inHandling, YieldHandling yieldHandling, Node pn,
624 HandleFunction fun, FunctionSyntaxKind kind);
625
626 // Determine whether |yield| is a valid name in the current context, or
627 // whether it's prohibited due to strictness, JS version, or occurrence
628 // inside a star generator.
629 bool checkYieldNameValidity();
yieldExpressionsSupported()630 bool yieldExpressionsSupported() {
631 return versionNumber() >= JSVERSION_1_7 || pc->isGenerator();
632 }
633
strictMode()634 virtual bool strictMode() { return pc->sc->strict(); }
setLocalStrictMode(bool strict)635 bool setLocalStrictMode(bool strict) {
636 MOZ_ASSERT(tokenStream.debugHasNoLookahead());
637 return pc->sc->setLocalStrictMode(strict);
638 }
639
options()640 const ReadOnlyCompileOptions& options() const {
641 return tokenStream.options();
642 }
643
644 private:
645 enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
646 enum ForInitLocation { InForInit, NotInForInit };
647
648 private:
649 /*
650 * JS parsers, from lowest to highest precedence.
651 *
652 * Each parser must be called during the dynamic scope of a ParseContext
653 * object, pointed to by this->pc.
654 *
655 * Each returns a parse node tree or null on error.
656 *
657 * Parsers whose name has a '1' suffix leave the TokenStream state
658 * pointing to the token one past the end of the parsed fragment. For a
659 * number of the parsers this is convenient and avoids a lot of
660 * unnecessary ungetting and regetting of tokens.
661 *
662 * Some parsers have two versions: an always-inlined version (with an 'i'
663 * suffix) and a never-inlined version (with an 'n' suffix).
664 */
665 Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
666 Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
667 Node statements(YieldHandling yieldHandling);
668
669 Node blockStatement(YieldHandling yieldHandling);
670 Node ifStatement(YieldHandling yieldHandling);
671 Node doWhileStatement(YieldHandling yieldHandling);
672 Node whileStatement(YieldHandling yieldHandling);
673 Node forStatement(YieldHandling yieldHandling);
674 Node switchStatement(YieldHandling yieldHandling);
675 Node continueStatement(YieldHandling yieldHandling);
676 Node breakStatement(YieldHandling yieldHandling);
677 Node returnStatement(YieldHandling yieldHandling);
678 Node withStatement(YieldHandling yieldHandling);
679 Node labeledStatement(YieldHandling yieldHandling);
680 Node throwStatement(YieldHandling yieldHandling);
681 Node tryStatement(YieldHandling yieldHandling);
682 Node debuggerStatement();
683
684 Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
685 Node importDeclaration();
686 Node exportDeclaration();
687 Node expressionStatement(YieldHandling yieldHandling,
688 InvokedPrediction invoked = PredictUninvoked);
689 Node variables(YieldHandling yieldHandling,
690 ParseNodeKind kind,
691 ForInitLocation location,
692 bool* psimple = nullptr, StaticBlockObject* blockObj = nullptr,
693 VarContext varContext = HoistVars);
694 Node expr(InHandling inHandling, YieldHandling yieldHandling,
695 TripledotHandling tripledotHandling,
696 InvokedPrediction invoked = PredictUninvoked);
697 Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
698 TripledotHandling tripledotHandling,
699 InvokedPrediction invoked = PredictUninvoked);
700 Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
701 Node yieldExpression(InHandling inHandling);
702 Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
703 TripledotHandling tripledotHandling,
704 InvokedPrediction invoked = PredictUninvoked);
705 Node orExpr1(InHandling inHandling, YieldHandling yieldHandling,
706 TripledotHandling tripledotHandling,
707 InvokedPrediction invoked = PredictUninvoked);
708 Node unaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
709 InvokedPrediction invoked = PredictUninvoked);
710 Node memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling, TokenKind tt,
711 bool allowCallSyntax, InvokedPrediction invoked = PredictUninvoked);
712 Node primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling, TokenKind tt,
713 InvokedPrediction invoked = PredictUninvoked);
714 Node exprInParens(InHandling inHandling, YieldHandling yieldHandling,
715 TripledotHandling tripledotHandling);
716
717 bool tryNewTarget(Node& newTarget);
718 bool checkAndMarkSuperScope();
719
720 Node methodDefinition(YieldHandling yieldHandling, PropertyType propType,
721 HandlePropertyName funName);
722
723 /*
724 * Additional JS parsers.
725 */
726 bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
727 Node funcpn, bool* hasRest);
728
729 Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
730 FunctionSyntaxKind kind, GeneratorKind generatorKind,
731 InvokedPrediction invoked = PredictUninvoked);
732 bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
733 FunctionSyntaxKind kind, GeneratorKind generatorKind,
734 Directives inheritedDirectives, Directives* newDirectives);
735
736 Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
737
738 Node condition(InHandling inHandling, YieldHandling yieldHandling);
739
740 /* comprehensions */
741 Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
742 ParseContext<ParseHandler>* outerpc,
743 unsigned innerBlockScopeDepth);
744 Node legacyArrayComprehension(Node array);
745 Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
746 Node innerStmt);
747 Node legacyGeneratorExpr(Node kid);
748 Node comprehensionFor(GeneratorKind comprehensionKind);
749 Node comprehensionIf(GeneratorKind comprehensionKind);
750 Node comprehensionTail(GeneratorKind comprehensionKind);
751 Node comprehension(GeneratorKind comprehensionKind);
752 Node arrayComprehension(uint32_t begin);
753 Node generatorComprehension(uint32_t begin);
754
755 bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
756 Node destructuringExpr(YieldHandling yieldHandling, BindData<ParseHandler>* data,
757 TokenKind tt);
758 Node destructuringExprWithoutYield(YieldHandling yieldHandling, BindData<ParseHandler>* data,
759 TokenKind tt, unsigned msg);
760
761 Node newBoundImportForCurrentName();
762 bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet);
763 bool addExportName(JSAtom* exportName);
764
765 enum ClassContext { ClassStatement, ClassExpression };
766 Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling);
767
768 Node identifierName(YieldHandling yieldHandling);
769
770 bool matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label);
771
allowsForEachIn()772 bool allowsForEachIn() {
773 #if !JS_HAS_FOR_EACH_IN
774 return false;
775 #else
776 return versionNumber() >= JSVERSION_1_6;
777 #endif
778 }
779
780 enum AssignmentFlavor {
781 PlainAssignment,
782 CompoundAssignment,
783 KeyedDestructuringAssignment,
784 IncrementAssignment,
785 DecrementAssignment
786 };
787
788 bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
789 bool matchInOrOf(bool* isForInp, bool* isForOfp);
790
791 bool checkFunctionArguments();
792
793 bool defineFunctionThis();
794 Node newThisName();
795
796 bool makeDefIntoUse(Definition* dn, Node pn, HandleAtom atom);
797 bool checkFunctionDefinition(HandlePropertyName funName, Node* pn, FunctionSyntaxKind kind,
798 bool* pbodyProcessed);
799 bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
800 bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
801
802 bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
803 ParseNodeKind headKind);
804 bool checkForHeadConstInitializers(Node pn1);
805
806 // Use when the current token is TOK_NAME and is known to be 'let'.
807 bool shouldParseLetDeclaration(bool* parseDeclOut);
808
809 // Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
810 // let declaration should be parsed, the TOK_NAME token of 'let' is
811 // consumed. Otherwise, the current token remains the TOK_NAME token of
812 // 'let'.
813 bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
814
815 public:
816 enum FunctionCallBehavior {
817 PermitAssignmentToFunctionCalls,
818 ForbidAssignmentToFunctionCalls
819 };
820
821 bool isValidSimpleAssignmentTarget(Node node,
822 FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
823
824 private:
825 bool reportIfArgumentsEvalTarget(Node nameNode);
826 bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor);
827
828 bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor);
829
830 bool checkStrictAssignment(Node lhs);
831
832 bool checkStrictBinding(PropertyName* name, Node pn);
833 bool defineArg(Node funcpn, HandlePropertyName name,
834 bool disallowDuplicateArgs = false, Node* duplicatedArg = nullptr);
835 Node pushLexicalScope(AutoPushStmtInfoPC& stmt);
836 Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, AutoPushStmtInfoPC& stmt);
837 Node pushLetScope(Handle<StaticBlockObject*> blockObj, AutoPushStmtInfoPC& stmt);
838 bool noteNameUse(HandlePropertyName name, Node pn);
839 Node propertyName(YieldHandling yieldHandling, Node propList,
840 PropertyType* propType, MutableHandleAtom propAtom);
841 Node computedPropertyName(YieldHandling yieldHandling, Node literal);
842 Node arrayInitializer(YieldHandling yieldHandling);
843 Node newRegExp();
844
845 Node objectLiteral(YieldHandling yieldHandling);
846
847 bool checkAndPrepareLexical(bool isConst, const TokenPos& errorPos);
848 Node makeInitializedLexicalBinding(HandlePropertyName name, bool isConst, const TokenPos& pos);
849
850 Node newBindingNode(PropertyName* name, bool functionScope, VarContext varContext = HoistVars);
851
852 // Top-level entrypoint into destructuring pattern checking/name-analyzing.
853 bool checkDestructuringPattern(BindData<ParseHandler>* data, Node pattern);
854
855 // Recursive methods for checking/name-analyzing subcomponents of a
856 // destructuring pattern. The array/object methods *must* be passed arrays
857 // or objects. The name method may be passed anything but will report an
858 // error if not passed a name.
859 bool checkDestructuringArray(BindData<ParseHandler>* data, Node arrayPattern);
860 bool checkDestructuringObject(BindData<ParseHandler>* data, Node objectPattern);
861 bool checkDestructuringName(BindData<ParseHandler>* data, Node expr);
862
863 bool bindInitialized(BindData<ParseHandler>* data, Node pn);
864 bool bindUninitialized(BindData<ParseHandler>* data, Node pn);
865 bool makeSetCall(Node node, unsigned errnum);
866 Node cloneDestructuringDefault(Node opn);
867 Node cloneLeftHandSide(Node opn);
868 Node cloneParseTree(Node opn);
869
newNumber(const Token & tok)870 Node newNumber(const Token& tok) {
871 return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
872 }
873
874 static bool
875 bindDestructuringArg(BindData<ParseHandler>* data,
876 HandlePropertyName name, Parser<ParseHandler>* parser);
877
878 static bool
879 bindLexical(BindData<ParseHandler>* data,
880 HandlePropertyName name, Parser<ParseHandler>* parser);
881
882 static bool
883 bindVar(BindData<ParseHandler>* data,
884 HandlePropertyName name, Parser<ParseHandler>* parser);
885
null()886 static Node null() { return ParseHandler::null(); }
887
888 bool reportRedeclaration(Node pn, Definition::Kind redeclKind, HandlePropertyName name);
889 bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
890 DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler>* pc, JSAtom* atom);
891
892 bool leaveFunction(Node fn, ParseContext<ParseHandler>* outerpc,
893 FunctionSyntaxKind kind = Expression);
894
pos()895 TokenPos pos() const { return tokenStream.currentToken().pos; }
896
897 bool asmJS(Node list);
898
899 void addTelemetry(JSCompartment::DeprecatedLanguageExtension e);
900
901 bool warnOnceAboutExprClosure();
902
903 friend class LegacyCompExprTransplanter;
904 friend struct BindData<ParseHandler>;
905 };
906
907 } /* namespace frontend */
908 } /* namespace js */
909
910 /*
911 * Convenience macro to access Parser.tokenStream as a pointer.
912 */
913 #define TS(p) (&(p)->tokenStream)
914
915 #endif /* frontend_Parser_h */
916