mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Bug 1377272 - Making ParserContext less intertwined with Parser;r=shu+381259
To implement the BinJS decoder of Bug 1377007, we need to access ParserContext without a Parser. This patch makes it possible to construct one. MozReview-Commit-ID: Fx3S0UkU7Hq --HG-- extra : rebase_source : 7470b03fb45bd8d80ffd66b1507d1491b5e3158f
This commit is contained in:
parent
436186d6f8
commit
164c1cbbcd
@ -14,6 +14,7 @@
|
||||
|
||||
#include "builtin/ModuleObject.h"
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
#include "frontend/ErrorReporter.h"
|
||||
#include "frontend/FoldConstants.h"
|
||||
#include "frontend/NameFunctions.h"
|
||||
#include "frontend/Parser.h"
|
||||
@ -107,21 +108,21 @@ AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextI
|
||||
#endif
|
||||
|
||||
AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream)
|
||||
const ErrorReporter& errorReporter)
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
: logger_(TraceLoggerForCurrentThread(cx))
|
||||
{
|
||||
// If the tokenizer hasn't yet gotten any tokens, use the line and column
|
||||
// numbers from CompileOptions.
|
||||
uint32_t line, column;
|
||||
if (tokenStream.isCurrentTokenType(TOK_EOF) && !tokenStream.isEOF()) {
|
||||
line = tokenStream.options().lineno;
|
||||
column = tokenStream.options().column;
|
||||
if (errorReporter.hasTokenizationStarted()) {
|
||||
line = errorReporter.options().lineno;
|
||||
column = errorReporter.options().column;
|
||||
} else {
|
||||
uint32_t offset = tokenStream.currentToken().pos.begin;
|
||||
tokenStream.srcCoords.lineNumAndColumnIndex(offset, &line, &column);
|
||||
uint32_t offset = errorReporter.offset();
|
||||
errorReporter.lineNumAndColumnIndex(offset, &line, &column);
|
||||
}
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, tokenStream.getFilename(), line, column);
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(), line, column);
|
||||
frontendLog_.emplace(logger_, *frontendEvent_);
|
||||
typeLog_.emplace(logger_, id);
|
||||
}
|
||||
@ -130,12 +131,12 @@ AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextI
|
||||
#endif
|
||||
|
||||
AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream,
|
||||
const ErrorReporter& errorReporter,
|
||||
FunctionBox* funbox)
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
: logger_(TraceLoggerForCurrentThread(cx))
|
||||
{
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, tokenStream.getFilename(),
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(),
|
||||
funbox->startLine, funbox->startColumn);
|
||||
frontendLog_.emplace(logger_, *frontendEvent_);
|
||||
typeLog_.emplace(logger_, id);
|
||||
@ -145,13 +146,13 @@ AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextI
|
||||
#endif
|
||||
|
||||
AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream, ParseNode* pn)
|
||||
const ErrorReporter& errorReporter, ParseNode* pn)
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
: logger_(TraceLoggerForCurrentThread(cx))
|
||||
{
|
||||
uint32_t line, column;
|
||||
tokenStream.srcCoords.lineNumAndColumnIndex(pn->pn_pos.begin, &line, &column);
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, tokenStream.getFilename(), line, column);
|
||||
errorReporter.lineNumAndColumnIndex(pn->pn_pos.begin, &line, &column);
|
||||
frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(), line, column);
|
||||
frontendLog_.emplace(logger_, *frontendEvent_);
|
||||
typeLog_.emplace(logger_, id);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class ScriptSourceObject;
|
||||
|
||||
namespace frontend {
|
||||
|
||||
class TokenStreamAnyChars;
|
||||
class ErrorReporter;
|
||||
class FunctionBox;
|
||||
class ParseNode;
|
||||
|
||||
@ -143,13 +143,13 @@ class MOZ_STACK_CLASS AutoFrontendTraceLog
|
||||
const char* filename, size_t line, size_t column);
|
||||
|
||||
AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream);
|
||||
const ErrorReporter& reporter);
|
||||
|
||||
AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream, FunctionBox* funbox);
|
||||
const ErrorReporter& reporter, FunctionBox* funbox);
|
||||
|
||||
AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
|
||||
const TokenStreamAnyChars& tokenStream, ParseNode* pn);
|
||||
const ErrorReporter& reporter, ParseNode* pn);
|
||||
};
|
||||
|
||||
} /* namespace frontend */
|
||||
|
21
js/src/frontend/ErrorReporter.h
Normal file
21
js/src/frontend/ErrorReporter.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef frontend_ErrorReporter_h
|
||||
#define frontend_ErrorReporter_h
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
class ErrorReporter
|
||||
{
|
||||
public:
|
||||
virtual const ReadOnlyCompileOptions& options() const = 0;
|
||||
virtual void lineNumAndColumnIndex(size_t offset, uint32_t* line, uint32_t* column) const = 0;
|
||||
virtual size_t offset() const = 0;
|
||||
virtual bool hasTokenizationStarted() const = 0;
|
||||
virtual void reportErrorNoOffset(unsigned errorNumber, ...) = 0;
|
||||
virtual const char* getFilename() const = 0;
|
||||
};
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace js
|
||||
|
||||
#endif // frontend_ErrorReporter_h
|
689
js/src/frontend/ParseContext.h
Normal file
689
js/src/frontend/ParseContext.h
Normal file
@ -0,0 +1,689 @@
|
||||
#ifndef frontend_ParseContext_h
|
||||
#define frontend_ParseContext_h
|
||||
|
||||
#include "frontend/ErrorReporter.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace frontend {
|
||||
|
||||
class ParserBase;
|
||||
|
||||
// A data structure for tracking used names per parsing session in order to
|
||||
// compute which bindings are closed over. Scripts and scopes are numbered
|
||||
// monotonically in textual order and name uses are tracked by lists of
|
||||
// (script id, scope id) pairs of their use sites.
|
||||
//
|
||||
// Intuitively, in a pair (P,S), P tracks the most nested function that has a
|
||||
// use of u, and S tracks the most nested scope that is still being parsed.
|
||||
//
|
||||
// P is used to answer the question "is u used by a nested function?"
|
||||
// S is used to answer the question "is u used in any scopes currently being
|
||||
// parsed?"
|
||||
//
|
||||
// The algorithm:
|
||||
//
|
||||
// Let Used by a map of names to lists.
|
||||
//
|
||||
// 1. Number all scopes in monotonic increasing order in textual order.
|
||||
// 2. Number all scripts in monotonic increasing order in textual order.
|
||||
// 3. When an identifier u is used in scope numbered S in script numbered P,
|
||||
// and u is found in Used,
|
||||
// a. Append (P,S) to Used[u].
|
||||
// b. Otherwise, assign the the list [(P,S)] to Used[u].
|
||||
// 4. When we finish parsing a scope S in script P, for each declared name d in
|
||||
// Declared(S):
|
||||
// a. If d is found in Used, mark d as closed over if there is a value
|
||||
// (P_d, S_d) in Used[d] such that P_d > P and S_d > S.
|
||||
// b. Remove all values (P_d, S_d) in Used[d] such that S_d are >= S.
|
||||
//
|
||||
// Steps 1 and 2 are implemented by UsedNameTracker::next{Script,Scope}Id.
|
||||
// Step 3 is implemented by UsedNameTracker::noteUsedInScope.
|
||||
// Step 4 is implemented by UsedNameTracker::noteBoundInScope and
|
||||
// Parser::propagateFreeNamesAndMarkClosedOverBindings.
|
||||
class UsedNameTracker
|
||||
{
|
||||
public:
|
||||
struct Use
|
||||
{
|
||||
uint32_t scriptId;
|
||||
uint32_t scopeId;
|
||||
};
|
||||
|
||||
class UsedNameInfo
|
||||
{
|
||||
friend class UsedNameTracker;
|
||||
|
||||
Vector<Use, 6> uses_;
|
||||
|
||||
void resetToScope(uint32_t scriptId, uint32_t scopeId);
|
||||
|
||||
public:
|
||||
explicit UsedNameInfo(JSContext* cx)
|
||||
: uses_(cx)
|
||||
{ }
|
||||
|
||||
UsedNameInfo(UsedNameInfo&& other)
|
||||
: uses_(mozilla::Move(other.uses_))
|
||||
{ }
|
||||
|
||||
bool noteUsedInScope(uint32_t scriptId, uint32_t scopeId) {
|
||||
if (uses_.empty() || uses_.back().scopeId < scopeId)
|
||||
return uses_.append(Use { scriptId, scopeId });
|
||||
return true;
|
||||
}
|
||||
|
||||
void noteBoundInScope(uint32_t scriptId, uint32_t scopeId, bool* closedOver) {
|
||||
*closedOver = false;
|
||||
while (!uses_.empty()) {
|
||||
Use& innermost = uses_.back();
|
||||
if (innermost.scopeId < scopeId)
|
||||
break;
|
||||
if (innermost.scriptId > scriptId)
|
||||
*closedOver = true;
|
||||
uses_.popBack();
|
||||
}
|
||||
}
|
||||
|
||||
bool isUsedInScript(uint32_t scriptId) const {
|
||||
return !uses_.empty() && uses_.back().scriptId >= scriptId;
|
||||
}
|
||||
};
|
||||
|
||||
using UsedNameMap = HashMap<JSAtom*,
|
||||
UsedNameInfo,
|
||||
DefaultHasher<JSAtom*>>;
|
||||
|
||||
private:
|
||||
// The map of names to chains of uses.
|
||||
UsedNameMap map_;
|
||||
|
||||
// Monotonically increasing id for all nested scripts.
|
||||
uint32_t scriptCounter_;
|
||||
|
||||
// Monotonically increasing id for all nested scopes.
|
||||
uint32_t scopeCounter_;
|
||||
|
||||
public:
|
||||
explicit UsedNameTracker(JSContext* cx)
|
||||
: map_(cx),
|
||||
scriptCounter_(0),
|
||||
scopeCounter_(0)
|
||||
{ }
|
||||
|
||||
MOZ_MUST_USE bool init() {
|
||||
return map_.init();
|
||||
}
|
||||
|
||||
uint32_t nextScriptId() {
|
||||
MOZ_ASSERT(scriptCounter_ != UINT32_MAX,
|
||||
"ParseContext::Scope::init should have prevented wraparound");
|
||||
return scriptCounter_++;
|
||||
}
|
||||
|
||||
uint32_t nextScopeId() {
|
||||
MOZ_ASSERT(scopeCounter_ != UINT32_MAX);
|
||||
return scopeCounter_++;
|
||||
}
|
||||
|
||||
UsedNameMap::Ptr lookup(JSAtom* name) const {
|
||||
return map_.lookup(name);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool noteUse(JSContext* cx, JSAtom* name,
|
||||
uint32_t scriptId, uint32_t scopeId);
|
||||
|
||||
struct RewindToken
|
||||
{
|
||||
private:
|
||||
friend class UsedNameTracker;
|
||||
uint32_t scriptId;
|
||||
uint32_t scopeId;
|
||||
};
|
||||
|
||||
RewindToken getRewindToken() const {
|
||||
RewindToken token;
|
||||
token.scriptId = scriptCounter_;
|
||||
token.scopeId = scopeCounter_;
|
||||
return token;
|
||||
}
|
||||
|
||||
// Resets state so that scriptId and scopeId are the innermost script and
|
||||
// scope, respectively. Used for rewinding state on syntax parse failure.
|
||||
void rewind(RewindToken token);
|
||||
|
||||
// Resets state to beginning of compilation.
|
||||
void reset() {
|
||||
map_.clear();
|
||||
RewindToken token;
|
||||
token.scriptId = 0;
|
||||
token.scopeId = 0;
|
||||
rewind(token);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The struct ParseContext stores information about the current parsing context,
|
||||
* which is part of the parser state (see the field Parser::pc). The current
|
||||
* parsing context is either the global context, or the function currently being
|
||||
* parsed. When the parser encounters a function definition, it creates a new
|
||||
* ParseContext, makes it the new current context.
|
||||
*/
|
||||
class ParseContext : public Nestable<ParseContext>
|
||||
{
|
||||
public:
|
||||
// The intra-function statement stack.
|
||||
//
|
||||
// Used for early error checking that depend on the nesting structure of
|
||||
// statements, such as continue/break targets, labels, and unbraced
|
||||
// lexical declarations.
|
||||
class Statement : public Nestable<Statement>
|
||||
{
|
||||
StatementKind kind_;
|
||||
|
||||
public:
|
||||
using Nestable<Statement>::enclosing;
|
||||
using Nestable<Statement>::findNearest;
|
||||
|
||||
Statement(ParseContext* pc, StatementKind kind)
|
||||
: Nestable<Statement>(&pc->innermostStatement_),
|
||||
kind_(kind)
|
||||
{ }
|
||||
|
||||
template <typename T> inline bool is() const;
|
||||
template <typename T> inline T& as();
|
||||
|
||||
StatementKind kind() const {
|
||||
return kind_;
|
||||
}
|
||||
|
||||
void refineForKind(StatementKind newForKind) {
|
||||
MOZ_ASSERT(kind_ == StatementKind::ForLoop);
|
||||
MOZ_ASSERT(newForKind == StatementKind::ForInLoop ||
|
||||
newForKind == StatementKind::ForOfLoop);
|
||||
kind_ = newForKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LabelStatement : public Statement
|
||||
{
|
||||
RootedAtom label_;
|
||||
|
||||
public:
|
||||
LabelStatement(ParseContext* pc, JSAtom* label)
|
||||
: Statement(pc, StatementKind::Label),
|
||||
label_(pc->sc_->context, label)
|
||||
{ }
|
||||
|
||||
HandleAtom label() const {
|
||||
return label_;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassStatement : public Statement
|
||||
{
|
||||
FunctionBox* constructorBox;
|
||||
|
||||
explicit ClassStatement(ParseContext* pc)
|
||||
: Statement(pc, StatementKind::Class),
|
||||
constructorBox(nullptr)
|
||||
{ }
|
||||
};
|
||||
|
||||
// The intra-function scope stack.
|
||||
//
|
||||
// Tracks declared and used names within a scope.
|
||||
class Scope : public Nestable<Scope>
|
||||
{
|
||||
// Names declared in this scope. Corresponds to the union of
|
||||
// VarDeclaredNames and LexicallyDeclaredNames in the ES spec.
|
||||
//
|
||||
// A 'var' declared name is a member of the declared name set of every
|
||||
// scope in its scope contour.
|
||||
//
|
||||
// A lexically declared name is a member only of the declared name set of
|
||||
// the scope in which it is declared.
|
||||
PooledMapPtr<DeclaredNameMap> declared_;
|
||||
|
||||
// FunctionBoxes in this scope that need to be considered for Annex
|
||||
// B.3.3 semantics. This is checked on Scope exit, as by then we have
|
||||
// all the declared names and would know if Annex B.3.3 is applicable.
|
||||
PooledVectorPtr<FunctionBoxVector> possibleAnnexBFunctionBoxes_;
|
||||
|
||||
// Monotonically increasing id.
|
||||
uint32_t id_;
|
||||
|
||||
bool maybeReportOOM(ParseContext* pc, bool result) {
|
||||
if (!result)
|
||||
ReportOutOfMemory(pc->sc()->context);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
using DeclaredNamePtr = DeclaredNameMap::Ptr;
|
||||
using AddDeclaredNamePtr = DeclaredNameMap::AddPtr;
|
||||
|
||||
using Nestable<Scope>::enclosing;
|
||||
|
||||
explicit inline Scope(ParserBase* parser);
|
||||
explicit inline Scope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames);
|
||||
|
||||
void dump(ParseContext* pc);
|
||||
|
||||
uint32_t id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool init(ParseContext* pc) {
|
||||
if (id_ == UINT32_MAX) {
|
||||
pc->errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
return declared_.acquire(pc->sc()->context);
|
||||
}
|
||||
|
||||
DeclaredNamePtr lookupDeclaredName(JSAtom* name) {
|
||||
return declared_->lookup(name);
|
||||
}
|
||||
|
||||
AddDeclaredNamePtr lookupDeclaredNameForAdd(JSAtom* name) {
|
||||
return declared_->lookupForAdd(name);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p, JSAtom* name,
|
||||
DeclarationKind kind, uint32_t pos)
|
||||
{
|
||||
return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind, pos)));
|
||||
}
|
||||
|
||||
// Add a FunctionBox as a possible candidate for Annex B.3.3 semantics.
|
||||
MOZ_MUST_USE bool addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox);
|
||||
|
||||
// Check if the candidate function boxes for Annex B.3.3 should in
|
||||
// fact get Annex B semantics. Checked on Scope exit.
|
||||
MOZ_MUST_USE bool propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc);
|
||||
|
||||
// Add and remove catch parameter names. Used to implement the odd
|
||||
// semantics of catch bodies.
|
||||
bool addCatchParameters(ParseContext* pc, Scope& catchParamScope);
|
||||
void removeCatchParameters(ParseContext* pc, Scope& catchParamScope);
|
||||
|
||||
void useAsVarScope(ParseContext* pc) {
|
||||
MOZ_ASSERT(!pc->varScope_);
|
||||
pc->varScope_ = this;
|
||||
}
|
||||
|
||||
// An iterator for the set of names a scope binds: the set of all
|
||||
// declared names for 'var' scopes, and the set of lexically declared
|
||||
// names for non-'var' scopes.
|
||||
class BindingIter
|
||||
{
|
||||
friend class Scope;
|
||||
|
||||
DeclaredNameMap::Range declaredRange_;
|
||||
mozilla::DebugOnly<uint32_t> count_;
|
||||
bool isVarScope_;
|
||||
|
||||
BindingIter(Scope& scope, bool isVarScope)
|
||||
: declaredRange_(scope.declared_->all()),
|
||||
count_(0),
|
||||
isVarScope_(isVarScope)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
void settle() {
|
||||
// Both var and lexically declared names are binding in a var
|
||||
// scope.
|
||||
if (isVarScope_)
|
||||
return;
|
||||
|
||||
// Otherwise, pop only lexically declared names are
|
||||
// binding. Pop the range until we find such a name.
|
||||
while (!declaredRange_.empty()) {
|
||||
if (BindingKindIsLexical(kind()))
|
||||
break;
|
||||
declaredRange_.popFront();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool done() const {
|
||||
return declaredRange_.empty();
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return !done();
|
||||
}
|
||||
|
||||
JSAtom* name() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().key();
|
||||
}
|
||||
|
||||
DeclarationKind declarationKind() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->kind();
|
||||
}
|
||||
|
||||
BindingKind kind() {
|
||||
return DeclarationKindToBindingKind(declarationKind());
|
||||
}
|
||||
|
||||
bool closedOver() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->closedOver();
|
||||
}
|
||||
|
||||
void setClosedOver() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->setClosedOver();
|
||||
}
|
||||
|
||||
void operator++(int) {
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(count_ != UINT32_MAX);
|
||||
declaredRange_.popFront();
|
||||
settle();
|
||||
}
|
||||
};
|
||||
|
||||
inline BindingIter bindings(ParseContext* pc);
|
||||
};
|
||||
|
||||
class VarScope : public Scope
|
||||
{
|
||||
public:
|
||||
explicit inline VarScope(ParserBase* parser);
|
||||
};
|
||||
|
||||
private:
|
||||
// Trace logging of parsing time.
|
||||
AutoFrontendTraceLog traceLog_;
|
||||
|
||||
// Context shared between parsing and bytecode generation.
|
||||
SharedContext* sc_;
|
||||
|
||||
// A mechanism used for error reporting.
|
||||
ErrorReporter& errorReporter_;
|
||||
|
||||
// The innermost statement, i.e., top of the statement stack.
|
||||
Statement* innermostStatement_;
|
||||
|
||||
// The innermost scope, i.e., top of the scope stack.
|
||||
//
|
||||
// The outermost scope in the stack is usually varScope_. In the case of
|
||||
// functions, the outermost scope is functionScope_, which may be
|
||||
// varScope_. See comment above functionScope_.
|
||||
Scope* innermostScope_;
|
||||
|
||||
// If isFunctionBox() and the function is a named lambda, the DeclEnv
|
||||
// scope for named lambdas.
|
||||
mozilla::Maybe<Scope> namedLambdaScope_;
|
||||
|
||||
// If isFunctionBox(), the scope for the function. If there are no
|
||||
// parameter expressions, this is scope for the entire function. If there
|
||||
// are parameter expressions, this holds the special function names
|
||||
// ('.this', 'arguments') and the formal parameters.
|
||||
mozilla::Maybe<Scope> functionScope_;
|
||||
|
||||
// The body-level scope. This always exists, but not necessarily at the
|
||||
// beginning of parsing the script in the case of functions with parameter
|
||||
// expressions.
|
||||
Scope* varScope_;
|
||||
|
||||
// Simple formal parameter names, in order of appearance. Only used when
|
||||
// isFunctionBox().
|
||||
PooledVectorPtr<AtomVector> positionalFormalParameterNames_;
|
||||
|
||||
// Closed over binding names, in order of appearance. Null-delimited
|
||||
// between scopes. Only used when syntax parsing.
|
||||
PooledVectorPtr<AtomVector> closedOverBindingsForLazy_;
|
||||
|
||||
// Monotonically increasing id.
|
||||
uint32_t scriptId_;
|
||||
|
||||
// Set when compiling a function using Parser::standaloneFunctionBody via
|
||||
// the Function or Generator constructor.
|
||||
bool isStandaloneFunctionBody_;
|
||||
|
||||
// Set when encountering a super.property inside a method. We need to mark
|
||||
// the nearest super scope as needing a home object.
|
||||
bool superScopeNeedsHomeObject_;
|
||||
|
||||
public:
|
||||
// lastYieldOffset stores the offset of the last yield that was parsed.
|
||||
// NoYieldOffset is its initial value.
|
||||
static const uint32_t NoYieldOffset = UINT32_MAX;
|
||||
uint32_t lastYieldOffset;
|
||||
|
||||
// lastAwaitOffset stores the offset of the last await that was parsed.
|
||||
// NoAwaitOffset is its initial value.
|
||||
static const uint32_t NoAwaitOffset = UINT32_MAX;
|
||||
uint32_t lastAwaitOffset;
|
||||
|
||||
// All inner functions in this context. Only used when syntax parsing.
|
||||
Rooted<GCVector<JSFunction*, 8>> innerFunctionsForLazy;
|
||||
|
||||
// In a function context, points to a Directive struct that can be updated
|
||||
// to reflect new directives encountered in the Directive Prologue that
|
||||
// require reparsing the function. In global/module/generator-tail contexts,
|
||||
// we don't need to reparse when encountering a DirectivePrologue so this
|
||||
// pointer may be nullptr.
|
||||
Directives* newDirectives;
|
||||
|
||||
// Set when parsing a function and it has 'return <expr>;'
|
||||
bool funHasReturnExpr;
|
||||
|
||||
// Set when parsing a function and it has 'return;'
|
||||
bool funHasReturnVoid;
|
||||
|
||||
public:
|
||||
inline ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, ErrorReporter& errorReporter,
|
||||
class UsedNameTracker& usedNames, Directives* newDirectives, bool isFull)
|
||||
: Nestable<ParseContext>(&parent),
|
||||
traceLog_(sc->context,
|
||||
isFull
|
||||
? TraceLogger_ParsingFull
|
||||
: TraceLogger_ParsingSyntax,
|
||||
errorReporter),
|
||||
sc_(sc),
|
||||
errorReporter_(errorReporter),
|
||||
innermostStatement_(nullptr),
|
||||
innermostScope_(nullptr),
|
||||
varScope_(nullptr),
|
||||
positionalFormalParameterNames_(cx->frontendCollectionPool()),
|
||||
closedOverBindingsForLazy_(cx->frontendCollectionPool()),
|
||||
scriptId_(usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false),
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
|
||||
newDirectives(newDirectives),
|
||||
funHasReturnExpr(false),
|
||||
funHasReturnVoid(false)
|
||||
{
|
||||
if (isFunctionBox()) {
|
||||
if (functionBox()->function()->isNamedLambda())
|
||||
namedLambdaScope_.emplace(cx, parent, usedNames);
|
||||
functionScope_.emplace(cx, parent, usedNames);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool init();
|
||||
|
||||
SharedContext* sc() {
|
||||
return sc_;
|
||||
}
|
||||
|
||||
bool isFunctionBox() const {
|
||||
return sc_->isFunctionBox();
|
||||
}
|
||||
|
||||
FunctionBox* functionBox() {
|
||||
return sc_->asFunctionBox();
|
||||
}
|
||||
|
||||
Statement* innermostStatement() {
|
||||
return innermostStatement_;
|
||||
}
|
||||
|
||||
Scope* innermostScope() {
|
||||
// There is always at least one scope: the 'var' scope.
|
||||
MOZ_ASSERT(innermostScope_);
|
||||
return innermostScope_;
|
||||
}
|
||||
|
||||
Scope& namedLambdaScope() {
|
||||
MOZ_ASSERT(functionBox()->function()->isNamedLambda());
|
||||
return *namedLambdaScope_;
|
||||
}
|
||||
|
||||
Scope& functionScope() {
|
||||
MOZ_ASSERT(isFunctionBox());
|
||||
return *functionScope_;
|
||||
}
|
||||
|
||||
Scope& varScope() {
|
||||
MOZ_ASSERT(varScope_);
|
||||
return *varScope_;
|
||||
}
|
||||
|
||||
bool isFunctionExtraBodyVarScopeInnermost() {
|
||||
return isFunctionBox() && functionBox()->hasParameterExprs &&
|
||||
innermostScope() == varScope_;
|
||||
}
|
||||
|
||||
template <typename Predicate /* (Statement*) -> bool */>
|
||||
Statement* findInnermostStatement(Predicate predicate) {
|
||||
return Statement::findNearest(innermostStatement_, predicate);
|
||||
}
|
||||
|
||||
template <typename T, typename Predicate /* (Statement*) -> bool */>
|
||||
T* findInnermostStatement(Predicate predicate) {
|
||||
return Statement::findNearest<T>(innermostStatement_, predicate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* findInnermostStatement() {
|
||||
return Statement::findNearest<T>(innermostStatement_);
|
||||
}
|
||||
|
||||
AtomVector& positionalFormalParameterNames() {
|
||||
return *positionalFormalParameterNames_;
|
||||
}
|
||||
|
||||
AtomVector& closedOverBindingsForLazy() {
|
||||
return *closedOverBindingsForLazy_;
|
||||
}
|
||||
|
||||
// True if we are at the topmost level of a entire script or function body.
|
||||
// For example, while parsing this code we would encounter f1 and f2 at
|
||||
// body level, but we would not encounter f3 or f4 at body level:
|
||||
//
|
||||
// function f1() { function f2() { } }
|
||||
// if (cond) { function f3() { if (cond) { function f4() { } } } }
|
||||
//
|
||||
bool atBodyLevel() {
|
||||
return !innermostStatement_;
|
||||
}
|
||||
|
||||
bool atGlobalLevel() {
|
||||
return atBodyLevel() && sc_->isGlobalContext();
|
||||
}
|
||||
|
||||
// True if we are at the topmost level of a module only.
|
||||
bool atModuleLevel() {
|
||||
return atBodyLevel() && sc_->isModuleContext();
|
||||
}
|
||||
|
||||
void setIsStandaloneFunctionBody() {
|
||||
isStandaloneFunctionBody_ = true;
|
||||
}
|
||||
|
||||
bool isStandaloneFunctionBody() const {
|
||||
return isStandaloneFunctionBody_;
|
||||
}
|
||||
|
||||
void setSuperScopeNeedsHomeObject() {
|
||||
MOZ_ASSERT(sc_->allowSuperProperty());
|
||||
superScopeNeedsHomeObject_ = true;
|
||||
}
|
||||
|
||||
bool superScopeNeedsHomeObject() const {
|
||||
return superScopeNeedsHomeObject_;
|
||||
}
|
||||
|
||||
bool useAsmOrInsideUseAsm() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->useAsmOrInsideUseAsm();
|
||||
}
|
||||
|
||||
// Most functions start off being parsed as non-generators.
|
||||
// Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7.
|
||||
// An ES6 generator is marked as a "star generator" before its body is parsed.
|
||||
GeneratorKind generatorKind() const {
|
||||
return sc_->isFunctionBox() ? sc_->asFunctionBox()->generatorKind() : NotGenerator;
|
||||
}
|
||||
|
||||
bool isLegacyGenerator() const {
|
||||
return generatorKind() == LegacyGenerator;
|
||||
}
|
||||
|
||||
bool isStarGenerator() const {
|
||||
return generatorKind() == StarGenerator;
|
||||
}
|
||||
|
||||
bool isAsync() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
|
||||
}
|
||||
|
||||
bool needsDotGeneratorName() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? AsyncFunction : SyncFunction;
|
||||
}
|
||||
|
||||
bool isArrowFunction() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
|
||||
}
|
||||
|
||||
bool isMethod() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
|
||||
}
|
||||
|
||||
bool isGetterOrSetter() const {
|
||||
return sc_->isFunctionBox() && (sc_->asFunctionBox()->function()->isGetter() ||
|
||||
sc_->asFunctionBox()->function()->isSetter());
|
||||
}
|
||||
|
||||
uint32_t scriptId() const {
|
||||
return scriptId_;
|
||||
}
|
||||
|
||||
bool annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox);
|
||||
|
||||
bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
|
||||
mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos);
|
||||
|
||||
private:
|
||||
mozilla::Maybe<DeclarationKind> isVarRedeclaredInInnermostScope(HandlePropertyName name,
|
||||
DeclarationKind kind);
|
||||
mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
|
||||
DeclarationKind kind);
|
||||
|
||||
enum DryRunOption { NotDryRun, DryRunInnermostScopeOnly };
|
||||
template <DryRunOption dryRunOption>
|
||||
bool tryDeclareVarHelper(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
|
||||
mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos);
|
||||
|
||||
};
|
||||
|
||||
} // namespace frontend
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // frontend_ParseContext_h
|
@ -368,7 +368,7 @@ bool
|
||||
ParseContext::init()
|
||||
{
|
||||
if (scriptId_ == UINT32_MAX) {
|
||||
tokenStream_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1010,7 +1010,7 @@ Parser<ParseHandler, CharT>::parse()
|
||||
Directives directives(options().strictOption);
|
||||
GlobalSharedContext globalsc(context, ScopeKind::Global,
|
||||
directives, options().extraWarningsOption);
|
||||
ParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
|
||||
SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
|
||||
if (!globalpc.init())
|
||||
return null();
|
||||
|
||||
@ -2151,7 +2151,7 @@ template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler, char16_t>::evalBody(EvalSharedContext* evalsc)
|
||||
{
|
||||
ParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
|
||||
SourceParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
|
||||
if (!evalpc.init())
|
||||
return nullptr;
|
||||
|
||||
@ -2234,7 +2234,7 @@ template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler, char16_t>::globalBody(GlobalSharedContext* globalsc)
|
||||
{
|
||||
ParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
|
||||
SourceParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
|
||||
if (!globalpc.init())
|
||||
return nullptr;
|
||||
|
||||
@ -2272,7 +2272,7 @@ Parser<FullParseHandler, char16_t>::moduleBody(ModuleSharedContext* modulesc)
|
||||
{
|
||||
MOZ_ASSERT(checkOptionsCalled);
|
||||
|
||||
ParseContext modulepc(this, modulesc, nullptr);
|
||||
SourceParseContext modulepc(this, modulesc, nullptr);
|
||||
if (!modulepc.init())
|
||||
return null();
|
||||
|
||||
@ -2614,7 +2614,7 @@ Parser<FullParseHandler, char16_t>::standaloneFunction(HandleFunction fun,
|
||||
return null();
|
||||
funbox->initStandaloneFunction(enclosingScope);
|
||||
|
||||
ParseContext funpc(this, funbox, newDirectives);
|
||||
SourceParseContext funpc(this, funbox, newDirectives);
|
||||
if (!funpc.init())
|
||||
return null();
|
||||
funpc.setIsStandaloneFunctionBody();
|
||||
@ -3591,11 +3591,11 @@ Parser<ParseHandler, CharT>::innerFunction(Node pn, ParseContext* outerpc, Funct
|
||||
{
|
||||
// Note that it is possible for outerpc != this->pc, as we may be
|
||||
// attempting to syntax parse an inner function from an outer full
|
||||
// parser. In that case, outerpc is a ParseContext from the full parser
|
||||
// parser. In that case, outerpc is a SourceParseContext from the full parser
|
||||
// instead of the current top of the stack of the syntax parser.
|
||||
|
||||
// Push a new ParseContext.
|
||||
ParseContext funpc(this, funbox, newDirectives);
|
||||
SourceParseContext funpc(this, funbox, newDirectives);
|
||||
if (!funpc.init())
|
||||
return false;
|
||||
|
||||
@ -3619,7 +3619,7 @@ Parser<ParseHandler, CharT>::innerFunction(Node pn, ParseContext* outerpc, Handl
|
||||
{
|
||||
// Note that it is possible for outerpc != this->pc, as we may be
|
||||
// attempting to syntax parse an inner function from an outer full
|
||||
// parser. In that case, outerpc is a ParseContext from the full parser
|
||||
// parser. In that case, outerpc is a SourceParseContext from the full parser
|
||||
// instead of the current top of the stack of the syntax parser.
|
||||
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
|
||||
@ -3682,7 +3682,7 @@ Parser<FullParseHandler, char16_t>::standaloneLazyFunction(HandleFunction fun,
|
||||
funbox->initFromLazyFunction();
|
||||
|
||||
Directives newDirectives = directives;
|
||||
ParseContext funpc(this, funbox, &newDirectives);
|
||||
SourceParseContext funpc(this, funbox, &newDirectives);
|
||||
if (!funpc.init())
|
||||
return null();
|
||||
|
||||
@ -8695,7 +8695,7 @@ Parser<ParseHandler, CharT>::generatorComprehensionLambda(unsigned begin)
|
||||
genFunbox->isGenexpLambda = true;
|
||||
genFunbox->initWithEnclosingParseContext(outerpc, Expression);
|
||||
|
||||
ParseContext genpc(this, genFunbox, /* newDirectives = */ nullptr);
|
||||
SourceParseContext genpc(this, genFunbox, /* newDirectives = */ nullptr);
|
||||
if (!genpc.init())
|
||||
return null();
|
||||
genpc.functionScope().useAsVarScope(&genpc);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "frontend/LanguageExtensions.h"
|
||||
#include "frontend/NameAnalysisTypes.h"
|
||||
#include "frontend/NameCollections.h"
|
||||
#include "frontend/ParseContext.h"
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/SyntaxParseHandler.h"
|
||||
|
||||
@ -35,523 +36,15 @@ class ParserBase;
|
||||
|
||||
template <class ParseHandler, typename CharT> class Parser;
|
||||
|
||||
/*
|
||||
* The struct ParseContext stores information about the current parsing context,
|
||||
* which is part of the parser state (see the field Parser::pc). The current
|
||||
* parsing context is either the global context, or the function currently being
|
||||
* parsed. When the parser encounters a function definition, it creates a new
|
||||
* ParseContext, makes it the new current context.
|
||||
*/
|
||||
class ParseContext : public Nestable<ParseContext>
|
||||
class SourceParseContext: public ParseContext
|
||||
{
|
||||
public:
|
||||
// The intra-function statement stack.
|
||||
//
|
||||
// Used for early error checking that depend on the nesting structure of
|
||||
// statements, such as continue/break targets, labels, and unbraced
|
||||
// lexical declarations.
|
||||
class Statement : public Nestable<Statement>
|
||||
{
|
||||
StatementKind kind_;
|
||||
|
||||
public:
|
||||
using Nestable<Statement>::enclosing;
|
||||
using Nestable<Statement>::findNearest;
|
||||
|
||||
Statement(ParseContext* pc, StatementKind kind)
|
||||
: Nestable<Statement>(&pc->innermostStatement_),
|
||||
kind_(kind)
|
||||
{ }
|
||||
|
||||
template <typename T> inline bool is() const;
|
||||
template <typename T> inline T& as();
|
||||
|
||||
StatementKind kind() const {
|
||||
return kind_;
|
||||
}
|
||||
|
||||
void refineForKind(StatementKind newForKind) {
|
||||
MOZ_ASSERT(kind_ == StatementKind::ForLoop);
|
||||
MOZ_ASSERT(newForKind == StatementKind::ForInLoop ||
|
||||
newForKind == StatementKind::ForOfLoop);
|
||||
kind_ = newForKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LabelStatement : public Statement
|
||||
{
|
||||
RootedAtom label_;
|
||||
|
||||
public:
|
||||
LabelStatement(ParseContext* pc, JSAtom* label)
|
||||
: Statement(pc, StatementKind::Label),
|
||||
label_(pc->sc_->context, label)
|
||||
{ }
|
||||
|
||||
HandleAtom label() const {
|
||||
return label_;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassStatement : public Statement
|
||||
{
|
||||
FunctionBox* constructorBox;
|
||||
|
||||
explicit ClassStatement(ParseContext* pc)
|
||||
: Statement(pc, StatementKind::Class),
|
||||
constructorBox(nullptr)
|
||||
{ }
|
||||
};
|
||||
|
||||
// The intra-function scope stack.
|
||||
//
|
||||
// Tracks declared and used names within a scope.
|
||||
class Scope : public Nestable<Scope>
|
||||
{
|
||||
// Names declared in this scope. Corresponds to the union of
|
||||
// VarDeclaredNames and LexicallyDeclaredNames in the ES spec.
|
||||
//
|
||||
// A 'var' declared name is a member of the declared name set of every
|
||||
// scope in its scope contour.
|
||||
//
|
||||
// A lexically declared name is a member only of the declared name set of
|
||||
// the scope in which it is declared.
|
||||
PooledMapPtr<DeclaredNameMap> declared_;
|
||||
|
||||
// FunctionBoxes in this scope that need to be considered for Annex
|
||||
// B.3.3 semantics. This is checked on Scope exit, as by then we have
|
||||
// all the declared names and would know if Annex B.3.3 is applicable.
|
||||
PooledVectorPtr<FunctionBoxVector> possibleAnnexBFunctionBoxes_;
|
||||
|
||||
// Monotonically increasing id.
|
||||
uint32_t id_;
|
||||
|
||||
bool maybeReportOOM(ParseContext* pc, bool result) {
|
||||
if (!result)
|
||||
ReportOutOfMemory(pc->sc()->context);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
using DeclaredNamePtr = DeclaredNameMap::Ptr;
|
||||
using AddDeclaredNamePtr = DeclaredNameMap::AddPtr;
|
||||
|
||||
using Nestable<Scope>::enclosing;
|
||||
|
||||
explicit inline Scope(ParserBase* parser);
|
||||
|
||||
void dump(ParseContext* pc);
|
||||
|
||||
uint32_t id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool init(ParseContext* pc) {
|
||||
if (id_ == UINT32_MAX) {
|
||||
pc->tokenStream_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
return declared_.acquire(pc->sc()->context);
|
||||
}
|
||||
|
||||
DeclaredNamePtr lookupDeclaredName(JSAtom* name) {
|
||||
return declared_->lookup(name);
|
||||
}
|
||||
|
||||
AddDeclaredNamePtr lookupDeclaredNameForAdd(JSAtom* name) {
|
||||
return declared_->lookupForAdd(name);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p, JSAtom* name,
|
||||
DeclarationKind kind, uint32_t pos)
|
||||
{
|
||||
return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind, pos)));
|
||||
}
|
||||
|
||||
// Add a FunctionBox as a possible candidate for Annex B.3.3 semantics.
|
||||
MOZ_MUST_USE bool addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox);
|
||||
|
||||
// Check if the candidate function boxes for Annex B.3.3 should in
|
||||
// fact get Annex B semantics. Checked on Scope exit.
|
||||
MOZ_MUST_USE bool propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc);
|
||||
|
||||
// Add and remove catch parameter names. Used to implement the odd
|
||||
// semantics of catch bodies.
|
||||
bool addCatchParameters(ParseContext* pc, Scope& catchParamScope);
|
||||
void removeCatchParameters(ParseContext* pc, Scope& catchParamScope);
|
||||
|
||||
void useAsVarScope(ParseContext* pc) {
|
||||
MOZ_ASSERT(!pc->varScope_);
|
||||
pc->varScope_ = this;
|
||||
}
|
||||
|
||||
// An iterator for the set of names a scope binds: the set of all
|
||||
// declared names for 'var' scopes, and the set of lexically declared
|
||||
// names for non-'var' scopes.
|
||||
class BindingIter
|
||||
{
|
||||
friend class Scope;
|
||||
|
||||
DeclaredNameMap::Range declaredRange_;
|
||||
mozilla::DebugOnly<uint32_t> count_;
|
||||
bool isVarScope_;
|
||||
|
||||
BindingIter(Scope& scope, bool isVarScope)
|
||||
: declaredRange_(scope.declared_->all()),
|
||||
count_(0),
|
||||
isVarScope_(isVarScope)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
void settle() {
|
||||
// Both var and lexically declared names are binding in a var
|
||||
// scope.
|
||||
if (isVarScope_)
|
||||
return;
|
||||
|
||||
// Otherwise, pop only lexically declared names are
|
||||
// binding. Pop the range until we find such a name.
|
||||
while (!declaredRange_.empty()) {
|
||||
if (BindingKindIsLexical(kind()))
|
||||
break;
|
||||
declaredRange_.popFront();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool done() const {
|
||||
return declaredRange_.empty();
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return !done();
|
||||
}
|
||||
|
||||
JSAtom* name() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().key();
|
||||
}
|
||||
|
||||
DeclarationKind declarationKind() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->kind();
|
||||
}
|
||||
|
||||
BindingKind kind() {
|
||||
return DeclarationKindToBindingKind(declarationKind());
|
||||
}
|
||||
|
||||
bool closedOver() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->closedOver();
|
||||
}
|
||||
|
||||
void setClosedOver() {
|
||||
MOZ_ASSERT(!done());
|
||||
return declaredRange_.front().value()->setClosedOver();
|
||||
}
|
||||
|
||||
void operator++(int) {
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(count_ != UINT32_MAX);
|
||||
declaredRange_.popFront();
|
||||
settle();
|
||||
}
|
||||
};
|
||||
|
||||
inline BindingIter bindings(ParseContext* pc);
|
||||
};
|
||||
|
||||
class VarScope : public Scope
|
||||
{
|
||||
public:
|
||||
explicit inline VarScope(ParserBase* parser);
|
||||
};
|
||||
|
||||
private:
|
||||
// Trace logging of parsing time.
|
||||
AutoFrontendTraceLog traceLog_;
|
||||
|
||||
// Context shared between parsing and bytecode generation.
|
||||
SharedContext* sc_;
|
||||
|
||||
// TokenStream used for error reporting.
|
||||
TokenStreamAnyChars& tokenStream_;
|
||||
|
||||
// The innermost statement, i.e., top of the statement stack.
|
||||
Statement* innermostStatement_;
|
||||
|
||||
// The innermost scope, i.e., top of the scope stack.
|
||||
//
|
||||
// The outermost scope in the stack is usually varScope_. In the case of
|
||||
// functions, the outermost scope is functionScope_, which may be
|
||||
// varScope_. See comment above functionScope_.
|
||||
Scope* innermostScope_;
|
||||
|
||||
// If isFunctionBox() and the function is a named lambda, the DeclEnv
|
||||
// scope for named lambdas.
|
||||
mozilla::Maybe<Scope> namedLambdaScope_;
|
||||
|
||||
// If isFunctionBox(), the scope for the function. If there are no
|
||||
// parameter expressions, this is scope for the entire function. If there
|
||||
// are parameter expressions, this holds the special function names
|
||||
// ('.this', 'arguments') and the formal parameers.
|
||||
mozilla::Maybe<Scope> functionScope_;
|
||||
|
||||
// The body-level scope. This always exists, but not necessarily at the
|
||||
// beginning of parsing the script in the case of functions with parameter
|
||||
// expressions.
|
||||
Scope* varScope_;
|
||||
|
||||
// Simple formal parameter names, in order of appearance. Only used when
|
||||
// isFunctionBox().
|
||||
PooledVectorPtr<AtomVector> positionalFormalParameterNames_;
|
||||
|
||||
// Closed over binding names, in order of appearance. Null-delimited
|
||||
// between scopes. Only used when syntax parsing.
|
||||
PooledVectorPtr<AtomVector> closedOverBindingsForLazy_;
|
||||
|
||||
// Monotonically increasing id.
|
||||
uint32_t scriptId_;
|
||||
|
||||
// Set when compiling a function using Parser::standaloneFunctionBody via
|
||||
// the Function or Generator constructor.
|
||||
bool isStandaloneFunctionBody_;
|
||||
|
||||
// Set when encountering a super.property inside a method. We need to mark
|
||||
// the nearest super scope as needing a home object.
|
||||
bool superScopeNeedsHomeObject_;
|
||||
|
||||
public:
|
||||
// lastYieldOffset stores the offset of the last yield that was parsed.
|
||||
// NoYieldOffset is its initial value.
|
||||
static const uint32_t NoYieldOffset = UINT32_MAX;
|
||||
uint32_t lastYieldOffset;
|
||||
|
||||
// lastAwaitOffset stores the offset of the last await that was parsed.
|
||||
// NoAwaitOffset is its initial value.
|
||||
static const uint32_t NoAwaitOffset = UINT32_MAX;
|
||||
uint32_t lastAwaitOffset;
|
||||
|
||||
// All inner functions in this context. Only used when syntax parsing.
|
||||
Rooted<GCVector<JSFunction*, 8>> innerFunctionsForLazy;
|
||||
|
||||
// In a function context, points to a Directive struct that can be updated
|
||||
// to reflect new directives encountered in the Directive Prologue that
|
||||
// require reparsing the function. In global/module/generator-tail contexts,
|
||||
// we don't need to reparse when encountering a DirectivePrologue so this
|
||||
// pointer may be nullptr.
|
||||
Directives* newDirectives;
|
||||
|
||||
// Set when parsing a function and it has 'return <expr>;'
|
||||
bool funHasReturnExpr;
|
||||
|
||||
// Set when parsing a function and it has 'return;'
|
||||
bool funHasReturnVoid;
|
||||
|
||||
public:
|
||||
template <class ParseHandler, typename CharT>
|
||||
ParseContext(Parser<ParseHandler, CharT>* prs, SharedContext* sc, Directives* newDirectives)
|
||||
: Nestable<ParseContext>(&prs->pc),
|
||||
traceLog_(sc->context,
|
||||
mozilla::IsSame<ParseHandler, FullParseHandler>::value
|
||||
? TraceLogger_ParsingFull
|
||||
: TraceLogger_ParsingSyntax,
|
||||
prs->tokenStream),
|
||||
sc_(sc),
|
||||
tokenStream_(prs->tokenStream),
|
||||
innermostStatement_(nullptr),
|
||||
innermostScope_(nullptr),
|
||||
varScope_(nullptr),
|
||||
positionalFormalParameterNames_(prs->context->frontendCollectionPool()),
|
||||
closedOverBindingsForLazy_(prs->context->frontendCollectionPool()),
|
||||
scriptId_(prs->usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false),
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
innerFunctionsForLazy(prs->context, GCVector<JSFunction*, 8>(prs->context)),
|
||||
newDirectives(newDirectives),
|
||||
funHasReturnExpr(false),
|
||||
funHasReturnVoid(false)
|
||||
{
|
||||
if (isFunctionBox()) {
|
||||
if (functionBox()->function()->isNamedLambda())
|
||||
namedLambdaScope_.emplace(prs);
|
||||
functionScope_.emplace(prs);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool init();
|
||||
|
||||
SharedContext* sc() {
|
||||
return sc_;
|
||||
}
|
||||
|
||||
bool isFunctionBox() const {
|
||||
return sc_->isFunctionBox();
|
||||
}
|
||||
|
||||
FunctionBox* functionBox() {
|
||||
return sc_->asFunctionBox();
|
||||
}
|
||||
|
||||
Statement* innermostStatement() {
|
||||
return innermostStatement_;
|
||||
}
|
||||
|
||||
Scope* innermostScope() {
|
||||
// There is always at least one scope: the 'var' scope.
|
||||
MOZ_ASSERT(innermostScope_);
|
||||
return innermostScope_;
|
||||
}
|
||||
|
||||
Scope& namedLambdaScope() {
|
||||
MOZ_ASSERT(functionBox()->function()->isNamedLambda());
|
||||
return *namedLambdaScope_;
|
||||
}
|
||||
|
||||
Scope& functionScope() {
|
||||
MOZ_ASSERT(isFunctionBox());
|
||||
return *functionScope_;
|
||||
}
|
||||
|
||||
Scope& varScope() {
|
||||
MOZ_ASSERT(varScope_);
|
||||
return *varScope_;
|
||||
}
|
||||
|
||||
bool isFunctionExtraBodyVarScopeInnermost() {
|
||||
return isFunctionBox() && functionBox()->hasParameterExprs &&
|
||||
innermostScope() == varScope_;
|
||||
}
|
||||
|
||||
template <typename Predicate /* (Statement*) -> bool */>
|
||||
Statement* findInnermostStatement(Predicate predicate) {
|
||||
return Statement::findNearest(innermostStatement_, predicate);
|
||||
}
|
||||
|
||||
template <typename T, typename Predicate /* (Statement*) -> bool */>
|
||||
T* findInnermostStatement(Predicate predicate) {
|
||||
return Statement::findNearest<T>(innermostStatement_, predicate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* findInnermostStatement() {
|
||||
return Statement::findNearest<T>(innermostStatement_);
|
||||
}
|
||||
|
||||
AtomVector& positionalFormalParameterNames() {
|
||||
return *positionalFormalParameterNames_;
|
||||
}
|
||||
|
||||
AtomVector& closedOverBindingsForLazy() {
|
||||
return *closedOverBindingsForLazy_;
|
||||
}
|
||||
|
||||
// True if we are at the topmost level of a entire script or function body.
|
||||
// For example, while parsing this code we would encounter f1 and f2 at
|
||||
// body level, but we would not encounter f3 or f4 at body level:
|
||||
//
|
||||
// function f1() { function f2() { } }
|
||||
// if (cond) { function f3() { if (cond) { function f4() { } } } }
|
||||
//
|
||||
bool atBodyLevel() {
|
||||
return !innermostStatement_;
|
||||
}
|
||||
|
||||
bool atGlobalLevel() {
|
||||
return atBodyLevel() && sc_->isGlobalContext();
|
||||
}
|
||||
|
||||
// True if we are at the topmost level of a module only.
|
||||
bool atModuleLevel() {
|
||||
return atBodyLevel() && sc_->isModuleContext();
|
||||
}
|
||||
|
||||
void setIsStandaloneFunctionBody() {
|
||||
isStandaloneFunctionBody_ = true;
|
||||
}
|
||||
|
||||
bool isStandaloneFunctionBody() const {
|
||||
return isStandaloneFunctionBody_;
|
||||
}
|
||||
|
||||
void setSuperScopeNeedsHomeObject() {
|
||||
MOZ_ASSERT(sc_->allowSuperProperty());
|
||||
superScopeNeedsHomeObject_ = true;
|
||||
}
|
||||
|
||||
bool superScopeNeedsHomeObject() const {
|
||||
return superScopeNeedsHomeObject_;
|
||||
}
|
||||
|
||||
bool useAsmOrInsideUseAsm() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->useAsmOrInsideUseAsm();
|
||||
}
|
||||
|
||||
// Most functions start off being parsed as non-generators.
|
||||
// Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7.
|
||||
// An ES6 generator is marked as a "star generator" before its body is parsed.
|
||||
GeneratorKind generatorKind() const {
|
||||
return sc_->isFunctionBox() ? sc_->asFunctionBox()->generatorKind() : NotGenerator;
|
||||
}
|
||||
|
||||
bool isLegacyGenerator() const {
|
||||
return generatorKind() == LegacyGenerator;
|
||||
}
|
||||
|
||||
bool isStarGenerator() const {
|
||||
return generatorKind() == StarGenerator;
|
||||
}
|
||||
|
||||
bool isAsync() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
|
||||
}
|
||||
|
||||
bool needsDotGeneratorName() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? AsyncFunction : SyncFunction;
|
||||
}
|
||||
|
||||
bool isArrowFunction() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
|
||||
}
|
||||
|
||||
bool isMethod() const {
|
||||
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
|
||||
}
|
||||
|
||||
bool isGetterOrSetter() const {
|
||||
return sc_->isFunctionBox() && (sc_->asFunctionBox()->function()->isGetter() ||
|
||||
sc_->asFunctionBox()->function()->isSetter());
|
||||
}
|
||||
|
||||
uint32_t scriptId() const {
|
||||
return scriptId_;
|
||||
}
|
||||
|
||||
bool annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox);
|
||||
|
||||
bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
|
||||
mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos);
|
||||
|
||||
private:
|
||||
mozilla::Maybe<DeclarationKind> isVarRedeclaredInInnermostScope(HandlePropertyName name,
|
||||
DeclarationKind kind);
|
||||
mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
|
||||
DeclarationKind kind);
|
||||
|
||||
enum DryRunOption { NotDryRun, DryRunInnermostScopeOnly };
|
||||
template <DryRunOption dryRunOption>
|
||||
bool tryDeclareVarHelper(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos,
|
||||
mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos);
|
||||
|
||||
public:
|
||||
template<typename ParseHandler, typename CharT>
|
||||
SourceParseContext(Parser<ParseHandler, CharT>* prs, SharedContext* sc, Directives* newDirectives)
|
||||
: ParseContext(prs->context, prs->pc, sc, prs->tokenStream,
|
||||
prs->usedNames, newDirectives, mozilla::IsSame<ParseHandler,
|
||||
FullParseHandler>::value)
|
||||
{ }
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -619,158 +112,6 @@ enum InHandling { InAllowed, InProhibited };
|
||||
enum DefaultHandling { NameRequired, AllowDefaultName };
|
||||
enum TripledotHandling { TripledotAllowed, TripledotProhibited };
|
||||
|
||||
// A data structure for tracking used names per parsing session in order to
|
||||
// compute which bindings are closed over. Scripts and scopes are numbered
|
||||
// monotonically in textual order and name uses are tracked by lists of
|
||||
// (script id, scope id) pairs of their use sites.
|
||||
//
|
||||
// Intuitively, in a pair (P,S), P tracks the most nested function that has a
|
||||
// use of u, and S tracks the most nested scope that is still being parsed.
|
||||
//
|
||||
// P is used to answer the question "is u used by a nested function?"
|
||||
// S is used to answer the question "is u used in any scopes currently being
|
||||
// parsed?"
|
||||
//
|
||||
// The algorithm:
|
||||
//
|
||||
// Let Used by a map of names to lists.
|
||||
//
|
||||
// 1. Number all scopes in monotonic increasing order in textual order.
|
||||
// 2. Number all scripts in monotonic increasing order in textual order.
|
||||
// 3. When an identifier u is used in scope numbered S in script numbered P,
|
||||
// and u is found in Used,
|
||||
// a. Append (P,S) to Used[u].
|
||||
// b. Otherwise, assign the the list [(P,S)] to Used[u].
|
||||
// 4. When we finish parsing a scope S in script P, for each declared name d in
|
||||
// Declared(S):
|
||||
// a. If d is found in Used, mark d as closed over if there is a value
|
||||
// (P_d, S_d) in Used[d] such that P_d > P and S_d > S.
|
||||
// b. Remove all values (P_d, S_d) in Used[d] such that S_d are >= S.
|
||||
//
|
||||
// Steps 1 and 2 are implemented by UsedNameTracker::next{Script,Scope}Id.
|
||||
// Step 3 is implemented by UsedNameTracker::noteUsedInScope.
|
||||
// Step 4 is implemented by UsedNameTracker::noteBoundInScope and
|
||||
// Parser::propagateFreeNamesAndMarkClosedOverBindings.
|
||||
class UsedNameTracker
|
||||
{
|
||||
public:
|
||||
struct Use
|
||||
{
|
||||
uint32_t scriptId;
|
||||
uint32_t scopeId;
|
||||
};
|
||||
|
||||
class UsedNameInfo
|
||||
{
|
||||
friend class UsedNameTracker;
|
||||
|
||||
Vector<Use, 6> uses_;
|
||||
|
||||
void resetToScope(uint32_t scriptId, uint32_t scopeId);
|
||||
|
||||
public:
|
||||
explicit UsedNameInfo(JSContext* cx)
|
||||
: uses_(cx)
|
||||
{ }
|
||||
|
||||
UsedNameInfo(UsedNameInfo&& other)
|
||||
: uses_(mozilla::Move(other.uses_))
|
||||
{ }
|
||||
|
||||
bool noteUsedInScope(uint32_t scriptId, uint32_t scopeId) {
|
||||
if (uses_.empty() || uses_.back().scopeId < scopeId)
|
||||
return uses_.append(Use { scriptId, scopeId });
|
||||
return true;
|
||||
}
|
||||
|
||||
void noteBoundInScope(uint32_t scriptId, uint32_t scopeId, bool* closedOver) {
|
||||
*closedOver = false;
|
||||
while (!uses_.empty()) {
|
||||
Use& innermost = uses_.back();
|
||||
if (innermost.scopeId < scopeId)
|
||||
break;
|
||||
if (innermost.scriptId > scriptId)
|
||||
*closedOver = true;
|
||||
uses_.popBack();
|
||||
}
|
||||
}
|
||||
|
||||
bool isUsedInScript(uint32_t scriptId) const {
|
||||
return !uses_.empty() && uses_.back().scriptId >= scriptId;
|
||||
}
|
||||
};
|
||||
|
||||
using UsedNameMap = HashMap<JSAtom*,
|
||||
UsedNameInfo,
|
||||
DefaultHasher<JSAtom*>>;
|
||||
|
||||
private:
|
||||
// The map of names to chains of uses.
|
||||
UsedNameMap map_;
|
||||
|
||||
// Monotonically increasing id for all nested scripts.
|
||||
uint32_t scriptCounter_;
|
||||
|
||||
// Monotonically increasing id for all nested scopes.
|
||||
uint32_t scopeCounter_;
|
||||
|
||||
public:
|
||||
explicit UsedNameTracker(JSContext* cx)
|
||||
: map_(cx),
|
||||
scriptCounter_(0),
|
||||
scopeCounter_(0)
|
||||
{ }
|
||||
|
||||
MOZ_MUST_USE bool init() {
|
||||
return map_.init();
|
||||
}
|
||||
|
||||
uint32_t nextScriptId() {
|
||||
MOZ_ASSERT(scriptCounter_ != UINT32_MAX,
|
||||
"ParseContext::Scope::init should have prevented wraparound");
|
||||
return scriptCounter_++;
|
||||
}
|
||||
|
||||
uint32_t nextScopeId() {
|
||||
MOZ_ASSERT(scopeCounter_ != UINT32_MAX);
|
||||
return scopeCounter_++;
|
||||
}
|
||||
|
||||
UsedNameMap::Ptr lookup(JSAtom* name) const {
|
||||
return map_.lookup(name);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool noteUse(JSContext* cx, JSAtom* name,
|
||||
uint32_t scriptId, uint32_t scopeId);
|
||||
|
||||
struct RewindToken
|
||||
{
|
||||
private:
|
||||
friend class UsedNameTracker;
|
||||
uint32_t scriptId;
|
||||
uint32_t scopeId;
|
||||
};
|
||||
|
||||
RewindToken getRewindToken() const {
|
||||
RewindToken token;
|
||||
token.scriptId = scriptCounter_;
|
||||
token.scopeId = scopeCounter_;
|
||||
return token;
|
||||
}
|
||||
|
||||
// Resets state so that scriptId and scopeId are the innermost script and
|
||||
// scope, respectively. Used for rewinding state on syntax parse failure.
|
||||
void rewind(RewindToken token);
|
||||
|
||||
// Resets state to beginning of compilation.
|
||||
void reset() {
|
||||
map_.clear();
|
||||
RewindToken token;
|
||||
token.scriptId = 0;
|
||||
token.scopeId = 0;
|
||||
rewind(token);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Parser>
|
||||
class AutoAwaitIsKeyword;
|
||||
@ -973,6 +314,14 @@ ParseContext::Scope::Scope(ParserBase* parser)
|
||||
id_(parser->usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::Scope::Scope(JSContext* cx, ParseContext* pc, UsedNameTracker& usedNames)
|
||||
: Nestable<Scope>(&pc->innermostScope_),
|
||||
declared_(cx->frontendCollectionPool()),
|
||||
possibleAnnexBFunctionBoxes_(cx->frontendCollectionPool()),
|
||||
id_(usedNames.nextScopeId())
|
||||
{ }
|
||||
|
||||
inline
|
||||
ParseContext::VarScope::VarScope(ParserBase* parser)
|
||||
: Scope(parser)
|
||||
|
@ -736,6 +736,25 @@ TokenStreamAnyChars::fillExcludingContext(ErrorMetadata* err, uint32_t offset)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenStreamAnyChars::hasTokenizationStarted() const
|
||||
{
|
||||
return isCurrentTokenType(TOK_EOF) && !isEOF();
|
||||
}
|
||||
|
||||
void
|
||||
TokenStreamAnyChars::lineNumAndColumnIndex(size_t offset, uint32_t* line, uint32_t* column) const
|
||||
{
|
||||
srcCoords.lineNumAndColumnIndex(offset, line, column);
|
||||
}
|
||||
|
||||
size_t
|
||||
TokenStreamAnyChars::offset() const
|
||||
{
|
||||
// Default implementation. Overridden by `TokenStream`.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TokenStream::computeErrorMetadata(ErrorMetadata* err, uint32_t offset)
|
||||
{
|
||||
@ -807,6 +826,13 @@ TokenStream::computeLineOfContext(ErrorMetadata* err, uint32_t offset)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
TokenStream::offset() const
|
||||
{
|
||||
return userbuf.offset();
|
||||
}
|
||||
|
||||
bool
|
||||
TokenStream::reportStrictModeError(unsigned errorNumber, ...)
|
||||
{
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "jscntxt.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "frontend/ErrorReporter.h"
|
||||
#include "frontend/TokenKind.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "js/Vector.h"
|
||||
@ -264,7 +265,7 @@ class StrictModeGetter {
|
||||
virtual bool strictMode() = 0;
|
||||
};
|
||||
|
||||
class TokenStreamAnyChars
|
||||
class TokenStreamAnyChars: public ErrorReporter
|
||||
{
|
||||
protected:
|
||||
TokenStreamAnyChars(JSContext* cx, const ReadOnlyCompileOptions& options, StrictModeGetter* smg);
|
||||
@ -281,7 +282,6 @@ class TokenStreamAnyChars
|
||||
return currentToken().type == type;
|
||||
}
|
||||
|
||||
const char* getFilename() const { return filename; }
|
||||
bool getMutedErrors() const { return mutedErrors; }
|
||||
JSVersion versionNumber() const { return VersionNumber(options().version); }
|
||||
JSVersion versionWithFlags() const { return options().version; }
|
||||
@ -549,7 +549,7 @@ class TokenStreamAnyChars
|
||||
return cx;
|
||||
}
|
||||
|
||||
const ReadOnlyCompileOptions& options() const {
|
||||
virtual const ReadOnlyCompileOptions& options() const override final {
|
||||
return options_;
|
||||
}
|
||||
|
||||
@ -573,11 +573,15 @@ class TokenStreamAnyChars
|
||||
MOZ_MUST_USE bool compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
|
||||
unsigned flags, unsigned errorNumber, va_list args);
|
||||
|
||||
void reportErrorNoOffset(unsigned errorNumber, ...);
|
||||
|
||||
// Compute error metadata for an error at no offset.
|
||||
void computeErrorMetadataNoOffset(ErrorMetadata* err);
|
||||
|
||||
virtual const char* getFilename() const override { return filename; }
|
||||
virtual bool hasTokenizationStarted() const override;
|
||||
virtual void lineNumAndColumnIndex(size_t offset, uint32_t* line, uint32_t* column) const override;
|
||||
virtual void reportErrorNoOffset(unsigned errorNumber, ...) override;
|
||||
virtual size_t offset() const override;
|
||||
|
||||
protected:
|
||||
// Options used for parsing/tokenizing.
|
||||
const ReadOnlyCompileOptions& options_;
|
||||
@ -1101,6 +1105,9 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamAnyChars
|
||||
|
||||
TokenBuf userbuf; // user input buffer
|
||||
CharBuffer tokenbuf; // current token string buffer
|
||||
|
||||
public:
|
||||
virtual size_t offset() const override;
|
||||
};
|
||||
|
||||
extern const char*
|
||||
|
@ -7126,7 +7126,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||
funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
|
||||
|
||||
Directives newDirectives = directives;
|
||||
ParseContext funpc(&m.parser(), funbox, &newDirectives);
|
||||
SourceParseContext funpc(&m.parser(), funbox, &newDirectives);
|
||||
if (!funpc.init())
|
||||
return false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user