Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
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_ParseContext_h
8
#define frontend_ParseContext_h
9
10
#include "ds/Nestable.h"
11
#include "frontend/BytecodeCompiler.h"
12
#include "frontend/CompilationInfo.h"
13
#include "frontend/ErrorReporter.h"
14
#include "frontend/FunctionTree.h"
15
#include "frontend/NameCollections.h"
16
#include "frontend/SharedContext.h"
17
#include "frontend/UsedNameTracker.h"
18
19
namespace js {
20
21
namespace frontend {
22
23
class ParserBase;
24
25
const char* DeclarationKindString(DeclarationKind kind);
26
27
// Returns true if the declaration is `var` or equivalent.
28
bool DeclarationKindIsVar(DeclarationKind kind);
29
30
bool DeclarationKindIsParameter(DeclarationKind kind);
31
32
class FunctionTree;
33
class FunctionTreeHolder;
34
35
/*
36
* The struct ParseContext stores information about the current parsing context,
37
* which is part of the parser state (see the field Parser::pc). The current
38
* parsing context is either the global context, or the function currently being
39
* parsed. When the parser encounters a function definition, it creates a new
40
* ParseContext, makes it the new current context.
41
*/
42
class ParseContext : public Nestable<ParseContext> {
43
public:
44
// The intra-function statement stack.
45
//
46
// Used for early error checking that depend on the nesting structure of
47
// statements, such as continue/break targets, labels, and unbraced
48
// lexical declarations.
49
class Statement : public Nestable<Statement> {
50
StatementKind kind_;
51
52
public:
53
using Nestable<Statement>::enclosing;
54
using Nestable<Statement>::findNearest;
55
56
Statement(ParseContext* pc, StatementKind kind)
57
: Nestable<Statement>(&pc->innermostStatement_), kind_(kind) {}
58
59
template <typename T>
60
inline bool is() const;
61
template <typename T>
62
inline T& as();
63
64
StatementKind kind() const { return kind_; }
65
66
void refineForKind(StatementKind newForKind) {
67
MOZ_ASSERT(kind_ == StatementKind::ForLoop);
68
MOZ_ASSERT(newForKind == StatementKind::ForInLoop ||
69
newForKind == StatementKind::ForOfLoop);
70
kind_ = newForKind;
71
}
72
};
73
74
class LabelStatement : public Statement {
75
RootedAtom label_;
76
77
public:
78
LabelStatement(ParseContext* pc, JSAtom* label)
79
: Statement(pc, StatementKind::Label), label_(pc->sc_->cx_, label) {}
80
81
HandleAtom label() const { return label_; }
82
};
83
84
struct ClassStatement : public Statement {
85
FunctionBox* constructorBox;
86
87
explicit ClassStatement(ParseContext* pc)
88
: Statement(pc, StatementKind::Class), constructorBox(nullptr) {}
89
};
90
91
// The intra-function scope stack.
92
//
93
// Tracks declared and used names within a scope.
94
class Scope : public Nestable<Scope> {
95
// Names declared in this scope. Corresponds to the union of
96
// VarDeclaredNames and LexicallyDeclaredNames in the ES spec.
97
//
98
// A 'var' declared name is a member of the declared name set of every
99
// scope in its scope contour.
100
//
101
// A lexically declared name is a member only of the declared name set of
102
// the scope in which it is declared.
103
PooledMapPtr<DeclaredNameMap> declared_;
104
105
// FunctionBoxes in this scope that need to be considered for Annex
106
// B.3.3 semantics. This is checked on Scope exit, as by then we have
107
// all the declared names and would know if Annex B.3.3 is applicable.
108
using FunctionBoxVector = Vector<FunctionBox*, 24, SystemAllocPolicy>;
109
PooledVectorPtr<FunctionBoxVector> possibleAnnexBFunctionBoxes_;
110
111
// Monotonically increasing id.
112
uint32_t id_;
113
114
bool maybeReportOOM(ParseContext* pc, bool result) {
115
if (!result) {
116
ReportOutOfMemory(pc->sc()->cx_);
117
}
118
return result;
119
}
120
121
public:
122
using DeclaredNamePtr = DeclaredNameMap::Ptr;
123
using AddDeclaredNamePtr = DeclaredNameMap::AddPtr;
124
125
using Nestable<Scope>::enclosing;
126
127
explicit inline Scope(ParserBase* parser);
128
explicit inline Scope(JSContext* cx, ParseContext* pc,
129
UsedNameTracker& usedNames);
130
131
void dump(ParseContext* pc);
132
133
uint32_t id() const { return id_; }
134
135
MOZ_MUST_USE bool init(ParseContext* pc) {
136
if (id_ == UINT32_MAX) {
137
pc->errorReporter_.errorNoOffset(JSMSG_NEED_DIET, js_script_str);
138
return false;
139
}
140
141
return declared_.acquire(pc->sc()->cx_);
142
}
143
144
bool isEmpty() const { return declared_->all().empty(); }
145
146
DeclaredNamePtr lookupDeclaredName(JSAtom* name) {
147
return declared_->lookup(name);
148
}
149
150
AddDeclaredNamePtr lookupDeclaredNameForAdd(JSAtom* name) {
151
return declared_->lookupForAdd(name);
152
}
153
154
MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p,
155
JSAtom* name, DeclarationKind kind,
156
uint32_t pos) {
157
return maybeReportOOM(
158
pc, declared_->add(p, name, DeclaredNameInfo(kind, pos)));
159
}
160
161
// Add a FunctionBox as a possible candidate for Annex B.3.3 semantics.
162
MOZ_MUST_USE bool addPossibleAnnexBFunctionBox(ParseContext* pc,
163
FunctionBox* funbox);
164
165
// Check if the candidate function boxes for Annex B.3.3 should in
166
// fact get Annex B semantics. Checked on Scope exit.
167
MOZ_MUST_USE bool propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc);
168
169
// Add and remove catch parameter names. Used to implement the odd
170
// semantics of catch bodies.
171
bool addCatchParameters(ParseContext* pc, Scope& catchParamScope);
172
void removeCatchParameters(ParseContext* pc, Scope& catchParamScope);
173
174
void useAsVarScope(ParseContext* pc) {
175
MOZ_ASSERT(!pc->varScope_);
176
pc->varScope_ = this;
177
}
178
179
// An iterator for the set of names a scope binds: the set of all
180
// declared names for 'var' scopes, and the set of lexically declared
181
// names for non-'var' scopes.
182
class BindingIter {
183
friend class Scope;
184
185
DeclaredNameMap::Range declaredRange_;
186
mozilla::DebugOnly<uint32_t> count_;
187
bool isVarScope_;
188
189
BindingIter(Scope& scope, bool isVarScope)
190
: declaredRange_(scope.declared_->all()),
191
count_(0),
192
isVarScope_(isVarScope) {
193
settle();
194
}
195
196
void settle() {
197
// Both var and lexically declared names are binding in a var
198
// scope.
199
if (isVarScope_) {
200
return;
201
}
202
203
// Otherwise, pop only lexically declared names are
204
// binding. Pop the range until we find such a name.
205
while (!declaredRange_.empty()) {
206
if (BindingKindIsLexical(kind())) {
207
break;
208
}
209
declaredRange_.popFront();
210
}
211
}
212
213
public:
214
bool done() const { return declaredRange_.empty(); }
215
216
explicit operator bool() const { return !done(); }
217
218
JSAtom* name() {
219
MOZ_ASSERT(!done());
220
return declaredRange_.front().key();
221
}
222
223
DeclarationKind declarationKind() {
224
MOZ_ASSERT(!done());
225
return declaredRange_.front().value()->kind();
226
}
227
228
BindingKind kind() {
229
return DeclarationKindToBindingKind(declarationKind());
230
}
231
232
bool closedOver() {
233
MOZ_ASSERT(!done());
234
return declaredRange_.front().value()->closedOver();
235
}
236
237
void setClosedOver() {
238
MOZ_ASSERT(!done());
239
return declaredRange_.front().value()->setClosedOver();
240
}
241
242
void operator++(int) {
243
MOZ_ASSERT(!done());
244
MOZ_ASSERT(count_ != UINT32_MAX);
245
declaredRange_.popFront();
246
settle();
247
}
248
};
249
250
inline BindingIter bindings(ParseContext* pc);
251
};
252
253
class VarScope : public Scope {
254
public:
255
explicit inline VarScope(ParserBase* parser);
256
explicit inline VarScope(JSContext* cx, ParseContext* pc,
257
UsedNameTracker& usedNames);
258
};
259
260
private:
261
// Not all contexts are Function contexts, hence the maybe
262
mozilla::Maybe<AutoPushTree> tree;
263
264
// Trace logging of parsing time.
265
AutoFrontendTraceLog traceLog_;
266
267
// Context shared between parsing and bytecode generation.
268
SharedContext* sc_;
269
270
// A mechanism used for error reporting.
271
ErrorReporter& errorReporter_;
272
273
// The innermost statement, i.e., top of the statement stack.
274
Statement* innermostStatement_;
275
276
// The innermost scope, i.e., top of the scope stack.
277
//
278
// The outermost scope in the stack is usually varScope_. In the case of
279
// functions, the outermost scope is functionScope_, which may be
280
// varScope_. See comment above functionScope_.
281
Scope* innermostScope_;
282
283
// If isFunctionBox() and the function is a named lambda, the DeclEnv
284
// scope for named lambdas.
285
mozilla::Maybe<Scope> namedLambdaScope_;
286
287
// If isFunctionBox(), the scope for the function. If there are no
288
// parameter expressions, this is scope for the entire function. If there
289
// are parameter expressions, this holds the special function names
290
// ('.this', 'arguments') and the formal parameters.
291
mozilla::Maybe<Scope> functionScope_;
292
293
// The body-level scope. This always exists, but not necessarily at the
294
// beginning of parsing the script in the case of functions with parameter
295
// expressions.
296
Scope* varScope_;
297
298
// Simple formal parameter names, in order of appearance. Only used when
299
// isFunctionBox().
300
PooledVectorPtr<AtomVector> positionalFormalParameterNames_;
301
302
// Closed over binding names, in order of appearance. Null-delimited
303
// between scopes. Only used when syntax parsing.
304
PooledVectorPtr<AtomVector> closedOverBindingsForLazy_;
305
306
public:
307
// All inner FunctionBoxes in this context. Only used when syntax parsing.
308
// The FunctionBoxes are traced as part of the TraceList on the parser,
309
// (see TraceListNode::TraceList)
310
FunctionBoxVector innerFunctionBoxesForLazy;
311
312
// In a function context, points to a Directive struct that can be updated
313
// to reflect new directives encountered in the Directive Prologue that
314
// require reparsing the function. In global/module/generator-tail contexts,
315
// we don't need to reparse when encountering a DirectivePrologue so this
316
// pointer may be nullptr.
317
Directives* newDirectives;
318
319
// lastYieldOffset stores the offset of the last yield that was parsed.
320
// NoYieldOffset is its initial value.
321
static const uint32_t NoYieldOffset = UINT32_MAX;
322
uint32_t lastYieldOffset;
323
324
// lastAwaitOffset stores the offset of the last await that was parsed.
325
// NoAwaitOffset is its initial value.
326
static const uint32_t NoAwaitOffset = UINT32_MAX;
327
uint32_t lastAwaitOffset;
328
329
private:
330
// Monotonically increasing id.
331
uint32_t scriptId_;
332
333
// Set when compiling a function using Parser::standaloneFunctionBody via
334
// the Function or Generator constructor.
335
bool isStandaloneFunctionBody_;
336
337
// Set when encountering a super.property inside a method. We need to mark
338
// the nearest super scope as needing a home object.
339
bool superScopeNeedsHomeObject_;
340
341
public:
342
ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
343
ErrorReporter& errorReporter, CompilationInfo& compilationInfo,
344
Directives* newDirectives, bool isFull);
345
346
MOZ_MUST_USE bool init();
347
348
SharedContext* sc() { return sc_; }
349
350
// `true` if we are in the body of a function definition.
351
bool isFunctionBox() const { return sc_->isFunctionBox(); }
352
353
FunctionBox* functionBox() { return sc_->asFunctionBox(); }
354
355
Statement* innermostStatement() { return innermostStatement_; }
356
357
Scope* innermostScope() {
358
// There is always at least one scope: the 'var' scope.
359
MOZ_ASSERT(innermostScope_);
360
return innermostScope_;
361
}
362
363
Scope& namedLambdaScope() {
364
MOZ_ASSERT(functionBox()->isNamedLambda());
365
return *namedLambdaScope_;
366
}
367
368
Scope& functionScope() {
369
MOZ_ASSERT(isFunctionBox());
370
return *functionScope_;
371
}
372
373
Scope& varScope() {
374
MOZ_ASSERT(varScope_);
375
return *varScope_;
376
}
377
378
bool isFunctionExtraBodyVarScopeInnermost() {
379
return isFunctionBox() && functionBox()->hasParameterExprs &&
380
innermostScope() == varScope_;
381
}
382
383
template <typename Predicate /* (Statement*) -> bool */>
384
Statement* findInnermostStatement(Predicate predicate) {
385
return Statement::findNearest(innermostStatement_, predicate);
386
}
387
388
template <typename T, typename Predicate /* (Statement*) -> bool */>
389
T* findInnermostStatement(Predicate predicate) {
390
return Statement::findNearest<T>(innermostStatement_, predicate);
391
}
392
393
template <typename T>
394
T* findInnermostStatement() {
395
return Statement::findNearest<T>(innermostStatement_);
396
}
397
398
AtomVector& positionalFormalParameterNames() {
399
return *positionalFormalParameterNames_;
400
}
401
402
AtomVector& closedOverBindingsForLazy() {
403
return *closedOverBindingsForLazy_;
404
}
405
406
enum class BreakStatementError {
407
// Unlabeled break must be inside loop or switch.
408
ToughBreak,
409
LabelNotFound,
410
};
411
412
// Return Err(true) if we have encountered at least one loop,
413
// Err(false) otherwise.
414
MOZ_MUST_USE inline JS::Result<Ok, BreakStatementError> checkBreakStatement(
415
PropertyName* label);
416
417
enum class ContinueStatementError {
418
NotInALoop,
419
LabelNotFound,
420
};
421
MOZ_MUST_USE inline JS::Result<Ok, ContinueStatementError>
422
checkContinueStatement(PropertyName* label);
423
424
// True if we are at the topmost level of a entire script or function body.
425
// For example, while parsing this code we would encounter f1 and f2 at
426
// body level, but we would not encounter f3 or f4 at body level:
427
//
428
// function f1() { function f2() { } }
429
// if (cond) { function f3() { if (cond) { function f4() { } } } }
430
//
431
bool atBodyLevel() { return !innermostStatement_; }
432
433
bool atGlobalLevel() { return atBodyLevel() && sc_->isGlobalContext(); }
434
435
// True if we are at the topmost level of a module only.
436
bool atModuleLevel() { return atBodyLevel() && sc_->isModuleContext(); }
437
438
// True if we are at the topmost level of an entire script or module. For
439
// example, in the comment on |atBodyLevel()| above, we would encounter |f1|
440
// and the outermost |if (cond)| at top level, and everything else would not
441
// be at top level.
442
bool atTopLevel() { return atBodyLevel() && sc_->isTopLevelContext(); }
443
444
void setIsStandaloneFunctionBody() { isStandaloneFunctionBody_ = true; }
445
446
bool isStandaloneFunctionBody() const { return isStandaloneFunctionBody_; }
447
448
void setSuperScopeNeedsHomeObject() {
449
MOZ_ASSERT(sc_->allowSuperProperty());
450
superScopeNeedsHomeObject_ = true;
451
}
452
453
bool superScopeNeedsHomeObject() const { return superScopeNeedsHomeObject_; }
454
455
bool useAsmOrInsideUseAsm() const {
456
return sc_->isFunctionBox() && sc_->asFunctionBox()->useAsmOrInsideUseAsm();
457
}
458
459
// A generator is marked as a generator before its body is parsed.
460
GeneratorKind generatorKind() const {
461
return sc_->isFunctionBox() ? sc_->asFunctionBox()->generatorKind()
462
: GeneratorKind::NotGenerator;
463
}
464
465
bool isGenerator() const {
466
return generatorKind() == GeneratorKind::Generator;
467
}
468
469
bool isAsync() const {
470
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
471
}
472
473
bool needsDotGeneratorName() const { return isGenerator() || isAsync(); }
474
475
FunctionAsyncKind asyncKind() const {
476
return isAsync() ? FunctionAsyncKind::AsyncFunction
477
: FunctionAsyncKind::SyncFunction;
478
}
479
480
bool isArrowFunction() const {
481
return sc_->isFunctionBox() && sc_->asFunctionBox()->isArrow();
482
}
483
484
bool isMethod() const {
485
return sc_->isFunctionBox() && sc_->asFunctionBox()->isMethod();
486
}
487
488
bool isGetterOrSetter() const {
489
return sc_->isFunctionBox() && (sc_->asFunctionBox()->isGetter() ||
490
sc_->asFunctionBox()->isSetter());
491
}
492
493
uint32_t scriptId() const { return scriptId_; }
494
495
bool annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox);
496
497
bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
498
uint32_t beginPos,
499
mozilla::Maybe<DeclarationKind>* redeclaredKind,
500
uint32_t* prevPos);
501
502
bool hasUsedName(const UsedNameTracker& usedNames, HandlePropertyName name);
503
bool hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
504
HandlePropertyName name);
505
506
bool declareFunctionThis(const UsedNameTracker& usedNames,
507
bool canSkipLazyClosedOverBindings);
508
bool declareFunctionArgumentsObject(const UsedNameTracker& usedNames,
509
bool canSkipLazyClosedOverBindings);
510
bool declareDotGeneratorName();
511
512
private:
513
mozilla::Maybe<DeclarationKind> isVarRedeclaredInInnermostScope(
514
HandlePropertyName name, DeclarationKind kind);
515
mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
516
DeclarationKind kind);
517
518
enum DryRunOption { NotDryRun, DryRunInnermostScopeOnly };
519
template <DryRunOption dryRunOption>
520
bool tryDeclareVarHelper(HandlePropertyName name, DeclarationKind kind,
521
uint32_t beginPos,
522
mozilla::Maybe<DeclarationKind>* redeclaredKind,
523
uint32_t* prevPos);
524
};
525
526
} // namespace frontend
527
528
} // namespace js
529
530
#endif // frontend_ParseContext_h