1325157 - Implement a ParserBase class that holds functionality that's identical between syntax parsing and full parsing.

This commit is contained in:
Gaming4JC 2019-06-08 15:29:37 -04:00 committed by Roy Tam
commit 94c6eea52b
2 changed files with 181 additions and 170 deletions

View file

@ -571,9 +571,8 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
computeInWith(enclosingScope);
}
template <typename ParseHandler>
void
Parser<ParseHandler>::error(unsigned errorNumber, ...)
ParserBase::error(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -585,9 +584,8 @@ Parser<ParseHandler>::error(unsigned errorNumber, ...)
va_end(args);
}
template <typename ParseHandler>
void
Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...)
ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -599,9 +597,8 @@ Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...)
va_end(args);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::warning(unsigned errorNumber, ...)
ParserBase::warning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -611,9 +608,8 @@ Parser<ParseHandler>::warning(unsigned errorNumber, ...)
return result;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...)
ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -623,9 +619,8 @@ Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...)
return result;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...)
ParserBase::extraWarning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -634,9 +629,8 @@ Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...)
return result;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...)
ParserBase::strictModeError(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -647,9 +641,8 @@ Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...)
return res;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -659,9 +652,8 @@ Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, .
return res;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -702,16 +694,14 @@ Parser<SyntaxParseHandler>::abortIfSyntaxParser()
return false;
}
template <typename ParseHandler>
Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
bool foldConstants,
UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: AutoGCRooter(cx, PARSER),
context(cx),
ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
bool foldConstants,
UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: context(cx),
alloc(alloc),
tokenStream(cx, options, chars, length, thisForCtor()),
traceListHead(nullptr),
@ -725,38 +715,14 @@ Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
checkOptionsCalled(false),
#endif
abortedSyntaxParse(false),
isUnexpectedEOF_(false),
handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
isUnexpectedEOF_(false)
{
cx->perThreadData->frontendCollectionPool.addActiveCompilation();
// The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
// which are not generated if functions are parsed lazily. Note that the
// standard "use strict" does not inhibit lazy parsing.
if (options.extraWarningsOption)
handler.disableSyntaxParser();
tempPoolMark = alloc.mark();
}
template<typename ParseHandler>
bool
Parser<ParseHandler>::checkOptions()
ParserBase::~ParserBase()
{
#ifdef DEBUG
checkOptionsCalled = true;
#endif
if (!tokenStream.checkOptions())
return false;
return true;
}
template <typename ParseHandler>
Parser<ParseHandler>::~Parser()
{
MOZ_ASSERT(checkOptionsCalled);
alloc.release(tempPoolMark);
/*
@ -769,6 +735,43 @@ Parser<ParseHandler>::~Parser()
context->perThreadData->frontendCollectionPool.removeActiveCompilation();
}
template <typename ParseHandler>
Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
bool foldConstants,
UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser,
lazyOuterFunction),
AutoGCRooter(cx, PARSER),
handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
{
// The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
// which are not generated if functions are parsed lazily. Note that the
// standard "use strict" does not inhibit lazy parsing.
if (options.extraWarningsOption)
handler.disableSyntaxParser();
}
template<typename ParseHandler>
bool
Parser<ParseHandler>::checkOptions()
{
#ifdef DEBUG
checkOptionsCalled = true;
#endif
return tokenStream.checkOptions();
}
template <typename ParseHandler>
Parser<ParseHandler>::~Parser()
{
MOZ_ASSERT(checkOptionsCalled);
}
template <typename ParseHandler>
ObjectBox*
Parser<ParseHandler>::newObjectBox(JSObject* obj)
@ -897,9 +900,8 @@ Parser<ParseHandler>::parse()
* Strict mode forbids introducing new definitions for 'eval', 'arguments', or
* for any strict mode reserved keyword.
*/
template <typename ParseHandler>
bool
Parser<ParseHandler>::isValidStrictBinding(PropertyName* name)
ParserBase::isValidStrictBinding(PropertyName* name)
{
return name != context->names().eval &&
name != context->names().arguments &&
@ -9602,9 +9604,8 @@ Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHan
return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::warnOnceAboutExprClosure()
ParserBase::warnOnceAboutExprClosure()
{
#ifndef RELEASE_OR_BETA
JSContext* cx = context->maybeJSContext();
@ -9620,9 +9621,8 @@ Parser<ParseHandler>::warnOnceAboutExprClosure()
return true;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::warnOnceAboutForEach()
ParserBase::warnOnceAboutForEach()
{
JSContext* cx = context->maybeJSContext();
if (!cx)

View file

@ -734,8 +734,138 @@ class UsedNameTracker
}
};
class ParserBase : public StrictModeGetter
{
private:
ParserBase* thisForCtor() { return this; }
public:
ExclusiveContext* const context;
LifoAlloc& alloc;
TokenStream tokenStream;
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox* traceListHead;
/* innermost parse context (stack-allocated) */
ParseContext* pc;
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
AutoKeepAtoms keepAtoms;
/* Perform constant-folding; must be true when interfacing with the emitter. */
const bool foldConstants:1;
protected:
#if DEBUG
/* Our fallible 'checkOptions' member function has been called. */
bool checkOptionsCalled:1;
#endif
/*
* Not all language constructs can be handled during syntax parsing. If it
* is not known whether the parse succeeds or fails, this bit is set and
* the parse will return false.
*/
bool abortedSyntaxParse:1;
/* Unexpected end of input, i.e. TOK_EOF not at top-level. */
bool isUnexpectedEOF_:1;
public:
ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants,
UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction);
~ParserBase();
const char* getFilename() const { return tokenStream.getFilename(); }
JSVersion versionNumber() const { return tokenStream.versionNumber(); }
TokenPos pos() const { return tokenStream.currentToken().pos; }
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
virtual bool strictMode() { return pc->sc()->strict(); }
bool setLocalStrictMode(bool strict) {
MOZ_ASSERT(tokenStream.debugHasNoLookahead());
return pc->sc()->setLocalStrictMode(strict);
}
const ReadOnlyCompileOptions& options() const {
return tokenStream.options();
}
bool hadAbortedSyntaxParse() {
return abortedSyntaxParse;
}
void clearAbortedSyntaxParse() {
abortedSyntaxParse = false;
}
bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
/* Report the given error at the current offset. */
void error(unsigned errorNumber, ...);
/* Report the given error at the given offset. */
void errorAt(uint32_t offset, unsigned errorNumber, ...);
/*
* Handle a strict mode error at the current offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
/*
* Handle a strict mode error at the given offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
/* Report the given warning at the current offset. */
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
/* Report the given warning at the given offset. */
MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
/*
* If extra warnings are enabled, report the given warning at the current
* offset.
*/
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
bool isValidStrictBinding(PropertyName* name);
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
protected:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
};
template <typename ParseHandler>
class Parser final : private JS::AutoGCRooter, public StrictModeGetter
class Parser final : public ParserBase, private JS::AutoGCRooter
{
private:
using Node = typename ParseHandler::Node;
@ -852,50 +982,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void transferErrorsTo(PossibleError* other);
};
public:
ExclusiveContext* const context;
LifoAlloc& alloc;
TokenStream tokenStream;
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox* traceListHead;
/* innermost parse context (stack-allocated) */
ParseContext* pc;
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
AutoKeepAtoms keepAtoms;
/* Perform constant-folding; must be true when interfacing with the emitter. */
const bool foldConstants:1;
private:
#if DEBUG
/* Our fallible 'checkOptions' member function has been called. */
bool checkOptionsCalled:1;
#endif
/*
* Not all language constructs can be handled during syntax parsing. If it
* is not known whether the parse succeeds or fails, this bit is set and
* the parse will return false.
*/
bool abortedSyntaxParse:1;
/* Unexpected end of input, i.e. TOK_EOF not at top-level. */
bool isUnexpectedEOF_:1;
public:
/* State specific to the kind of parse being performed. */
ParseHandler handler;
@ -904,40 +990,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void freeTree(Node node) { handler.freeTree(node); }
public:
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
/* Report the given error at the current offset. */
void error(unsigned errorNumber, ...);
/* Report the given error at the given offset. */
void errorAt(uint32_t offset, unsigned errorNumber, ...);
/*
* Handle a strict mode error at the current offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
/*
* Handle a strict mode error at the given offset. Report an error if in
* strict mode code, or warn if not, using the given error number and
* arguments.
*/
MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
/* Report the given warning at the current offset. */
MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
/* Report the given warning at the given offset. */
MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
/*
* If extra warnings are enabled, report the given warning at the current
* offset.
*/
MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser, LazyScript* lazyOuterFunction);
@ -967,9 +1019,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
friend void js::frontend::MarkParser(JSTracer* trc, JS::AutoGCRooter* parser);
const char* getFilename() const { return tokenStream.getFilename(); }
JSVersion versionNumber() const { return tokenStream.versionNumber(); }
/*
* Parse a top-level JS script.
*/
@ -995,15 +1044,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void trace(JSTracer* trc);
bool hadAbortedSyntaxParse() {
return abortedSyntaxParse;
}
void clearAbortedSyntaxParse() {
abortedSyntaxParse = false;
}
bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
bool checkUnescapedName();
private:
@ -1072,34 +1112,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node pn, FunctionSyntaxKind kind,
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing(),
bool isStandaloneFunction = false);
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
// Match the current token against the BindingIdentifier production with
// the given Yield parameter. If there is no match, report a syntax
// error.
PropertyName* bindingIdentifier(YieldHandling yieldHandling);
virtual bool strictMode() { return pc->sc()->strict(); }
bool setLocalStrictMode(bool strict) {
MOZ_ASSERT(tokenStream.debugHasNoLookahead());
return pc->sc()->setLocalStrictMode(strict);
}
const ReadOnlyCompileOptions& options() const {
return tokenStream.options();
}
private:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
private:
/*
* JS parsers, from lowest to highest precedence.
@ -1375,8 +1393,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool hasValidSimpleStrictParameterNames();
bool isValidStrictBinding(PropertyName* name);
void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
bool notePositionalFormalParameter(Node fn, HandlePropertyName name,
bool disallowDuplicateParams, bool* duplicatedParam);
@ -1432,12 +1448,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
TokenPos pos() const { return tokenStream.currentToken().pos; }
bool asmJS(Node list);
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
};
} /* namespace frontend */