summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/Parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/Parser.h')
-rw-r--r--js/src/frontend/Parser.h1974
1 files changed, 1974 insertions, 0 deletions
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
new file mode 100644
index 0000000000..9cf19cdaf4
--- /dev/null
+++ b/js/src/frontend/Parser.h
@@ -0,0 +1,1974 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* JS parser. */
+
+#ifndef frontend_Parser_h
+#define frontend_Parser_h
+
+/*
+ * [SMDOC] JS Parser
+ *
+ * JS parsers capable of generating ASTs from source text.
+ *
+ * A parser embeds token stream information, then gets and matches tokens to
+ * generate a syntax tree that, if desired, BytecodeEmitter will use to compile
+ * bytecode.
+ *
+ * Like token streams (see the comment near the top of TokenStream.h), parser
+ * classes are heavily templatized -- along the token stream's character-type
+ * axis, and also along a full-parse/syntax-parse axis. Certain limitations of
+ * C++ (primarily the inability to partially specialize function templates),
+ * plus the desire to minimize compiled code size in duplicate function
+ * template instantiations wherever possible, mean that Parser exhibits much of
+ * the same unholy template/inheritance complexity as token streams.
+ *
+ * == ParserSharedBase ==
+ *
+ * ParserSharedBase is the base class for both regular JS and BinAST parsing.
+ * This class contains common fields and methods between both parsers. There is
+ * currently no BinAST parser here so this can potentially be merged into the
+ * ParserBase type below.
+ *
+ * == ParserBase → ParserSharedBase, ErrorReportMixin ==
+ *
+ * ParserBase is the base class for regular JS parser, shared by all regular JS
+ * parsers of all character types and parse-handling behavior. It stores
+ * everything character- and handler-agnostic.
+ *
+ * ParserBase's most important field is the parser's token stream's
+ * |TokenStreamAnyChars| component, for all tokenizing aspects that are
+ * character-type-agnostic. The character-type-sensitive components residing
+ * in |TokenStreamSpecific| (see the comment near the top of TokenStream.h)
+ * live elsewhere in this hierarchy. These separate locations are the reason
+ * for the |AnyCharsAccess| template parameter to |TokenStreamChars| and
+ * |TokenStreamSpecific|.
+ *
+ * == PerHandlerParser<ParseHandler> → ParserBase ==
+ *
+ * Certain parsing behavior varies between full parsing and syntax-only parsing
+ * but does not vary across source-text character types. For example, the work
+ * to "create an arguments object for a function" obviously varies between
+ * syntax and full parsing but (because no source characters are examined) does
+ * not vary by source text character type. Such functionality is implemented
+ * through functions in PerHandlerParser.
+ *
+ * Functionality only used by syntax parsing or full parsing doesn't live here:
+ * it should be implemented in the appropriate Parser<ParseHandler> (described
+ * further below).
+ *
+ * == GeneralParser<ParseHandler, Unit> → PerHandlerParser<ParseHandler> ==
+ *
+ * Most parsing behavior varies across the character-type axis (and possibly
+ * along the full/syntax axis). For example:
+ *
+ * * Parsing ECMAScript's Expression production, implemented by
+ * GeneralParser::expr, varies in this manner: different types are used to
+ * represent nodes in full and syntax parsing (ParseNode* versus an enum),
+ * and reading the tokens comprising the expression requires inspecting
+ * individual characters (necessarily dependent upon character type).
+ * * Reporting an error or warning does not depend on the full/syntax parsing
+ * distinction. But error reports and warnings include a line of context
+ * (or a slice of one), for pointing out where a mistake was made.
+ * Computing such line of context requires inspecting the source text to
+ * make that line/slice of context, which requires knowing the source text
+ * character type.
+ *
+ * Such functionality, implemented using identical function code across these
+ * axes, should live in GeneralParser.
+ *
+ * GeneralParser's most important field is the parser's token stream's
+ * |TokenStreamSpecific| component, for all aspects of tokenizing that (contra
+ * |TokenStreamAnyChars| in ParserBase above) are character-type-sensitive. As
+ * noted above, this field's existence separate from that in ParserBase
+ * motivates the |AnyCharsAccess| template parameters on various token stream
+ * classes.
+ *
+ * Everything in PerHandlerParser *could* be folded into GeneralParser (below)
+ * if desired. We don't fold in this manner because all such functions would
+ * be instantiated once per Unit -- but if exactly equivalent code would be
+ * generated (because PerHandlerParser functions have no awareness of Unit),
+ * it's risky to *depend* upon the compiler coalescing the instantiations into
+ * one in the final binary. PerHandlerParser guarantees no duplication.
+ *
+ * == Parser<ParseHandler, Unit> final → GeneralParser<ParseHandler, Unit> ==
+ *
+ * The final (pun intended) axis of complexity lies in Parser.
+ *
+ * Some functionality depends on character type, yet also is defined in
+ * significantly different form in full and syntax parsing. For example,
+ * attempting to parse the source text of a module will do so in full parsing
+ * but immediately fail in syntax parsing -- so the former is a mess'o'code
+ * while the latter is effectively |return null();|. Such functionality is
+ * defined in Parser<SyntaxParseHandler or FullParseHandler, Unit> as
+ * appropriate.
+ *
+ * There's a crucial distinction between GeneralParser and Parser, that
+ * explains why both must exist (despite taking exactly the same template
+ * parameters, and despite GeneralParser and Parser existing in a one-to-one
+ * relationship). GeneralParser is one unspecialized template class:
+ *
+ * template<class ParseHandler, typename Unit>
+ * class GeneralParser : ...
+ * {
+ * ...parsing functions...
+ * };
+ *
+ * but Parser is one undefined template class with two separate
+ * specializations:
+ *
+ * // Declare, but do not define.
+ * template<class ParseHandler, typename Unit> class Parser;
+ *
+ * // Define a syntax-parsing specialization.
+ * template<typename Unit>
+ * class Parser<SyntaxParseHandler, Unit> final
+ * : public GeneralParser<SyntaxParseHandler, Unit>
+ * {
+ * ...parsing functions...
+ * };
+ *
+ * // Define a full-parsing specialization.
+ * template<typename Unit>
+ * class Parser<SyntaxParseHandler, Unit> final
+ * : public GeneralParser<SyntaxParseHandler, Unit>
+ * {
+ * ...parsing functions...
+ * };
+ *
+ * This odd distinction is necessary because C++ unfortunately doesn't allow
+ * partial function specialization:
+ *
+ * // BAD: You can only specialize a template function if you specify *every*
+ * // template parameter, i.e. ParseHandler *and* Unit.
+ * template<typename Unit>
+ * void
+ * GeneralParser<SyntaxParseHandler, Unit>::foo() {}
+ *
+ * But if you specialize Parser *as a class*, then this is allowed:
+ *
+ * template<typename Unit>
+ * void
+ * Parser<SyntaxParseHandler, Unit>::foo() {}
+ *
+ * template<typename Unit>
+ * void
+ * Parser<FullParseHandler, Unit>::foo() {}
+ *
+ * because the only template parameter on the function is Unit -- and so all
+ * template parameters *are* varying, not a strict subset of them.
+ *
+ * So -- any parsing functionality that is differently defined for different
+ * ParseHandlers, *but* is defined textually identically for different Unit
+ * (even if different code ends up generated for them by the compiler), should
+ * reside in Parser.
+ */
+
+#include "mozilla/Maybe.h"
+
+#include <type_traits>
+#include <utility>
+
+#include "frontend/CompilationStencil.h" // CompilationState
+#include "frontend/ErrorReporter.h"
+#include "frontend/FullParseHandler.h"
+#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
+#include "frontend/IteratorKind.h"
+#include "frontend/NameAnalysisTypes.h"
+#include "frontend/ParseContext.h"
+#include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex
+#include "frontend/SharedContext.h"
+#include "frontend/SyntaxParseHandler.h"
+#include "frontend/TokenStream.h"
+#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
+#include "js/friend/ErrorMessages.h" // JSErrNum, JSMSG_*
+#include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind
+
+namespace js {
+
+class FrontendContext;
+struct ErrorMetadata;
+
+namespace frontend {
+
+template <class ParseHandler, typename Unit>
+class GeneralParser;
+
+class SourceParseContext : public ParseContext {
+ public:
+ template <typename ParseHandler, typename Unit>
+ SourceParseContext(GeneralParser<ParseHandler, Unit>* prs, SharedContext* sc,
+ Directives* newDirectives)
+ : ParseContext(prs->fc_, prs->pc_, sc, prs->tokenStream,
+ prs->compilationState_, newDirectives,
+ std::is_same_v<ParseHandler, FullParseHandler>) {}
+};
+
+enum VarContext { HoistVars, DontHoistVars };
+enum PropListType { ObjectLiteral, ClassBody, DerivedClassBody };
+enum class PropertyType {
+ Normal,
+ Shorthand,
+ CoverInitializedName,
+ Getter,
+ Setter,
+ Method,
+ GeneratorMethod,
+ AsyncMethod,
+ AsyncGeneratorMethod,
+ Constructor,
+ DerivedConstructor,
+ Field,
+ FieldWithAccessor,
+};
+
+enum AwaitHandling : uint8_t {
+ AwaitIsName,
+ AwaitIsKeyword,
+ AwaitIsModuleKeyword,
+ AwaitIsDisallowed
+};
+
+template <class ParseHandler, typename Unit>
+class AutoAwaitIsKeyword;
+
+template <class ParseHandler, typename Unit>
+class AutoInParametersOfAsyncFunction;
+
+class MOZ_STACK_CLASS ParserSharedBase {
+ public:
+ enum class Kind { Parser };
+
+ ParserSharedBase(FrontendContext* fc, CompilationState& compilationState,
+ Kind kind);
+ ~ParserSharedBase();
+
+ public:
+ FrontendContext* fc_;
+
+ LifoAlloc& alloc_;
+
+ CompilationState& compilationState_;
+
+ // innermost parse context (stack-allocated)
+ ParseContext* pc_;
+
+ // For tracking used names in this parsing session.
+ UsedNameTracker& usedNames_;
+
+ public:
+ CompilationState& getCompilationState() { return compilationState_; }
+
+ ParserAtomsTable& parserAtoms() { return compilationState_.parserAtoms; }
+ const ParserAtomsTable& parserAtoms() const {
+ return compilationState_.parserAtoms;
+ }
+
+ LifoAlloc& stencilAlloc() { return compilationState_.alloc; }
+
+ const UsedNameTracker& usedNames() { return usedNames_; }
+
+#if defined(DEBUG) || defined(JS_JITSPEW)
+ void dumpAtom(TaggedParserAtomIndex index) const;
+#endif
+};
+
+class MOZ_STACK_CLASS ParserBase : public ParserSharedBase,
+ public ErrorReportMixin {
+ using Base = ErrorReportMixin;
+
+ public:
+ TokenStreamAnyChars anyChars;
+
+ ScriptSource* ss;
+
+ // 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
+
+ /* Unexpected end of input, i.e. Eof not at top-level. */
+ bool isUnexpectedEOF_ : 1;
+
+ /* AwaitHandling */ uint8_t awaitHandling_ : 2;
+
+ bool inParametersOfAsyncFunction_ : 1;
+
+ public:
+ JSAtom* liftParserAtomToJSAtom(TaggedParserAtomIndex index);
+
+ bool awaitIsKeyword() const {
+ return awaitHandling_ == AwaitIsKeyword ||
+ awaitHandling_ == AwaitIsModuleKeyword;
+ }
+ bool awaitIsDisallowed() const { return awaitHandling_ == AwaitIsDisallowed; }
+
+ bool inParametersOfAsyncFunction() const {
+ return inParametersOfAsyncFunction_;
+ }
+
+ ParseGoal parseGoal() const {
+ return pc_->sc()->hasModuleGoal() ? ParseGoal::Module : ParseGoal::Script;
+ }
+
+ template <class, typename>
+ friend class AutoAwaitIsKeyword;
+ template <class, typename>
+ friend class AutoInParametersOfAsyncFunction;
+
+ ParserBase(FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
+ bool foldConstants, CompilationState& compilationState);
+ ~ParserBase();
+
+ bool checkOptions();
+
+ JS::ConstUTF8CharsZ getFilename() const { return anyChars.getFilename(); }
+ TokenPos pos() const { return anyChars.currentToken().pos; }
+
+ // Determine whether |yield| is a valid name in the current context.
+ bool yieldExpressionsSupported() const { return pc_->isGenerator(); }
+
+ bool setLocalStrictMode(bool strict) {
+ MOZ_ASSERT(anyChars.debugHasNoLookahead());
+ return pc_->sc()->setLocalStrictMode(strict);
+ }
+
+ public:
+ // Implement ErrorReportMixin.
+
+ FrontendContext* getContext() const override { return fc_; }
+
+ bool strictMode() const override { return pc_->sc()->strict(); }
+
+ const JS::ReadOnlyCompileOptions& options() const override {
+ return anyChars.options();
+ }
+
+ using Base::error;
+ using Base::errorAt;
+ using Base::errorNoOffset;
+ using Base::errorWithNotes;
+ using Base::errorWithNotesAt;
+ using Base::errorWithNotesNoOffset;
+ using Base::strictModeError;
+ using Base::strictModeErrorAt;
+ using Base::strictModeErrorNoOffset;
+ using Base::strictModeErrorWithNotes;
+ using Base::strictModeErrorWithNotesAt;
+ using Base::strictModeErrorWithNotesNoOffset;
+ using Base::warning;
+ using Base::warningAt;
+ using Base::warningNoOffset;
+
+ public:
+ bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
+
+ bool isValidStrictBinding(TaggedParserAtomIndex name);
+
+ bool hasValidSimpleStrictParameterNames();
+
+ // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
+ // Parser's state. Note: clients must still take care that any ParseContext
+ // that points into released ParseNodes is destroyed.
+ class Mark {
+ friend class ParserBase;
+ LifoAlloc::Mark mark;
+ CompilationState::CompilationStatePosition pos;
+ };
+ Mark mark() const {
+ Mark m;
+ m.mark = alloc_.mark();
+ m.pos = compilationState_.getPosition();
+ return m;
+ }
+ void release(Mark m) {
+ alloc_.release(m.mark);
+ compilationState_.rewind(m.pos);
+ }
+
+ public:
+ mozilla::Maybe<GlobalScope::ParserData*> newGlobalScopeData(
+ ParseContext::Scope& scope);
+ mozilla::Maybe<ModuleScope::ParserData*> newModuleScopeData(
+ ParseContext::Scope& scope);
+ mozilla::Maybe<EvalScope::ParserData*> newEvalScopeData(
+ ParseContext::Scope& scope);
+ mozilla::Maybe<FunctionScope::ParserData*> newFunctionScopeData(
+ ParseContext::Scope& scope, bool hasParameterExprs);
+ mozilla::Maybe<VarScope::ParserData*> newVarScopeData(
+ ParseContext::Scope& scope);
+ mozilla::Maybe<LexicalScope::ParserData*> newLexicalScopeData(
+ ParseContext::Scope& scope);
+ mozilla::Maybe<ClassBodyScope::ParserData*> newClassBodyScopeData(
+ ParseContext::Scope& scope);
+
+ protected:
+ enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
+ enum ForInitLocation { InForInit, NotInForInit };
+
+ // While on a |let| Name token, examine |next| (which must already be
+ // gotten). Indicate whether |next|, the next token already gotten with
+ // modifier TokenStream::SlashIsDiv, continues a LexicalDeclaration.
+ bool nextTokenContinuesLetDeclaration(TokenKind next);
+
+ bool noteUsedNameInternal(TaggedParserAtomIndex name,
+ NameVisibility visibility,
+ mozilla::Maybe<TokenPos> tokenPosition);
+
+ bool checkAndMarkSuperScope();
+
+ bool leaveInnerFunction(ParseContext* outerpc);
+
+ TaggedParserAtomIndex prefixAccessorName(PropertyType propType,
+ TaggedParserAtomIndex propAtom);
+
+ [[nodiscard]] bool setSourceMapInfo();
+
+ void setFunctionEndFromCurrentToken(FunctionBox* funbox) const;
+};
+
+template <class ParseHandler>
+class MOZ_STACK_CLASS PerHandlerParser : public ParserBase {
+ using Base = ParserBase;
+
+ private:
+ using Node = typename ParseHandler::Node;
+ using NodeResult = typename ParseHandler::NodeResult;
+
+#define DECLARE_TYPE(typeName) \
+ using typeName##Type = typename ParseHandler::typeName##Type; \
+ using typeName##Result = typename ParseHandler::typeName##Result;
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
+#undef DECLARE_TYPE
+
+ protected:
+ /* State specific to the kind of parse being performed. */
+ ParseHandler handler_;
+
+ // When ParseHandler is FullParseHandler:
+ //
+ // If non-null, this field holds the syntax parser used to attempt lazy
+ // parsing of inner functions. If null, then lazy parsing is disabled.
+ //
+ // When ParseHandler is SyntaxParseHandler:
+ //
+ // If non-null, this field must be a sentinel value signaling that the
+ // syntax parse was aborted. If null, then lazy parsing was aborted due
+ // to encountering unsupported language constructs.
+ //
+ // |internalSyntaxParser_| is really a |Parser<SyntaxParseHandler, Unit>*|
+ // where |Unit| varies per |Parser<ParseHandler, Unit>|. But this
+ // template class doesn't know |Unit|, so we store a |void*| here and make
+ // |GeneralParser<ParseHandler, Unit>::getSyntaxParser| impose the real type.
+ void* internalSyntaxParser_;
+
+ private:
+ // NOTE: The argument ordering here is deliberately different from the
+ // public constructor so that typos calling the public constructor
+ // are less likely to select this overload.
+ PerHandlerParser(FrontendContext* fc,
+ const JS::ReadOnlyCompileOptions& options,
+ bool foldConstants, CompilationState& compilationState,
+ void* internalSyntaxParser);
+
+ protected:
+ template <typename Unit>
+ PerHandlerParser(FrontendContext* fc,
+ const JS::ReadOnlyCompileOptions& options,
+ bool foldConstants, CompilationState& compilationState,
+ GeneralParser<SyntaxParseHandler, Unit>* syntaxParser)
+ : PerHandlerParser(fc, options, foldConstants, compilationState,
+ static_cast<void*>(syntaxParser)) {}
+
+ static typename ParseHandler::NullNode null() { return ParseHandler::null(); }
+
+ // The return value for the error case in the functions that returns
+ // Result type.
+ static constexpr typename ParseHandler::NodeErrorResult errorResult() {
+ return ParseHandler::errorResult();
+ }
+
+ NameNodeResult stringLiteral();
+
+ const char* nameIsArgumentsOrEval(Node node);
+
+ bool noteDestructuredPositionalFormalParameter(FunctionNodeType funNode,
+ Node destruct);
+
+ bool noteUsedName(
+ TaggedParserAtomIndex name,
+ NameVisibility visibility = NameVisibility::Public,
+ mozilla::Maybe<TokenPos> tokenPosition = mozilla::Nothing()) {
+ // If the we are delazifying, the BaseScript already has all the closed-over
+ // info for bindings and there's no need to track used names.
+ if (handler_.reuseClosedOverBindings()) {
+ return true;
+ }
+
+ return ParserBase::noteUsedNameInternal(name, visibility, tokenPosition);
+ }
+
+ // Required on Scope exit.
+ bool propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope);
+
+ bool checkForUndefinedPrivateFields(EvalSharedContext* evalSc = nullptr);
+
+ bool finishFunctionScopes(bool isStandaloneFunction);
+ LexicalScopeNodeResult finishLexicalScope(
+ ParseContext::Scope& scope, Node body,
+ ScopeKind kind = ScopeKind::Lexical);
+ ClassBodyScopeNodeResult finishClassBodyScope(ParseContext::Scope& scope,
+ ListNodeType body);
+ bool finishFunction(bool isStandaloneFunction = false);
+
+ inline NameNodeResult newName(TaggedParserAtomIndex name);
+ inline NameNodeResult newName(TaggedParserAtomIndex name, TokenPos pos);
+
+ inline NameNodeResult newPrivateName(TaggedParserAtomIndex name);
+
+ NameNodeResult newInternalDotName(TaggedParserAtomIndex name);
+ NameNodeResult newThisName();
+ NameNodeResult newNewTargetName();
+ NameNodeResult newDotGeneratorName();
+
+ NameNodeResult identifierReference(TaggedParserAtomIndex name);
+ NameNodeResult privateNameReference(TaggedParserAtomIndex name);
+
+ NodeResult noSubstitutionTaggedTemplate();
+
+ inline bool processExport(Node node);
+ inline bool processExportFrom(BinaryNodeType node);
+ inline bool processImport(BinaryNodeType node);
+
+ // If ParseHandler is SyntaxParseHandler:
+ // Do nothing.
+ // If ParseHandler is FullParseHandler:
+ // Disable syntax parsing of all future inner functions during this
+ // full-parse.
+ inline void disableSyntaxParser();
+
+ // If ParseHandler is SyntaxParseHandler:
+ // Flag the current syntax parse as aborted due to unsupported language
+ // constructs and return false. Aborting the current syntax parse does
+ // not disable attempts to syntax-parse future inner functions.
+ // If ParseHandler is FullParseHandler:
+ // Disable syntax parsing of all future inner functions and return true.
+ inline bool abortIfSyntaxParser();
+
+ // If ParseHandler is SyntaxParseHandler:
+ // Return whether the last syntax parse was aborted due to unsupported
+ // language constructs.
+ // If ParseHandler is FullParseHandler:
+ // Return false.
+ inline bool hadAbortedSyntaxParse();
+
+ // If ParseHandler is SyntaxParseHandler:
+ // Clear whether the last syntax parse was aborted.
+ // If ParseHandler is FullParseHandler:
+ // Do nothing.
+ inline void clearAbortedSyntaxParse();
+
+ public:
+ FunctionBox* newFunctionBox(FunctionNodeType funNode,
+ TaggedParserAtomIndex explicitName,
+ FunctionFlags flags, uint32_t toStringStart,
+ Directives directives,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind);
+
+ FunctionBox* newFunctionBox(FunctionNodeType funNode,
+ const ScriptStencil& cachedScriptData,
+ const ScriptStencilExtra& cachedScriptExtra);
+
+ public:
+ // ErrorReportMixin.
+
+ using Base::error;
+ using Base::errorAt;
+ using Base::errorNoOffset;
+ using Base::errorWithNotes;
+ using Base::errorWithNotesAt;
+ using Base::errorWithNotesNoOffset;
+ using Base::strictModeError;
+ using Base::strictModeErrorAt;
+ using Base::strictModeErrorNoOffset;
+ using Base::strictModeErrorWithNotes;
+ using Base::strictModeErrorWithNotesAt;
+ using Base::strictModeErrorWithNotesNoOffset;
+ using Base::warning;
+ using Base::warningAt;
+ using Base::warningNoOffset;
+};
+
+#define ABORTED_SYNTAX_PARSE_SENTINEL reinterpret_cast<void*>(0x1)
+
+template <>
+inline void PerHandlerParser<SyntaxParseHandler>::disableSyntaxParser() {}
+
+template <>
+inline bool PerHandlerParser<SyntaxParseHandler>::abortIfSyntaxParser() {
+ internalSyntaxParser_ = ABORTED_SYNTAX_PARSE_SENTINEL;
+ return false;
+}
+
+template <>
+inline bool PerHandlerParser<SyntaxParseHandler>::hadAbortedSyntaxParse() {
+ return internalSyntaxParser_ == ABORTED_SYNTAX_PARSE_SENTINEL;
+}
+
+template <>
+inline void PerHandlerParser<SyntaxParseHandler>::clearAbortedSyntaxParse() {
+ internalSyntaxParser_ = nullptr;
+}
+
+#undef ABORTED_SYNTAX_PARSE_SENTINEL
+
+// Disable syntax parsing of all future inner functions during this
+// full-parse.
+template <>
+inline void PerHandlerParser<FullParseHandler>::disableSyntaxParser() {
+ internalSyntaxParser_ = nullptr;
+}
+
+template <>
+inline bool PerHandlerParser<FullParseHandler>::abortIfSyntaxParser() {
+ disableSyntaxParser();
+ return true;
+}
+
+template <>
+inline bool PerHandlerParser<FullParseHandler>::hadAbortedSyntaxParse() {
+ return false;
+}
+
+template <>
+inline void PerHandlerParser<FullParseHandler>::clearAbortedSyntaxParse() {}
+
+template <class Parser>
+class ParserAnyCharsAccess {
+ public:
+ using TokenStreamSpecific = typename Parser::TokenStream;
+ using GeneralTokenStreamChars =
+ typename TokenStreamSpecific::GeneralCharsBase;
+
+ static inline TokenStreamAnyChars& anyChars(GeneralTokenStreamChars* ts);
+ static inline const TokenStreamAnyChars& anyChars(
+ const GeneralTokenStreamChars* ts);
+};
+
+// Specify a value for an ES6 grammar parametrization. We have no enum for
+// [Return] because its behavior is almost exactly equivalent to checking
+// whether we're in a function box -- easier and simpler than passing an extra
+// parameter everywhere.
+enum YieldHandling { YieldIsName, YieldIsKeyword };
+enum InHandling { InAllowed, InProhibited };
+enum DefaultHandling { NameRequired, AllowDefaultName };
+enum TripledotHandling { TripledotAllowed, TripledotProhibited };
+
+// For Ergonomic brand checks.
+enum PrivateNameHandling { PrivateNameProhibited, PrivateNameAllowed };
+
+template <class ParseHandler, typename Unit>
+class Parser;
+
+template <class ParseHandler, typename Unit>
+class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
+ public:
+ using TokenStream =
+ TokenStreamSpecific<Unit, ParserAnyCharsAccess<GeneralParser>>;
+
+ private:
+ using Base = PerHandlerParser<ParseHandler>;
+ using FinalParser = Parser<ParseHandler, Unit>;
+ using Node = typename ParseHandler::Node;
+ using NodeResult = typename ParseHandler::NodeResult;
+
+#define DECLARE_TYPE(typeName) \
+ using typeName##Type = typename ParseHandler::typeName##Type; \
+ using typeName##Result = typename ParseHandler::typeName##Result;
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
+#undef DECLARE_TYPE
+
+ using typename Base::InvokedPrediction;
+ using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
+
+ protected:
+ using Modifier = TokenStreamShared::Modifier;
+ using Position = typename TokenStream::Position;
+
+ using Base::PredictInvoked;
+ using Base::PredictUninvoked;
+
+ using Base::alloc_;
+ using Base::awaitIsDisallowed;
+ using Base::awaitIsKeyword;
+ using Base::inParametersOfAsyncFunction;
+ using Base::parseGoal;
+#if DEBUG
+ using Base::checkOptionsCalled_;
+#endif
+ using Base::checkForUndefinedPrivateFields;
+ using Base::errorResult;
+ using Base::finishClassBodyScope;
+ using Base::finishFunctionScopes;
+ using Base::finishLexicalScope;
+ using Base::foldConstants_;
+ using Base::getFilename;
+ using Base::hasValidSimpleStrictParameterNames;
+ using Base::isUnexpectedEOF_;
+ using Base::nameIsArgumentsOrEval;
+ using Base::newDotGeneratorName;
+ using Base::newFunctionBox;
+ using Base::newName;
+ using Base::null;
+ using Base::options;
+ using Base::pos;
+ using Base::propagateFreeNamesAndMarkClosedOverBindings;
+ using Base::setLocalStrictMode;
+ using Base::stringLiteral;
+ using Base::yieldExpressionsSupported;
+
+ using Base::abortIfSyntaxParser;
+ using Base::clearAbortedSyntaxParse;
+ using Base::disableSyntaxParser;
+ using Base::hadAbortedSyntaxParse;
+
+ public:
+ // Implement ErrorReportMixin.
+
+ [[nodiscard]] bool computeErrorMetadata(
+ ErrorMetadata* err,
+ const ErrorReportMixin::ErrorOffset& offset) const override;
+
+ using Base::error;
+ using Base::errorAt;
+ using Base::errorNoOffset;
+ using Base::errorWithNotes;
+ using Base::errorWithNotesAt;
+ using Base::errorWithNotesNoOffset;
+ using Base::strictModeError;
+ using Base::strictModeErrorAt;
+ using Base::strictModeErrorNoOffset;
+ using Base::strictModeErrorWithNotes;
+ using Base::strictModeErrorWithNotesAt;
+ using Base::strictModeErrorWithNotesNoOffset;
+ using Base::warning;
+ using Base::warningAt;
+ using Base::warningNoOffset;
+
+ public:
+ using Base::anyChars;
+ using Base::fc_;
+ using Base::handler_;
+ using Base::noteUsedName;
+ using Base::pc_;
+ using Base::usedNames_;
+
+ private:
+ using Base::checkAndMarkSuperScope;
+ using Base::finishFunction;
+ using Base::identifierReference;
+ using Base::leaveInnerFunction;
+ using Base::newInternalDotName;
+ using Base::newNewTargetName;
+ using Base::newThisName;
+ using Base::nextTokenContinuesLetDeclaration;
+ using Base::noSubstitutionTaggedTemplate;
+ using Base::noteDestructuredPositionalFormalParameter;
+ using Base::prefixAccessorName;
+ using Base::privateNameReference;
+ using Base::processExport;
+ using Base::processExportFrom;
+ using Base::processImport;
+ using Base::setFunctionEndFromCurrentToken;
+
+ private:
+ inline FinalParser* asFinalParser();
+ inline const FinalParser* asFinalParser() const;
+
+ /*
+ * A class for temporarily stashing errors while parsing continues.
+ *
+ * The ability to stash an error is useful for handling situations where we
+ * aren't able to verify that an error has occurred until later in the parse.
+ * For instance | ({x=1}) | is always parsed as an object literal with
+ * a SyntaxError, however, in the case where it is followed by '=>' we rewind
+ * and reparse it as a valid arrow function. Here a PossibleError would be
+ * set to 'pending' when the initial SyntaxError was encountered then
+ * 'resolved' just before rewinding the parser.
+ *
+ * There are currently two kinds of PossibleErrors: Expression and
+ * Destructuring errors. Expression errors are used to mark a possible
+ * syntax error when a grammar production is used in an expression context.
+ * For example in |{x = 1}|, we mark the CoverInitializedName |x = 1| as a
+ * possible expression error, because CoverInitializedName productions
+ * are disallowed when an actual ObjectLiteral is expected.
+ * Destructuring errors are used to record possible syntax errors in
+ * destructuring contexts. For example in |[...rest, ] = []|, we initially
+ * mark the trailing comma after the spread expression as a possible
+ * destructuring error, because the ArrayAssignmentPattern grammar
+ * production doesn't allow a trailing comma after the rest element.
+ *
+ * When using PossibleError one should set a pending error at the location
+ * where an error occurs. From that point, the error may be resolved
+ * (invalidated) or left until the PossibleError is checked.
+ *
+ * Ex:
+ * PossibleError possibleError(*this);
+ * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
+ * // A JSMSG_BAD_PROP_ID ParseError is reported, returns false.
+ * if (!possibleError.checkForExpressionError()) {
+ * return false; // we reach this point with a pending exception
+ * }
+ *
+ * PossibleError possibleError(*this);
+ * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
+ * // Returns true, no error is reported.
+ * if (!possibleError.checkForDestructuringError()) {
+ * return false; // not reached, no pending exception
+ * }
+ *
+ * PossibleError possibleError(*this);
+ * // Returns true, no error is reported.
+ * if (!possibleError.checkForExpressionError()) {
+ * return false; // not reached, no pending exception
+ * }
+ */
+ class MOZ_STACK_CLASS PossibleError {
+ private:
+ enum class ErrorKind { Expression, Destructuring, DestructuringWarning };
+
+ enum class ErrorState { None, Pending };
+
+ struct Error {
+ ErrorState state_ = ErrorState::None;
+
+ // Error reporting fields.
+ uint32_t offset_;
+ unsigned errorNumber_;
+ };
+
+ GeneralParser<ParseHandler, Unit>& parser_;
+ Error exprError_;
+ Error destructuringError_;
+ Error destructuringWarning_;
+
+ // Returns the error report.
+ Error& error(ErrorKind kind);
+
+ // Return true if an error is pending without reporting.
+ bool hasError(ErrorKind kind);
+
+ // Resolve any pending error.
+ void setResolved(ErrorKind kind);
+
+ // Set a pending error. Only a single error may be set per instance and
+ // error kind.
+ void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber);
+
+ // If there is a pending error, report it and return false, otherwise
+ // return true.
+ [[nodiscard]] bool checkForError(ErrorKind kind);
+
+ // Transfer an existing error to another instance.
+ void transferErrorTo(ErrorKind kind, PossibleError* other);
+
+ public:
+ explicit PossibleError(GeneralParser<ParseHandler, Unit>& parser);
+
+ // Return true if a pending destructuring error is present.
+ bool hasPendingDestructuringError();
+
+ // Set a pending destructuring error. Only a single error may be set
+ // per instance, i.e. subsequent calls to this method are ignored and
+ // won't overwrite the existing pending error.
+ void setPendingDestructuringErrorAt(const TokenPos& pos,
+ unsigned errorNumber);
+
+ // Set a pending destructuring warning. Only a single warning may be
+ // set per instance, i.e. subsequent calls to this method are ignored
+ // and won't overwrite the existing pending warning.
+ void setPendingDestructuringWarningAt(const TokenPos& pos,
+ unsigned errorNumber);
+
+ // Set a pending expression error. Only a single error may be set per
+ // instance, i.e. subsequent calls to this method are ignored and won't
+ // overwrite the existing pending error.
+ void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
+
+ // If there is a pending destructuring error or warning, report it and
+ // return false, otherwise return true. Clears any pending expression
+ // error.
+ [[nodiscard]] bool checkForDestructuringErrorOrWarning();
+
+ // If there is a pending expression error, report it and return false,
+ // otherwise return true. Clears any pending destructuring error or
+ // warning.
+ [[nodiscard]] bool checkForExpressionError();
+
+ // Pass pending errors between possible error instances. This is useful
+ // for extending the lifetime of a pending error beyond the scope of
+ // the PossibleError where it was initially set (keeping in mind that
+ // PossibleError is a MOZ_STACK_CLASS).
+ void transferErrorsTo(PossibleError* other);
+ };
+
+ protected:
+ SyntaxParser* getSyntaxParser() const {
+ return reinterpret_cast<SyntaxParser*>(Base::internalSyntaxParser_);
+ }
+
+ public:
+ TokenStream tokenStream;
+
+ public:
+ GeneralParser(FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
+ const Unit* units, size_t length, bool foldConstants,
+ CompilationState& compilationState, SyntaxParser* syntaxParser);
+
+ inline void setAwaitHandling(AwaitHandling awaitHandling);
+ inline void setInParametersOfAsyncFunction(bool inParameters);
+
+ /*
+ * Parse a top-level JS script.
+ */
+ ListNodeResult parse();
+
+ private:
+ /*
+ * Gets the next token and checks if it matches to the given `condition`.
+ * If it matches, returns true.
+ * If it doesn't match, calls `errorReport` to report the error, and
+ * returns false.
+ * If other error happens, it returns false but `errorReport` may not be
+ * called and other error will be thrown in that case.
+ *
+ * In any case, the already gotten token is not ungotten.
+ *
+ * The signature of `condition` is [...](TokenKind actual) -> bool, and
+ * the signature of `errorReport` is [...](TokenKind actual).
+ */
+ template <typename ConditionT, typename ErrorReportT>
+ [[nodiscard]] bool mustMatchTokenInternal(ConditionT condition,
+ ErrorReportT errorReport);
+
+ public:
+ /*
+ * The following mustMatchToken variants follow the behavior and parameter
+ * types of mustMatchTokenInternal above.
+ *
+ * If modifier is omitted, `SlashIsDiv` is used.
+ * If TokenKind is passed instead of `condition`, it checks if the next
+ * token is the passed token.
+ * If error number is passed instead of `errorReport`, it reports an
+ * error with the passed errorNumber.
+ */
+ [[nodiscard]] bool mustMatchToken(TokenKind expected, JSErrNum errorNumber) {
+ return mustMatchTokenInternal(
+ [expected](TokenKind actual) { return actual == expected; },
+ [this, errorNumber](TokenKind) { this->error(errorNumber); });
+ }
+
+ template <typename ConditionT>
+ [[nodiscard]] bool mustMatchToken(ConditionT condition,
+ JSErrNum errorNumber) {
+ return mustMatchTokenInternal(condition, [this, errorNumber](TokenKind) {
+ this->error(errorNumber);
+ });
+ }
+
+ template <typename ErrorReportT>
+ [[nodiscard]] bool mustMatchToken(TokenKind expected,
+ ErrorReportT errorReport) {
+ return mustMatchTokenInternal(
+ [expected](TokenKind actual) { return actual == expected; },
+ errorReport);
+ }
+
+ private:
+ NameNodeResult noSubstitutionUntaggedTemplate();
+ ListNodeResult templateLiteral(YieldHandling yieldHandling);
+ bool taggedTemplate(YieldHandling yieldHandling, ListNodeType tagArgsList,
+ TokenKind tt);
+ bool appendToCallSiteObj(CallSiteNodeType callSiteObj);
+ bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling,
+ ListNodeType nodeList, TokenKind* ttp);
+
+ inline bool trySyntaxParseInnerFunction(
+ FunctionNodeType* funNode, TaggedParserAtomIndex explicitName,
+ FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
+ YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
+ Directives inheritedDirectives, Directives* newDirectives);
+
+ inline bool skipLazyInnerFunction(FunctionNodeType funNode,
+ uint32_t toStringStart, bool tryAnnexB);
+
+ void setFunctionStartAtPosition(FunctionBox* funbox, TokenPos pos) const;
+ void setFunctionStartAtCurrentToken(FunctionBox* funbox) const;
+
+ public:
+ /* Public entry points for parsing. */
+ NodeResult statementListItem(YieldHandling yieldHandling,
+ bool canHaveDirectives = false);
+
+ // Parse an inner function given an enclosing ParseContext and a
+ // FunctionBox for the inner function.
+ [[nodiscard]] FunctionNodeResult innerFunctionForFunctionBox(
+ FunctionNodeType funNode, ParseContext* outerpc, FunctionBox* funbox,
+ InHandling inHandling, YieldHandling yieldHandling,
+ FunctionSyntaxKind kind, Directives* newDirectives);
+
+ // Parse a function's formal parameters and its body assuming its function
+ // ParseContext is already on the stack.
+ bool functionFormalParametersAndBody(
+ InHandling inHandling, YieldHandling yieldHandling,
+ FunctionNodeType* funNode, FunctionSyntaxKind kind,
+ const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing(),
+ bool isStandaloneFunction = false);
+
+ private:
+ /*
+ * JS parsers, from lowest to highest precedence.
+ *
+ * Each parser must be called during the dynamic scope of a ParseContext
+ * object, pointed to by this->pc_.
+ *
+ * Each returns a parse node tree or null on error.
+ */
+ FunctionNodeResult functionStmt(
+ uint32_t toStringStart, YieldHandling yieldHandling,
+ DefaultHandling defaultHandling,
+ FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
+ FunctionNodeResult functionExpr(uint32_t toStringStart,
+ InvokedPrediction invoked,
+ FunctionAsyncKind asyncKind);
+
+ NodeResult statement(YieldHandling yieldHandling);
+ bool maybeParseDirective(ListNodeType list, Node pn, bool* cont);
+
+ LexicalScopeNodeResult blockStatement(
+ YieldHandling yieldHandling,
+ unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
+ BinaryNodeResult doWhileStatement(YieldHandling yieldHandling);
+ BinaryNodeResult whileStatement(YieldHandling yieldHandling);
+
+ NodeResult forStatement(YieldHandling yieldHandling);
+ bool forHeadStart(YieldHandling yieldHandling, IteratorKind iterKind,
+ ParseNodeKind* forHeadKind, Node* forInitialPart,
+ mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
+ Node* forInOrOfExpression);
+ NodeResult expressionAfterForInOrOf(ParseNodeKind forHeadKind,
+ YieldHandling yieldHandling);
+
+ SwitchStatementResult switchStatement(YieldHandling yieldHandling);
+ ContinueStatementResult continueStatement(YieldHandling yieldHandling);
+ BreakStatementResult breakStatement(YieldHandling yieldHandling);
+ UnaryNodeResult returnStatement(YieldHandling yieldHandling);
+ BinaryNodeResult withStatement(YieldHandling yieldHandling);
+ UnaryNodeResult throwStatement(YieldHandling yieldHandling);
+ TernaryNodeResult tryStatement(YieldHandling yieldHandling);
+ LexicalScopeNodeResult catchBlockStatement(
+ YieldHandling yieldHandling, ParseContext::Scope& catchParamScope);
+ DebuggerStatementResult debuggerStatement();
+
+ DeclarationListNodeResult variableStatement(YieldHandling yieldHandling);
+
+ LabeledStatementResult labeledStatement(YieldHandling yieldHandling);
+ NodeResult labeledItem(YieldHandling yieldHandling);
+
+ TernaryNodeResult ifStatement(YieldHandling yieldHandling);
+ NodeResult consequentOrAlternative(YieldHandling yieldHandling);
+
+ DeclarationListNodeResult lexicalDeclaration(YieldHandling yieldHandling,
+ DeclarationKind kind);
+
+ NameNodeResult moduleExportName();
+
+ bool withClause(ListNodeType attributesSet);
+
+ BinaryNodeResult importDeclaration();
+ NodeResult importDeclarationOrImportExpr(YieldHandling yieldHandling);
+ bool namedImports(ListNodeType importSpecSet);
+ bool namespaceImport(ListNodeType importSpecSet);
+
+ TaggedParserAtomIndex importedBinding() {
+ return bindingIdentifier(YieldIsName);
+ }
+
+ BinaryNodeResult exportFrom(uint32_t begin, Node specList);
+ BinaryNodeResult exportBatch(uint32_t begin);
+ inline bool checkLocalExportNames(ListNodeType node);
+ NodeResult exportClause(uint32_t begin);
+ UnaryNodeResult exportFunctionDeclaration(
+ uint32_t begin, uint32_t toStringStart,
+ FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
+ UnaryNodeResult exportVariableStatement(uint32_t begin);
+ UnaryNodeResult exportClassDeclaration(uint32_t begin);
+ UnaryNodeResult exportLexicalDeclaration(uint32_t begin,
+ DeclarationKind kind);
+ BinaryNodeResult exportDefaultFunctionDeclaration(
+ uint32_t begin, uint32_t toStringStart,
+ FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
+ BinaryNodeResult exportDefaultClassDeclaration(uint32_t begin);
+ BinaryNodeResult exportDefaultAssignExpr(uint32_t begin);
+ BinaryNodeResult exportDefault(uint32_t begin);
+ NodeResult exportDeclaration();
+
+ UnaryNodeResult expressionStatement(
+ YieldHandling yieldHandling,
+ InvokedPrediction invoked = PredictUninvoked);
+
+ // Declaration parsing. The main entrypoint is Parser::declarationList,
+ // with sub-functionality split out into the remaining methods.
+
+ // |blockScope| may be non-null only when |kind| corresponds to a lexical
+ // declaration (that is, ParseNodeKind::LetDecl or ParseNodeKind::ConstDecl).
+ //
+ // The for* parameters, for normal declarations, should be null/ignored.
+ // They should be non-null only when Parser::forHeadStart parses a
+ // declaration at the start of a for-loop head.
+ //
+ // In this case, on success |*forHeadKind| is ParseNodeKind::ForHead,
+ // ParseNodeKind::ForIn, or ParseNodeKind::ForOf, corresponding to the three
+ // for-loop kinds. The precise value indicates what was parsed.
+ //
+ // If parsing recognized a for(;;) loop, the next token is the ';' within
+ // the loop-head that separates the init/test parts.
+ //
+ // Otherwise, for for-in/of loops, the next token is the ')' ending the
+ // loop-head. Additionally, the expression that the loop iterates over was
+ // parsed into |*forInOrOfExpression|.
+ DeclarationListNodeResult declarationList(
+ YieldHandling yieldHandling, ParseNodeKind kind,
+ ParseNodeKind* forHeadKind = nullptr,
+ Node* forInOrOfExpression = nullptr);
+
+ // The items in a declaration list are either patterns or names, with or
+ // without initializers. These two methods parse a single pattern/name and
+ // any associated initializer -- and if parsing an |initialDeclaration|
+ // will, if parsing in a for-loop head (as specified by |forHeadKind| being
+ // non-null), consume additional tokens up to the closing ')' in a
+ // for-in/of loop head, returning the iterated expression in
+ // |*forInOrOfExpression|. (An "initial declaration" is the first
+ // declaration in a declaration list: |a| but not |b| in |var a, b|, |{c}|
+ // but not |d| in |let {c} = 3, d|.)
+ NodeResult declarationPattern(DeclarationKind declKind, TokenKind tt,
+ bool initialDeclaration,
+ YieldHandling yieldHandling,
+ ParseNodeKind* forHeadKind,
+ Node* forInOrOfExpression);
+ NodeResult declarationName(DeclarationKind declKind, TokenKind tt,
+ bool initialDeclaration,
+ YieldHandling yieldHandling,
+ ParseNodeKind* forHeadKind,
+ Node* forInOrOfExpression);
+
+ // Having parsed a name (not found in a destructuring pattern) declared by
+ // a declaration, with the current token being the '=' separating the name
+ // from its initializer, parse and bind that initializer -- and possibly
+ // consume trailing in/of and subsequent expression, if so directed by
+ // |forHeadKind|.
+ AssignmentNodeResult initializerInNameDeclaration(NameNodeType binding,
+ DeclarationKind declKind,
+ bool initialDeclaration,
+ YieldHandling yieldHandling,
+ ParseNodeKind* forHeadKind,
+ Node* forInOrOfExpression);
+
+ NodeResult expr(InHandling inHandling, YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError = nullptr,
+ InvokedPrediction invoked = PredictUninvoked);
+ NodeResult assignExpr(InHandling inHandling, YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError = nullptr,
+ InvokedPrediction invoked = PredictUninvoked);
+ NodeResult assignExprWithoutYieldOrAwait(YieldHandling yieldHandling);
+ UnaryNodeResult yieldExpression(InHandling inHandling);
+ NodeResult condExpr(InHandling inHandling, YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError, InvokedPrediction invoked);
+ NodeResult orExpr(InHandling inHandling, YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError, InvokedPrediction invoked);
+ NodeResult unaryExpr(YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError = nullptr,
+ InvokedPrediction invoked = PredictUninvoked,
+ PrivateNameHandling privateNameHandling =
+ PrivateNameHandling::PrivateNameProhibited);
+ NodeResult optionalExpr(YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling, TokenKind tt,
+ PossibleError* possibleError = nullptr,
+ InvokedPrediction invoked = PredictUninvoked);
+ NodeResult memberExpr(YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling, TokenKind tt,
+ bool allowCallSyntax, PossibleError* possibleError,
+ InvokedPrediction invoked);
+ NodeResult decoratorExpr(YieldHandling yieldHandling, TokenKind tt);
+ NodeResult primaryExpr(YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling, TokenKind tt,
+ PossibleError* possibleError,
+ InvokedPrediction invoked);
+ NodeResult exprInParens(InHandling inHandling, YieldHandling yieldHandling,
+ TripledotHandling tripledotHandling,
+ PossibleError* possibleError = nullptr);
+
+ bool tryNewTarget(NewTargetNodeType* newTarget);
+
+ BinaryNodeResult importExpr(YieldHandling yieldHandling,
+ bool allowCallSyntax);
+
+ FunctionNodeResult methodDefinition(uint32_t toStringStart,
+ PropertyType propType,
+ TaggedParserAtomIndex funName);
+
+ /*
+ * Additional JS parsers.
+ */
+ bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ FunctionNodeType funNode);
+
+ FunctionNodeResult functionDefinition(
+ FunctionNodeType funNode, uint32_t toStringStart, InHandling inHandling,
+ YieldHandling yieldHandling, TaggedParserAtomIndex name,
+ FunctionSyntaxKind kind, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind, bool tryAnnexB = false);
+
+ // Parse a function body. Pass StatementListBody if the body is a list of
+ // statements; pass ExpressionBody if the body is a single expression.
+ //
+ // Don't include opening LeftCurly token when invoking.
+ enum FunctionBodyType { StatementListBody, ExpressionBody };
+ LexicalScopeNodeResult functionBody(InHandling inHandling,
+ YieldHandling yieldHandling,
+ FunctionSyntaxKind kind,
+ FunctionBodyType type);
+
+ UnaryNodeResult unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind,
+ uint32_t begin);
+
+ NodeResult condition(InHandling inHandling, YieldHandling yieldHandling);
+
+ ListNodeResult argumentList(YieldHandling yieldHandling, bool* isSpread,
+ PossibleError* possibleError = nullptr);
+ NodeResult destructuringDeclaration(DeclarationKind kind,
+ YieldHandling yieldHandling,
+ TokenKind tt);
+ NodeResult destructuringDeclarationWithoutYieldOrAwait(
+ DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt);
+
+ inline bool checkExportedName(TaggedParserAtomIndex exportName);
+ inline bool checkExportedNamesForArrayBinding(ListNodeType array);
+ inline bool checkExportedNamesForObjectBinding(ListNodeType obj);
+ inline bool checkExportedNamesForDeclaration(Node node);
+ inline bool checkExportedNamesForDeclarationList(
+ DeclarationListNodeType node);
+ inline bool checkExportedNameForFunction(FunctionNodeType funNode);
+ inline bool checkExportedNameForClass(ClassNodeType classNode);
+ inline bool checkExportedNameForClause(NameNodeType nameNode);
+
+ enum ClassContext { ClassStatement, ClassExpression };
+ ClassNodeResult classDefinition(YieldHandling yieldHandling,
+ ClassContext classContext,
+ DefaultHandling defaultHandling);
+
+ struct ClassInitializedMembers {
+#ifdef ENABLE_DECORATORS
+ // Whether a non-static field has decorators or not.
+ bool hasInstanceDecorators = false;
+#endif
+
+ // The number of instance class fields.
+ size_t instanceFields = 0;
+
+ // The number of instance class fields with computed property names.
+ size_t instanceFieldKeys = 0;
+
+ // The number of static class fields.
+ size_t staticFields = 0;
+
+ // The number of static blocks
+ size_t staticBlocks = 0;
+
+ // The number of static class fields with computed property names.
+ size_t staticFieldKeys = 0;
+
+ // The number of instance class private methods.
+ size_t privateMethods = 0;
+
+ // The number of instance class private accessors.
+ size_t privateAccessors = 0;
+
+ bool hasPrivateBrand() const {
+ return privateMethods > 0 || privateAccessors > 0;
+ }
+ };
+#ifdef ENABLE_DECORATORS
+ ListNodeResult decoratorList(YieldHandling yieldHandling);
+#endif
+ [[nodiscard]] bool classMember(
+ YieldHandling yieldHandling,
+ const ParseContext::ClassStatement& classStmt,
+ TaggedParserAtomIndex className, uint32_t classStartOffset,
+ HasHeritage hasHeritage, ClassInitializedMembers& classInitializedMembers,
+ ListNodeType& classMembers, bool* done);
+ [[nodiscard]] bool finishClassConstructor(
+ const ParseContext::ClassStatement& classStmt,
+ TaggedParserAtomIndex className, HasHeritage hasHeritage,
+ uint32_t classStartOffset, uint32_t classEndOffset,
+ const ClassInitializedMembers& classInitializedMembers,
+ ListNodeType& classMembers);
+
+ FunctionNodeResult privateMethodInitializer(
+ TokenPos propNamePos, TaggedParserAtomIndex propAtom,
+ TaggedParserAtomIndex storedMethodAtom);
+ FunctionNodeResult fieldInitializerOpt(
+ TokenPos propNamePos, Node name, TaggedParserAtomIndex atom,
+ ClassInitializedMembers& classInitializedMembers, bool isStatic,
+ HasHeritage hasHeritage);
+
+ FunctionNodeResult synthesizePrivateMethodInitializer(
+ TaggedParserAtomIndex propAtom, AccessorType accessorType,
+ TokenPos propNamePos);
+
+#ifdef ENABLE_DECORATORS
+ FunctionNodeResult synthesizeAddInitializerFunction(
+ TaggedParserAtomIndex initializers, YieldHandling yieldHandling);
+
+ ClassMethodResult synthesizeAccessor(
+ Node propName, TokenPos propNamePos, TaggedParserAtomIndex propAtom,
+ TaggedParserAtomIndex privateStateNameAtom, bool isStatic,
+ FunctionSyntaxKind syntaxKind,
+ ClassInitializedMembers& classInitializedMembers);
+
+ FunctionNodeResult synthesizeAccessorBody(TaggedParserAtomIndex funNameAtom,
+ TokenPos propNamePos,
+ TaggedParserAtomIndex propNameAtom,
+ FunctionSyntaxKind syntaxKind);
+#endif
+
+ FunctionNodeResult staticClassBlock(
+ ClassInitializedMembers& classInitializedMembers);
+
+ FunctionNodeResult synthesizeConstructor(TaggedParserAtomIndex className,
+ TokenPos synthesizedBodyPos,
+ HasHeritage hasHeritage);
+
+ protected:
+ bool synthesizeConstructorBody(TokenPos synthesizedBodyPos,
+ HasHeritage hasHeritage,
+ FunctionNodeType funNode, FunctionBox* funbox);
+
+ private:
+ bool checkBindingIdentifier(TaggedParserAtomIndex ident, uint32_t offset,
+ YieldHandling yieldHandling,
+ TokenKind hint = TokenKind::Limit);
+
+ TaggedParserAtomIndex labelOrIdentifierReference(YieldHandling yieldHandling);
+
+ TaggedParserAtomIndex labelIdentifier(YieldHandling yieldHandling) {
+ return labelOrIdentifierReference(yieldHandling);
+ }
+
+ TaggedParserAtomIndex identifierReference(YieldHandling yieldHandling) {
+ return labelOrIdentifierReference(yieldHandling);
+ }
+
+ bool matchLabel(YieldHandling yieldHandling, TaggedParserAtomIndex* labelOut);
+
+ // Indicate if the next token (tokenized with SlashIsRegExp) is |in| or |of|.
+ // If so, consume it.
+ bool matchInOrOf(bool* isForInp, bool* isForOfp);
+
+ private:
+ bool checkIncDecOperand(Node operand, uint32_t operandOffset);
+ bool checkStrictAssignment(Node lhs);
+
+ void reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
+ uint32_t openedPos);
+
+ void reportRedeclarationHelper(TaggedParserAtomIndex& name,
+ DeclarationKind& prevKind, TokenPos& pos,
+ uint32_t& prevPos, const unsigned& errorNumber,
+ const unsigned& noteErrorNumber);
+
+ void reportRedeclaration(TaggedParserAtomIndex name, DeclarationKind prevKind,
+ TokenPos pos, uint32_t prevPos);
+
+ void reportMismatchedPlacement(TaggedParserAtomIndex name,
+ DeclarationKind prevKind, TokenPos pos,
+ uint32_t prevPos);
+
+ bool notePositionalFormalParameter(FunctionNodeType funNode,
+ TaggedParserAtomIndex name,
+ uint32_t beginPos,
+ bool disallowDuplicateParams,
+ bool* duplicatedParam);
+
+ enum PropertyNameContext {
+ PropertyNameInLiteral,
+ PropertyNameInPattern,
+ PropertyNameInClass,
+#ifdef ENABLE_RECORD_TUPLE
+ PropertyNameInRecord
+#endif
+ };
+ NodeResult propertyName(YieldHandling yieldHandling,
+ PropertyNameContext propertyNameContext,
+ const mozilla::Maybe<DeclarationKind>& maybeDecl,
+ ListNodeType propList,
+ TaggedParserAtomIndex* propAtomOut);
+ NodeResult propertyOrMethodName(
+ YieldHandling yieldHandling, PropertyNameContext propertyNameContext,
+ const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,
+ PropertyType* propType, TaggedParserAtomIndex* propAtomOut);
+ UnaryNodeResult computedPropertyName(
+ YieldHandling yieldHandling,
+ const mozilla::Maybe<DeclarationKind>& maybeDecl,
+ PropertyNameContext propertyNameContext, ListNodeType literal);
+ ListNodeResult arrayInitializer(YieldHandling yieldHandling,
+ PossibleError* possibleError);
+ inline RegExpLiteralResult newRegExp();
+
+ ListNodeResult objectLiteral(YieldHandling yieldHandling,
+ PossibleError* possibleError);
+
+#ifdef ENABLE_RECORD_TUPLE
+ ListNodeResult recordLiteral(YieldHandling yieldHandling);
+ ListNodeResult tupleLiteral(YieldHandling yieldHandling);
+#endif
+
+ BinaryNodeResult bindingInitializer(Node lhs, DeclarationKind kind,
+ YieldHandling yieldHandling);
+ NameNodeResult bindingIdentifier(DeclarationKind kind,
+ YieldHandling yieldHandling);
+ NodeResult bindingIdentifierOrPattern(DeclarationKind kind,
+ YieldHandling yieldHandling,
+ TokenKind tt);
+ ListNodeResult objectBindingPattern(DeclarationKind kind,
+ YieldHandling yieldHandling);
+ ListNodeResult arrayBindingPattern(DeclarationKind kind,
+ YieldHandling yieldHandling);
+
+ enum class TargetBehavior {
+ PermitAssignmentPattern,
+ ForbidAssignmentPattern
+ };
+ bool checkDestructuringAssignmentTarget(
+ Node expr, TokenPos exprPos, PossibleError* exprPossibleError,
+ PossibleError* possibleError,
+ TargetBehavior behavior = TargetBehavior::PermitAssignmentPattern);
+ void checkDestructuringAssignmentName(NameNodeType name, TokenPos namePos,
+ PossibleError* possibleError);
+ bool checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
+ PossibleError* exprPossibleError,
+ PossibleError* possibleError);
+
+ NumericLiteralResult newNumber(const Token& tok) {
+ return handler_.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
+ }
+
+ inline BigIntLiteralResult newBigInt();
+
+ enum class OptionalKind {
+ NonOptional = 0,
+ Optional,
+ };
+ NodeResult memberPropertyAccess(
+ Node lhs, OptionalKind optionalKind = OptionalKind::NonOptional);
+ NodeResult memberPrivateAccess(
+ Node lhs, OptionalKind optionalKind = OptionalKind::NonOptional);
+ NodeResult memberElemAccess(
+ Node lhs, YieldHandling yieldHandling,
+ OptionalKind optionalKind = OptionalKind::NonOptional);
+ NodeResult memberSuperCall(Node lhs, YieldHandling yieldHandling);
+ NodeResult memberCall(TokenKind tt, Node lhs, YieldHandling yieldHandling,
+ PossibleError* possibleError,
+ OptionalKind optionalKind = OptionalKind::NonOptional);
+
+ protected:
+ // Match the current token against the BindingIdentifier production with
+ // the given Yield parameter. If there is no match, report a syntax
+ // error.
+ TaggedParserAtomIndex bindingIdentifier(YieldHandling yieldHandling);
+
+ bool checkLabelOrIdentifierReference(TaggedParserAtomIndex ident,
+ uint32_t offset,
+ YieldHandling yieldHandling,
+ TokenKind hint = TokenKind::Limit);
+
+ ListNodeResult statementList(YieldHandling yieldHandling);
+
+ [[nodiscard]] FunctionNodeResult innerFunction(
+ FunctionNodeType funNode, ParseContext* outerpc,
+ TaggedParserAtomIndex explicitName, FunctionFlags flags,
+ uint32_t toStringStart, InHandling inHandling,
+ YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
+ Directives inheritedDirectives, Directives* newDirectives);
+
+ // Implements Automatic Semicolon Insertion.
+ //
+ // Use this to match `;` in contexts where ASI is allowed. Call this after
+ // ruling out all other possibilities except `;`, by peeking ahead if
+ // necessary.
+ //
+ // Unlike most optional Modifiers, this method's `modifier` argument defaults
+ // to SlashIsRegExp, since that's by far the most common case: usually an
+ // optional semicolon is at the end of a statement or declaration, and the
+ // next token could be a RegExp literal beginning a new ExpressionStatement.
+ bool matchOrInsertSemicolon(Modifier modifier = TokenStream::SlashIsRegExp);
+
+ bool noteDeclaredName(TaggedParserAtomIndex name, DeclarationKind kind,
+ TokenPos pos, ClosedOver isClosedOver = ClosedOver::No);
+
+ bool noteDeclaredPrivateName(Node nameNode, TaggedParserAtomIndex name,
+ PropertyType propType, FieldPlacement placement,
+ TokenPos pos);
+
+ private:
+ inline bool asmJS(ListNodeType list);
+};
+
+template <typename Unit>
+class MOZ_STACK_CLASS Parser<SyntaxParseHandler, Unit> final
+ : public GeneralParser<SyntaxParseHandler, Unit> {
+ using Base = GeneralParser<SyntaxParseHandler, Unit>;
+ using Node = SyntaxParseHandler::Node;
+ using NodeResult = typename SyntaxParseHandler::NodeResult;
+
+#define DECLARE_TYPE(typeName) \
+ using typeName##Type = SyntaxParseHandler::typeName##Type; \
+ using typeName##Result = SyntaxParseHandler::typeName##Result;
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
+#undef DECLARE_TYPE
+
+ using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
+
+ // Numerous Base::* functions have bodies like
+ //
+ // return asFinalParser()->func(...);
+ //
+ // and must be able to call functions here. Add a friendship relationship
+ // so functions here can be hidden when appropriate.
+ friend class GeneralParser<SyntaxParseHandler, Unit>;
+
+ public:
+ using Base::Base;
+
+ // Inherited types, listed here to have non-dependent names.
+ using typename Base::Modifier;
+ using typename Base::Position;
+ using typename Base::TokenStream;
+
+ // Inherited functions, listed here to have non-dependent names.
+
+ public:
+ using Base::anyChars;
+ using Base::clearAbortedSyntaxParse;
+ using Base::hadAbortedSyntaxParse;
+ using Base::innerFunctionForFunctionBox;
+ using Base::tokenStream;
+
+ public:
+ // ErrorReportMixin.
+
+ using Base::error;
+ using Base::errorAt;
+ using Base::errorNoOffset;
+ using Base::errorWithNotes;
+ using Base::errorWithNotesAt;
+ using Base::errorWithNotesNoOffset;
+ using Base::strictModeError;
+ using Base::strictModeErrorAt;
+ using Base::strictModeErrorNoOffset;
+ using Base::strictModeErrorWithNotes;
+ using Base::strictModeErrorWithNotesAt;
+ using Base::strictModeErrorWithNotesNoOffset;
+ using Base::warning;
+ using Base::warningAt;
+ using Base::warningNoOffset;
+
+ private:
+ using Base::alloc_;
+#if DEBUG
+ using Base::checkOptionsCalled_;
+#endif
+ using Base::checkForUndefinedPrivateFields;
+ using Base::errorResult;
+ using Base::finishFunctionScopes;
+ using Base::functionFormalParametersAndBody;
+ using Base::handler_;
+ using Base::innerFunction;
+ using Base::matchOrInsertSemicolon;
+ using Base::mustMatchToken;
+ using Base::newFunctionBox;
+ using Base::newLexicalScopeData;
+ using Base::newModuleScopeData;
+ using Base::newName;
+ using Base::noteDeclaredName;
+ using Base::null;
+ using Base::options;
+ using Base::pc_;
+ using Base::pos;
+ using Base::propagateFreeNamesAndMarkClosedOverBindings;
+ using Base::ss;
+ using Base::statementList;
+ using Base::stringLiteral;
+ using Base::usedNames_;
+
+ private:
+ using Base::abortIfSyntaxParser;
+ using Base::disableSyntaxParser;
+
+ public:
+ // Functions with multiple overloads of different visibility. We can't
+ // |using| the whole thing into existence because of the visibility
+ // distinction, so we instead must manually delegate the required overload.
+
+ TaggedParserAtomIndex bindingIdentifier(YieldHandling yieldHandling) {
+ return Base::bindingIdentifier(yieldHandling);
+ }
+
+ // Functions present in both Parser<ParseHandler, Unit> specializations.
+
+ inline void setAwaitHandling(AwaitHandling awaitHandling);
+ inline void setInParametersOfAsyncFunction(bool inParameters);
+
+ RegExpLiteralResult newRegExp();
+ BigIntLiteralResult newBigInt();
+
+ // Parse a module.
+ ModuleNodeResult moduleBody(ModuleSharedContext* modulesc);
+
+ inline bool checkLocalExportNames(ListNodeType node);
+ inline bool checkExportedName(TaggedParserAtomIndex exportName);
+ inline bool checkExportedNamesForArrayBinding(ListNodeType array);
+ inline bool checkExportedNamesForObjectBinding(ListNodeType obj);
+ inline bool checkExportedNamesForDeclaration(Node node);
+ inline bool checkExportedNamesForDeclarationList(
+ DeclarationListNodeType node);
+ inline bool checkExportedNameForFunction(FunctionNodeType funNode);
+ inline bool checkExportedNameForClass(ClassNodeType classNode);
+ inline bool checkExportedNameForClause(NameNodeType nameNode);
+
+ bool trySyntaxParseInnerFunction(
+ FunctionNodeType* funNode, TaggedParserAtomIndex explicitName,
+ FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
+ YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
+ Directives inheritedDirectives, Directives* newDirectives);
+
+ bool skipLazyInnerFunction(FunctionNodeType funNode, uint32_t toStringStart,
+ bool tryAnnexB);
+
+ bool asmJS(ListNodeType list);
+
+ // Functions present only in Parser<SyntaxParseHandler, Unit>.
+};
+
+template <typename Unit>
+class MOZ_STACK_CLASS Parser<FullParseHandler, Unit> final
+ : public GeneralParser<FullParseHandler, Unit> {
+ using Base = GeneralParser<FullParseHandler, Unit>;
+ using Node = FullParseHandler::Node;
+ using NodeResult = typename FullParseHandler::NodeResult;
+
+#define DECLARE_TYPE(typeName) \
+ using typeName##Type = FullParseHandler::typeName##Type; \
+ using typeName##Result = FullParseHandler::typeName##Result;
+ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
+#undef DECLARE_TYPE
+
+ using SyntaxParser = Parser<SyntaxParseHandler, Unit>;
+
+ // Numerous Base::* functions have bodies like
+ //
+ // return asFinalParser()->func(...);
+ //
+ // and must be able to call functions here. Add a friendship relationship
+ // so functions here can be hidden when appropriate.
+ friend class GeneralParser<FullParseHandler, Unit>;
+
+ public:
+ using Base::Base;
+
+ // Inherited types, listed here to have non-dependent names.
+ using typename Base::Modifier;
+ using typename Base::Position;
+ using typename Base::TokenStream;
+
+ // Inherited functions, listed here to have non-dependent names.
+
+ public:
+ using Base::anyChars;
+ using Base::clearAbortedSyntaxParse;
+ using Base::functionFormalParametersAndBody;
+ using Base::hadAbortedSyntaxParse;
+ using Base::handler_;
+ using Base::newFunctionBox;
+ using Base::options;
+ using Base::pc_;
+ using Base::pos;
+ using Base::ss;
+ using Base::tokenStream;
+
+ public:
+ // ErrorReportMixin.
+
+ using Base::error;
+ using Base::errorAt;
+ using Base::errorNoOffset;
+ using Base::errorWithNotes;
+ using Base::errorWithNotesAt;
+ using Base::errorWithNotesNoOffset;
+ using Base::strictModeError;
+ using Base::strictModeErrorAt;
+ using Base::strictModeErrorNoOffset;
+ using Base::strictModeErrorWithNotes;
+ using Base::strictModeErrorWithNotesAt;
+ using Base::strictModeErrorWithNotesNoOffset;
+ using Base::warning;
+ using Base::warningAt;
+ using Base::warningNoOffset;
+
+ private:
+ using Base::alloc_;
+ using Base::checkLabelOrIdentifierReference;
+#if DEBUG
+ using Base::checkOptionsCalled_;
+#endif
+ using Base::checkForUndefinedPrivateFields;
+ using Base::errorResult;
+ using Base::fc_;
+ using Base::finishClassBodyScope;
+ using Base::finishFunctionScopes;
+ using Base::finishLexicalScope;
+ using Base::innerFunction;
+ using Base::innerFunctionForFunctionBox;
+ using Base::matchOrInsertSemicolon;
+ using Base::mustMatchToken;
+ using Base::newEvalScopeData;
+ using Base::newFunctionScopeData;
+ using Base::newGlobalScopeData;
+ using Base::newLexicalScopeData;
+ using Base::newModuleScopeData;
+ using Base::newName;
+ using Base::newVarScopeData;
+ using Base::noteDeclaredName;
+ using Base::noteUsedName;
+ using Base::null;
+ using Base::propagateFreeNamesAndMarkClosedOverBindings;
+ using Base::statementList;
+ using Base::stringLiteral;
+ using Base::usedNames_;
+
+ using Base::abortIfSyntaxParser;
+ using Base::disableSyntaxParser;
+ using Base::getSyntaxParser;
+
+ public:
+ // Functions with multiple overloads of different visibility. We can't
+ // |using| the whole thing into existence because of the visibility
+ // distinction, so we instead must manually delegate the required overload.
+
+ TaggedParserAtomIndex bindingIdentifier(YieldHandling yieldHandling) {
+ return Base::bindingIdentifier(yieldHandling);
+ }
+
+ // Functions present in both Parser<ParseHandler, Unit> specializations.
+
+ friend class AutoAwaitIsKeyword<SyntaxParseHandler, Unit>;
+ inline void setAwaitHandling(AwaitHandling awaitHandling);
+
+ friend class AutoInParametersOfAsyncFunction<SyntaxParseHandler, Unit>;
+ inline void setInParametersOfAsyncFunction(bool inParameters);
+
+ RegExpLiteralResult newRegExp();
+ BigIntLiteralResult newBigInt();
+
+ // Parse a module.
+ ModuleNodeResult moduleBody(ModuleSharedContext* modulesc);
+
+ bool checkLocalExportNames(ListNodeType node);
+ bool checkExportedName(TaggedParserAtomIndex exportName);
+ bool checkExportedNamesForArrayBinding(ListNodeType array);
+ bool checkExportedNamesForObjectBinding(ListNodeType obj);
+ bool checkExportedNamesForDeclaration(Node node);
+ bool checkExportedNamesForDeclarationList(DeclarationListNodeType node);
+ bool checkExportedNameForFunction(FunctionNodeType funNode);
+ bool checkExportedNameForClass(ClassNodeType classNode);
+ inline bool checkExportedNameForClause(NameNodeType nameNode);
+
+ bool trySyntaxParseInnerFunction(
+ FunctionNodeType* funNode, TaggedParserAtomIndex explicitName,
+ FunctionFlags flags, uint32_t toStringStart, InHandling inHandling,
+ YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
+ Directives inheritedDirectives, Directives* newDirectives);
+
+ [[nodiscard]] bool advancePastSyntaxParsedFunction(
+ SyntaxParser* syntaxParser);
+
+ bool skipLazyInnerFunction(FunctionNodeType funNode, uint32_t toStringStart,
+ bool tryAnnexB);
+
+ // Functions present only in Parser<FullParseHandler, Unit>.
+
+ // Parse the body of an eval.
+ //
+ // Eval scripts are distinguished from global scripts in that in ES6, per
+ // 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
+ // lexical scope.
+ LexicalScopeNodeResult evalBody(EvalSharedContext* evalsc);
+
+ // Parse a function, given only its arguments and body. Used for lazily
+ // parsed functions.
+ FunctionNodeResult standaloneLazyFunction(CompilationInput& input,
+ uint32_t toStringStart, bool strict,
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind);
+
+ // Parse a function, used for the Function, GeneratorFunction, and
+ // AsyncFunction constructors.
+ FunctionNodeResult standaloneFunction(
+ const mozilla::Maybe<uint32_t>& parameterListEnd,
+ FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind, Directives inheritedDirectives,
+ Directives* newDirectives);
+
+ bool checkStatementsEOF();
+
+ // Parse the body of a global script.
+ ListNodeResult globalBody(GlobalSharedContext* globalsc);
+
+ bool checkLocalExportName(TaggedParserAtomIndex ident, uint32_t offset) {
+ return checkLabelOrIdentifierReference(ident, offset, YieldIsName);
+ }
+
+ bool asmJS(ListNodeType list);
+};
+
+template <class Parser>
+/* static */ inline const TokenStreamAnyChars&
+ParserAnyCharsAccess<Parser>::anyChars(const GeneralTokenStreamChars* ts) {
+ // The structure we're walking through looks like this:
+ //
+ // struct ParserBase
+ // {
+ // ...;
+ // TokenStreamAnyChars anyChars;
+ // ...;
+ // };
+ // struct Parser : <class that ultimately inherits from ParserBase>
+ // {
+ // ...;
+ // TokenStreamSpecific tokenStream;
+ // ...;
+ // };
+ //
+ // We're passed a GeneralTokenStreamChars* (this being a base class of
+ // Parser::tokenStream). We cast that pointer to a TokenStreamSpecific*,
+ // then translate that to the enclosing Parser*, then return the |anyChars|
+ // member within.
+
+ static_assert(std::is_base_of_v<GeneralTokenStreamChars, TokenStreamSpecific>,
+ "the static_cast<> below assumes a base-class relationship");
+ const auto* tss = static_cast<const TokenStreamSpecific*>(ts);
+
+ auto tssAddr = reinterpret_cast<uintptr_t>(tss);
+
+ using ActualTokenStreamType = decltype(std::declval<Parser>().tokenStream);
+ static_assert(std::is_same_v<ActualTokenStreamType, TokenStreamSpecific>,
+ "Parser::tokenStream must have type TokenStreamSpecific");
+
+ uintptr_t parserAddr = tssAddr - offsetof(Parser, tokenStream);
+
+ return reinterpret_cast<const Parser*>(parserAddr)->anyChars;
+}
+
+template <class Parser>
+/* static */ inline TokenStreamAnyChars& ParserAnyCharsAccess<Parser>::anyChars(
+ GeneralTokenStreamChars* ts) {
+ const TokenStreamAnyChars& anyCharsConst =
+ anyChars(const_cast<const GeneralTokenStreamChars*>(ts));
+
+ return const_cast<TokenStreamAnyChars&>(anyCharsConst);
+}
+
+template <class ParseHandler, typename Unit>
+class MOZ_STACK_CLASS AutoAwaitIsKeyword {
+ using GeneralParser = frontend::GeneralParser<ParseHandler, Unit>;
+
+ private:
+ GeneralParser* parser_;
+ AwaitHandling oldAwaitHandling_;
+
+ public:
+ AutoAwaitIsKeyword(GeneralParser* parser, AwaitHandling awaitHandling) {
+ parser_ = parser;
+ oldAwaitHandling_ = static_cast<AwaitHandling>(parser_->awaitHandling_);
+
+ // 'await' is always a keyword in module contexts, so we don't modify
+ // the state when the original handling is AwaitIsModuleKeyword.
+ if (oldAwaitHandling_ != AwaitIsModuleKeyword) {
+ parser_->setAwaitHandling(awaitHandling);
+ }
+ }
+
+ ~AutoAwaitIsKeyword() { parser_->setAwaitHandling(oldAwaitHandling_); }
+};
+
+template <class ParseHandler, typename Unit>
+class MOZ_STACK_CLASS AutoInParametersOfAsyncFunction {
+ using GeneralParser = frontend::GeneralParser<ParseHandler, Unit>;
+
+ private:
+ GeneralParser* parser_;
+ bool oldInParametersOfAsyncFunction_;
+
+ public:
+ AutoInParametersOfAsyncFunction(GeneralParser* parser, bool inParameters) {
+ parser_ = parser;
+ oldInParametersOfAsyncFunction_ = parser_->inParametersOfAsyncFunction_;
+ parser_->setInParametersOfAsyncFunction(inParameters);
+ }
+
+ ~AutoInParametersOfAsyncFunction() {
+ parser_->setInParametersOfAsyncFunction(oldInParametersOfAsyncFunction_);
+ }
+};
+
+GlobalScope::ParserData* NewEmptyGlobalScopeData(FrontendContext* fc,
+ LifoAlloc& alloc,
+ uint32_t numBindings);
+
+VarScope::ParserData* NewEmptyVarScopeData(FrontendContext* fc,
+ LifoAlloc& alloc,
+ uint32_t numBindings);
+
+LexicalScope::ParserData* NewEmptyLexicalScopeData(FrontendContext* fc,
+ LifoAlloc& alloc,
+ uint32_t numBindings);
+
+FunctionScope::ParserData* NewEmptyFunctionScopeData(FrontendContext* fc,
+ LifoAlloc& alloc,
+ uint32_t numBindings);
+
+bool FunctionScopeHasClosedOverBindings(ParseContext* pc);
+bool LexicalScopeHasClosedOverBindings(ParseContext* pc,
+ ParseContext::Scope& scope);
+
+} /* namespace frontend */
+} /* namespace js */
+
+#endif /* frontend_Parser_h */