Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/frontend/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 416 kB image not shown  

Quelle  Parser.cpp   Sprache: C

 
/* -*- 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.
 *
 * This is a recursive-descent parser for the JavaScript language specified by
 * "The ECMAScript Language Specification" (Standard ECMA-262).  It uses
 * lexical and semantic feedback to disambiguate non-LL(1) structures.  It
 * generates trees of nodes induced by the recursive parsing (not precise
 * syntax trees, see Parser.h).  After tree construction, it rewrites trees to
 * fold constants and evaluate compile-time expressions.
 *
 * This parser attempts no error recovery.
 */


#include "frontend/Parser.h"

#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/Range.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Try.h"  // MOZ_TRY*
#include "mozilla/Utf8.h"
#include "mozilla/Variant.h"

#include <memory>
#include <new>
#include <type_traits>

#include "jsnum.h"
#include "jstypes.h"

#include "frontend/FoldConstants.h"
#include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
#include "frontend/ModuleSharedContext.h"
#include "frontend/ParseNode.h"
#include "frontend/ParseNodeVerify.h"
#include "frontend/Parser-macros.h"  // MOZ_TRY_VAR_OR_RETURN
#include "frontend/ParserAtom.h"  // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom
#include "frontend/ScriptIndex.h"  // ScriptIndex
#include "frontend/TokenStream.h"  // IsKeyword, ReservedWordTokenKind, ReservedWordToCharZ, DeprecatedContent, *TokenStream*, CharBuffer, TokenKindToDesc
#include "irregexp/RegExpAPI.h"
#include "js/ColumnNumber.h"  // JS::LimitedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
#include "js/ErrorReport.h"           // JSErrorBase
#include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
#include "js/HashTable.h"
#include "js/RegExpFlags.h"      // JS::RegExpFlags
#include "js/Stack.h"            // JS::NativeStackLimit
#include "util/StringBuilder.h"  // StringBuilder
#include "vm/BytecodeUtil.h"
#include "vm/FunctionFlags.h"          // js::FunctionFlags
#include "vm/GeneratorAndAsyncKind.h"  // js::GeneratorKind, js::FunctionAsyncKind
#include "vm/JSContext.h"
#include "vm/JSScript.h"
#include "vm/ModuleBuilder.h"  // js::ModuleBuilder
#include "vm/Scope.h"          // GetScopeDataTrailingNames
#include "wasm/AsmJS.h"

#include "frontend/ParseContext-inl.h"
#include "frontend/SharedContext-inl.h"

using namespace js;

using mozilla::AssertedCast;
using mozilla::AsVariant;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::PointerRangeSize;
using mozilla::Some;
using mozilla::Utf8Unit;

using JS::ReadOnlyCompileOptions;
using JS::RegExpFlags;

namespace js::frontend {

using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
using BindingIter = ParseContext::Scope::BindingIter;
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;

using ParserBindingNameVector = Vector<ParserBindingName, 6>;

static inline void PropagateTransitiveParseFlags(const FunctionBox* inner,
                                                 SharedContext* outer) {
  if (inner->bindingsAccessedDynamically()) {
    outer->setBindingsAccessedDynamically();
  }
  if (inner->hasDirectEval()) {
    outer->setHasDirectEval();
  }
}

static bool StatementKindIsBraced(StatementKind kind) {
  return kind == StatementKind::Block || kind == StatementKind::Switch ||
         kind == StatementKind::Try || kind == StatementKind::Catch ||
         kind == StatementKind::Finally;
}

template <class ParseHandler, typename Unit>
inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
GeneralParser<ParseHandler, Unit>::asFinalParser() {
  static_assert(
      std::is_base_of_v<GeneralParser<ParseHandler, Unit>, FinalParser>,
      "inheritance relationship required by the static_cast<> below");

  return static_cast<FinalParser*>(this);
}

template <class ParseHandler, typename Unit>
inline const typename GeneralParser<ParseHandler, Unit>::FinalParser*
GeneralParser<ParseHandler, Unit>::asFinalParser() const {
  static_assert(
      std::is_base_of_v<GeneralParser<ParseHandler, Unit>, FinalParser>,
      "inheritance relationship required by the static_cast<> below");

  return static_cast<const FinalParser*>(this);
}

template <class ParseHandler, typename Unit>
template <typename ConditionT, typename ErrorReportT>
bool GeneralParser<ParseHandler, Unit>::mustMatchTokenInternal(
    ConditionT condition, ErrorReportT errorReport) {
  MOZ_ASSERT(condition(TokenKind::Div) == false);
  MOZ_ASSERT(condition(TokenKind::DivAssign) == false);
  MOZ_ASSERT(condition(TokenKind::RegExp) == false);

  TokenKind actual;
  if (!tokenStream.getToken(&actual, TokenStream::SlashIsInvalid)) {
    return false;
  }
  if (!condition(actual)) {
    errorReport(actual);
    return false;
  }
  return true;
}

ParserSharedBase::ParserSharedBase(FrontendContext* fc,
                                   CompilationState& compilationState,
                                   Kind kind)
    : fc_(fc),
      alloc_(compilationState.parserAllocScope.alloc()),
      compilationState_(compilationState),
      pc_(nullptr),
      usedNames_(compilationState.usedNames) {
  fc_->nameCollectionPool().addActiveCompilation();
}

ParserSharedBase::~ParserSharedBase() {
  fc_->nameCollectionPool().removeActiveCompilation();
}

#if defined(DEBUG) || defined(JS_JITSPEW)
void ParserSharedBase::dumpAtom(TaggedParserAtomIndex index) const {
  parserAtoms().dump(index);
}
#endif

ParserBase::ParserBase(FrontendContext* fc,
                       const ReadOnlyCompileOptions& options,
                       CompilationState& compilationState)
    : ParserSharedBase(fc, compilationState, ParserSharedBase::Kind::Parser),
      anyChars(fc, options, this),
      ss(nullptr),
#ifdef DEBUG
      checkOptionsCalled_(false),
#endif
      isUnexpectedEOF_(false),
      awaitHandling_(AwaitIsName),
      inParametersOfAsyncFunction_(false) {
}

bool ParserBase::checkOptions() {
#ifdef DEBUG
  checkOptionsCalled_ = true;
#endif

  return anyChars.checkOptions();
}

ParserBase::~ParserBase() { MOZ_ASSERT(checkOptionsCalled_); }

JSAtom* ParserBase::liftParserAtomToJSAtom(TaggedParserAtomIndex index) {
  JSContext* cx = fc_->maybeCurrentJSContext();
  MOZ_ASSERT(cx);
  return parserAtoms().toJSAtom(cx, fc_, index,
                                compilationState_.input.atomCache);
}

template <class ParseHandler>
PerHandlerParser<ParseHandler>::PerHandlerParser(
    FrontendContext* fc, const ReadOnlyCompileOptions& options,
    CompilationState& compilationState, void* internalSyntaxParser)
    : ParserBase(fc, options, compilationState),
      handler_(fc, compilationState),
      internalSyntaxParser_(internalSyntaxParser) {
  MOZ_ASSERT(compilationState.isInitialStencil() ==
             compilationState.input.isInitialStencil());
}

template <class ParseHandler, typename Unit>
GeneralParser<ParseHandler, Unit>::GeneralParser(
    FrontendContext* fc, const ReadOnlyCompileOptions& options,
    const Unit* units, size_t length, CompilationState& compilationState,
    SyntaxParser* syntaxParser)
    : Base(fc, options, compilationState, syntaxParser),
      tokenStream(fc, &compilationState.parserAtoms, options, units, length) {}

template <typename Unit>
void Parser<SyntaxParseHandler, Unit>::setAwaitHandling(
    AwaitHandling awaitHandling) {
  this->awaitHandling_ = awaitHandling;
}

template <typename Unit>
void Parser<FullParseHandler, Unit>::setAwaitHandling(
    AwaitHandling awaitHandling) {
  this->awaitHandling_ = awaitHandling;
  if (SyntaxParser* syntaxParser = getSyntaxParser()) {
    syntaxParser->setAwaitHandling(awaitHandling);
  }
}

template <class ParseHandler, typename Unit>
inline void GeneralParser<ParseHandler, Unit>::setAwaitHandling(
    AwaitHandling awaitHandling) {
  asFinalParser()->setAwaitHandling(awaitHandling);
}

template <typename Unit>
void Parser<SyntaxParseHandler, Unit>::setInParametersOfAsyncFunction(
    bool inParameters) {
  this->inParametersOfAsyncFunction_ = inParameters;
}

template <typename Unit>
void Parser<FullParseHandler, Unit>::setInParametersOfAsyncFunction(
    bool inParameters) {
  this->inParametersOfAsyncFunction_ = inParameters;
  if (SyntaxParser* syntaxParser = getSyntaxParser()) {
    syntaxParser->setInParametersOfAsyncFunction(inParameters);
  }
}

template <class ParseHandler, typename Unit>
inline void GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(
    bool inParameters) {
  asFinalParser()->setInParametersOfAsyncFunction(inParameters);
}

template <class ParseHandler>
FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
    FunctionNodeType funNode, TaggedParserAtomIndex explicitName,
    FunctionFlags flags, uint32_t toStringStart, Directives inheritedDirectives,
    GeneratorKind generatorKind, FunctionAsyncKind asyncKind) {
  MOZ_ASSERT(funNode);

  ScriptIndex index = ScriptIndex(compilationState_.scriptData.length());
  if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
    ReportAllocationOverflow(fc_);
    return nullptr;
  }
  if (!compilationState_.appendScriptStencilAndData(fc_)) {
    return nullptr;
  }

  bool isInitialStencil = compilationState_.isInitialStencil();

  // This source extent will be further filled in during the remainder of parse.
  SourceExtent extent;
  extent.toStringStart = toStringStart;

  FunctionBox* funbox = alloc_.new_<FunctionBox>(
      fc_, extent, compilationState_, inheritedDirectives, generatorKind,
      asyncKind, isInitialStencil, explicitName, flags, index);
  if (!funbox) {
    ReportOutOfMemory(fc_);
    return nullptr;
  }

  handler_.setFunctionBox(funNode, funbox);

  return funbox;
}

template <class ParseHandler>
FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
    FunctionNodeType funNode, const ScriptStencil& cachedScriptData,
    const ScriptStencilExtra& cachedScriptExtra) {
  MOZ_ASSERT(funNode);

  ScriptIndex index = ScriptIndex(compilationState_.scriptData.length());
  if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) {
    ReportAllocationOverflow(fc_);
    return nullptr;
  }
  if (!compilationState_.appendScriptStencilAndData(fc_)) {
    return nullptr;
  }

  FunctionBox* funbox = alloc_.new_<FunctionBox>(
      fc_, cachedScriptExtra.extent, compilationState_,
      Directives(/* strict = */ false), cachedScriptExtra.generatorKind(),
      cachedScriptExtra.asyncKind(), compilationState_.isInitialStencil(),
      cachedScriptData.functionAtom, cachedScriptData.functionFlags, index);
  if (!funbox) {
    ReportOutOfMemory(fc_);
    return nullptr;
  }

  handler_.setFunctionBox(funNode, funbox);
  funbox->initFromScriptStencilExtra(cachedScriptExtra);

  return funbox;
}

bool ParserBase::setSourceMapInfo() {
  // If support for source pragmas have been fully disabled, we can skip
  // processing of all of these values.
  if (!options().sourcePragmas()) {
    return true;
  }

  // Not all clients initialize ss. Can't update info to an object that isn't
  // there.
  if (!ss) {
    return true;
  }

  if (anyChars.hasDisplayURL()) {
    if (!ss->setDisplayURL(fc_, anyChars.displayURL())) {
      return false;
    }
  }

  if (anyChars.hasSourceMapURL()) {
    MOZ_ASSERT(!ss->hasSourceMapURL());
    if (!ss->setSourceMapURL(fc_, anyChars.sourceMapURL())) {
      return false;
    }
  }

  /*
   * Source map URLs passed as a compile option (usually via a HTTP source map
   * header) override any source map urls passed as comment pragmas.
   */

  if (options().sourceMapURL()) {
    // Warn about the replacement, but use the new one.
    if (ss->hasSourceMapURL()) {
      if (!warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA, ss->filename(),
                           "//# sourceMappingURL")) {
        return false;
      }
    }

    if (!ss->setSourceMapURL(fc_, options().sourceMapURL())) {
      return false;
    }
  }

  return true;
}

/*
 * Parse a top-level JS script.
 */

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeResult
GeneralParser<ParseHandler, Unit>::parse() {
  MOZ_ASSERT(checkOptionsCalled_);

  SourceExtent extent = SourceExtent::makeGlobalExtent(
      /* len = */ 0, options().lineno,
      JS::LimitedColumnNumberOneOrigin::fromUnlimited(
          JS::ColumnNumberOneOrigin(options().column)));
  Directives directives(options().forceStrictMode());
  GlobalSharedContext globalsc(this->fc_, ScopeKind::Global, options(),
                               directives, extent);
  SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
  if (!globalpc.init()) {
    return errorResult();
  }

  ParseContext::VarScope varScope(this);
  if (!varScope.init(pc_)) {
    return errorResult();
  }

  ListNodeType stmtList;
  MOZ_TRY_VAR(stmtList, statementList(YieldIsName));

  TokenKind tt;
  if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
    return errorResult();
  }
  if (tt != TokenKind::Eof) {
    error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
    return errorResult();
  }

  if (!CheckParseTree(this->fc_, alloc_, stmtList)) {
    return errorResult();
  }

  return stmtList;
}

/*
 * Strict mode forbids introducing new definitions for 'eval', 'arguments',
 * 'let', 'static', 'yield', or for any strict mode reserved word.
 */

bool ParserBase::isValidStrictBinding(TaggedParserAtomIndex name) {
  TokenKind tt = ReservedWordTokenKind(name);
  if (tt == TokenKind::Limit) {
    return name != TaggedParserAtomIndex::WellKnown::eval() &&
           name != TaggedParserAtomIndex::WellKnown::arguments();
  }
  return tt != TokenKind::Let && tt != TokenKind::Static &&
         tt != TokenKind::Yield && !TokenKindIsStrictReservedWord(tt);
}

/*
 * Returns true if all parameter names are valid strict mode binding names and
 * no duplicate parameter names are present.
 */

bool ParserBase::hasValidSimpleStrictParameterNames() {
  MOZ_ASSERT(pc_->isFunctionBox() &&
             pc_->functionBox()->hasSimpleParameterList());

  if (pc_->functionBox()->hasDuplicateParameters) {
    return false;
  }

  for (auto name : pc_->positionalFormalParameterNames()) {
    MOZ_ASSERT(name);
    if (!isValidStrictBinding(name)) {
      return false;
    }
  }
  return true;
}

template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportMissingClosing(
    unsigned errorNumber, unsigned noteNumber, uint32_t openedPos) {
  auto notes = MakeUnique<JSErrorNotes>();
  if (!notes) {
    ReportOutOfMemory(this->fc_);
    return;
  }

  uint32_t line;
  JS::LimitedColumnNumberOneOrigin column;
  tokenStream.computeLineAndColumn(openedPos, &line, &column);

  const size_t MaxWidth = sizeof("4294967295");
  char columnNumber[MaxWidth];
  SprintfLiteral(columnNumber, "%" PRIu32, column.oneOriginValue());
  char lineNumber[MaxWidth];
  SprintfLiteral(lineNumber, "%" PRIu32, line);

  if (!notes->addNoteASCII(this->fc_, getFilename().c_str(), 0, line,
                           JS::ColumnNumberOneOrigin(column), GetErrorMessage,
                           nullptr, noteNumber, lineNumber, columnNumber)) {
    return;
  }

  errorWithNotes(std::move(notes), errorNumber);
}

template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportRedeclarationHelper(
    TaggedParserAtomIndex& name, DeclarationKind& prevKind, TokenPos& pos,
    uint32_t& prevPos, const unsigned& errorNumber,
    const unsigned& noteErrorNumber) {
  UniqueChars bytes = this->parserAtoms().toPrintableString(name);
  if (!bytes) {
    ReportOutOfMemory(this->fc_);
    return;
  }

  if (prevPos == DeclaredNameInfo::npos) {
    errorAt(pos.begin, errorNumber, DeclarationKindString(prevKind),
            bytes.get());
    return;
  }

  auto notes = MakeUnique<JSErrorNotes>();
  if (!notes) {
    ReportOutOfMemory(this->fc_);
    return;
  }

  uint32_t line;
  JS::LimitedColumnNumberOneOrigin column;
  tokenStream.computeLineAndColumn(prevPos, &line, &column);

  const size_t MaxWidth = sizeof("4294967295");
  char columnNumber[MaxWidth];
  SprintfLiteral(columnNumber, "%" PRIu32, column.oneOriginValue());
  char lineNumber[MaxWidth];
  SprintfLiteral(lineNumber, "%" PRIu32, line);

  if (!notes->addNoteASCII(this->fc_, getFilename().c_str(), 0, line,
                           JS::ColumnNumberOneOrigin(column), GetErrorMessage,
                           nullptr, noteErrorNumber, lineNumber,
                           columnNumber)) {
    return;
  }

  errorWithNotesAt(std::move(notes), pos.begin, errorNumber,
                   DeclarationKindString(prevKind), bytes.get());
}

template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportRedeclaration(
    TaggedParserAtomIndex name, DeclarationKind prevKind, TokenPos pos,
    uint32_t prevPos) {
  reportRedeclarationHelper(name, prevKind, pos, prevPos, JSMSG_REDECLARED_VAR,
                            JSMSG_PREV_DECLARATION);
}

template <class ParseHandler, typename Unit>
void GeneralParser<ParseHandler, Unit>::reportMismatchedPlacement(
    TaggedParserAtomIndex name, DeclarationKind prevKind, TokenPos pos,
    uint32_t prevPos) {
  reportRedeclarationHelper(name, prevKind, pos, prevPos,
                            JSMSG_MISMATCHED_PLACEMENT, JSMSG_PREV_DECLARATION);
}

// notePositionalFormalParameter is called for both the arguments of a regular
// function definition and the arguments specified by the Function
// constructor.
//
// The 'disallowDuplicateParams' bool indicates whether the use of another
// feature (destructuring or default arguments) disables duplicate arguments.
// (ECMA-262 requires us to support duplicate parameter names, but, for newer
// features, we consider the code to have "opted in" to higher standards and
// forbid duplicates.)
template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::notePositionalFormalParameter(
    FunctionNodeType funNode, TaggedParserAtomIndex name, uint32_t beginPos,
    bool disallowDuplicateParams, bool* duplicatedParam) {
  if (AddDeclaredNamePtr p =
          pc_->functionScope().lookupDeclaredNameForAdd(name)) {
    if (disallowDuplicateParams) {
      error(JSMSG_BAD_DUP_ARGS);
      return false;
    }

    // Strict-mode disallows duplicate args. We may not know whether we are
    // in strict mode or not (since the function body hasn't been parsed).
    // In such cases, report will queue up the potential error and return
    // 'true'.
    if (pc_->sc()->strict()) {
      UniqueChars bytes = this->parserAtoms().toPrintableString(name);
      if (!bytes) {
        ReportOutOfMemory(this->fc_);
        return false;
      }
      if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.get())) {
        return false;
      }
    }

    *duplicatedParam = true;
  } else {
    DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
    if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, beginPos)) {
      return false;
    }
  }

  if (!pc_->positionalFormalParameterNames().append(
          TrivialTaggedParserAtomIndex::from(name))) {
    ReportOutOfMemory(this->fc_);
    return false;
  }

  NameNodeType paramNode;
  MOZ_TRY_VAR_OR_RETURN(paramNode, newName(name), false);

  handler_.addFunctionFormalParameter(funNode, paramNode);
  return true;
}

template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::noteDestructuredPositionalFormalParameter(
    FunctionNodeType funNode, Node destruct) {
  // Append an empty name to the positional formals vector to keep track of
  // argument slots when making FunctionScope::ParserData.
  if (!pc_->positionalFormalParameterNames().append(
          TrivialTaggedParserAtomIndex::null())) {
    ReportOutOfMemory(fc_);
    return false;
  }

  handler_.addFunctionFormalParameter(funNode, destruct);
  return true;
}

template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
    TaggedParserAtomIndex name, DeclarationKind kind, TokenPos pos,
    ClosedOver isClosedOver) {
  // The asm.js validator does all its own symbol-table management so, as an
  // optimization, avoid doing any work here.
  if (pc_->useAsmOrInsideUseAsm()) {
    return true;
  }

  switch (kind) {
    case DeclarationKind::Var:
    case DeclarationKind::BodyLevelFunction: {
      Maybe<DeclarationKind> redeclaredKind;
      uint32_t prevPos;
      if (!pc_->tryDeclareVar(name, this, kind, pos.begin, &redeclaredKind,
                              &prevPos)) {
        return false;
      }

      if (redeclaredKind) {
        reportRedeclaration(name, *redeclaredKind, pos, prevPos);
        return false;
      }

      break;
    }

    case DeclarationKind::ModuleBodyLevelFunction: {
      MOZ_ASSERT(pc_->atModuleLevel());

      AddDeclaredNamePtr p = pc_->varScope().lookupDeclaredNameForAdd(name);
      if (p) {
        reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
        return false;
      }

      if (!pc_->varScope().addDeclaredName(pc_, p, name, kind, pos.begin,
                                           isClosedOver)) {
        return false;
      }

      // Body-level functions in modules are always closed over.
      pc_->varScope().lookupDeclaredName(name)->value()->setClosedOver();

      break;
    }

    case DeclarationKind::FormalParameter: {
      // It is an early error if any non-positional formal parameter name
      // (e.g., destructuring formal parameter) is duplicated.

      AddDeclaredNamePtr p =
          pc_->functionScope().lookupDeclaredNameForAdd(name);
      if (p) {
        error(JSMSG_BAD_DUP_ARGS);
        return false;
      }

      if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, pos.begin,
                                                isClosedOver)) {
        return false;
      }

      break;
    }

    case DeclarationKind::LexicalFunction:
    case DeclarationKind::PrivateName:
    case DeclarationKind::Synthetic:
    case DeclarationKind::PrivateMethod: {
      ParseContext::Scope* scope = pc_->innermostScope();
      AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
      if (p) {
        reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
        return false;
      }

      if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
                                  isClosedOver)) {
        return false;
      }

      break;
    }

    case DeclarationKind::SloppyLexicalFunction: {
      // Functions in block have complex allowances in sloppy mode for being
      // labelled that other lexical declarations do not have. Those checks
      // are done in functionStmt.

      ParseContext::Scope* scope = pc_->innermostScope();
      if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
        // It is usually an early error if there is another declaration
        // with the same name in the same scope.
        //
        // Sloppy lexical functions may redeclare other sloppy lexical
        // functions for web compatibility reasons.
        if (p->value()->kind() != DeclarationKind::SloppyLexicalFunction) {
          reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
          return false;
        }
      } else {
        if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
                                    isClosedOver)) {
          return false;
        }
      }

      break;
    }

    case DeclarationKind::Let:
    case DeclarationKind::Const:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    case DeclarationKind::Using:
    case DeclarationKind::AwaitUsing:
#endif
    case DeclarationKind::Class:
      // The BoundNames of LexicalDeclaration and ForDeclaration must not
      // contain 'let'. (CatchParameter is the only lexical binding form
      // without this restriction.)
      if (name == TaggedParserAtomIndex::WellKnown::let()) {
        errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
        return false;
      }

      // For body-level lexically declared names in a function, it is an
      // early error if there is a formal parameter of the same name. This
      // needs a special check if there is an extra var scope due to
      // parameter expressions.
      if (pc_->isFunctionExtraBodyVarScopeInnermost()) {
        DeclaredNamePtr p = pc_->functionScope().lookupDeclaredName(name);
        if (p && DeclarationKindIsParameter(p->value()->kind())) {
          reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
          return false;
        }
      }

      [[fallthrough]];

    case DeclarationKind::Import:
      // Module code is always strict, so 'let' is always a keyword and never a
      // name.
      MOZ_ASSERT(name != TaggedParserAtomIndex::WellKnown::let());
      [[fallthrough]];

    case DeclarationKind::SimpleCatchParameter:
    case DeclarationKind::CatchParameter: {
      ParseContext::Scope* scope = pc_->innermostScope();

      // It is an early error if there is another declaration with the same
      // name in the same scope.
      AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
      if (p) {
        reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
        return false;
      }

      if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin,
                                  isClosedOver)) {
        return false;
      }

      break;
    }

    case DeclarationKind::CoverArrowParameter:
      // CoverArrowParameter is only used as a placeholder declaration kind.
      break;

    case DeclarationKind::PositionalFormalParameter:
      MOZ_CRASH(
          "Positional formal parameter names should use "
          "notePositionalFormalParameter");
      break;

    case DeclarationKind::VarForAnnexBLexicalFunction:
      MOZ_CRASH(
          "Synthesized Annex B vars should go through "
          "addPossibleAnnexBFunctionBox, and "
          "propagateAndMarkAnnexBFunctionBoxes");
      break;
  }

  return true;
}

template <class ParseHandler, typename Unit>
bool GeneralParser<ParseHandler, Unit>::noteDeclaredPrivateName(
    Node nameNode, TaggedParserAtomIndex name, PropertyType propType,
    FieldPlacement placement, TokenPos pos) {
  ParseContext::Scope* scope = pc_->innermostScope();
  AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);

  DeclarationKind declKind = DeclarationKind::PrivateName;

  // Our strategy for enabling debugger functionality is to mark names as closed
  // over, even if they don't necessarily need to be, to ensure that they are
  // included in the environment object. This allows us to easily look them up
  // by name when needed, even if there is no corresponding property on an
  // object, as is the case with getter, setters and private methods.
  ClosedOver closedOver = ClosedOver::Yes;
  PrivateNameKind kind;
  switch (propType) {
    case PropertyType::Field:
      kind = PrivateNameKind::Field;
      closedOver = ClosedOver::No;
      break;
    case PropertyType::FieldWithAccessor:
      // In this case, we create a new private field for the underlying storage,
      // and use the current name for the getter and setter.
      kind = PrivateNameKind::GetterSetter;
      break;
    case PropertyType::Method:
    case PropertyType::GeneratorMethod:
    case PropertyType::AsyncMethod:
    case PropertyType::AsyncGeneratorMethod:
      if (placement == FieldPlacement::Instance) {
        // Optimized private method. Non-optimized paths still get
        // DeclarationKind::Synthetic.
        declKind = DeclarationKind::PrivateMethod;
      }
      kind = PrivateNameKind::Method;
      break;
    case PropertyType::Getter:
      kind = PrivateNameKind::Getter;
      break;
    case PropertyType::Setter:
      kind = PrivateNameKind::Setter;
      break;
    default:
      MOZ_CRASH("Invalid Property Type for noteDeclarePrivateName");
  }

  if (p) {
    PrivateNameKind prevKind = p->value()->privateNameKind();
    if ((prevKind == PrivateNameKind::Getter &&
         kind == PrivateNameKind::Setter) ||
        (prevKind == PrivateNameKind::Setter &&
         kind == PrivateNameKind::Getter)) {
      // Private methods demands that
      //
      // class A {
      //   static set #x(_) {}
      //   get #x() { }
      // }
      //
      // Report a SyntaxError.
      if (placement == p->value()->placement()) {
        p->value()->setPrivateNameKind(PrivateNameKind::GetterSetter);
        handler_.setPrivateNameKind(nameNode, PrivateNameKind::GetterSetter);
        return true;
      }
    }

    reportMismatchedPlacement(name, p->value()->kind(), pos, p->value()->pos());
    return false;
  }

  if (!scope->addDeclaredName(pc_, p, name, declKind, pos.begin, closedOver)) {
    return false;
  }

  DeclaredNamePtr declared = scope->lookupDeclaredName(name);
  declared->value()->setPrivateNameKind(kind);
  declared->value()->setFieldPlacement(placement);
  handler_.setPrivateNameKind(nameNode, kind);

  return true;
}

bool ParserBase::noteUsedNameInternal(TaggedParserAtomIndex name,
                                      NameVisibility visibility,
                                      mozilla::Maybe<TokenPos> tokenPosition) {
  // The asm.js validator does all its own symbol-table management so, as an
  // optimization, avoid doing any work here.
  if (pc_->useAsmOrInsideUseAsm()) {
    return true;
  }

  // Global bindings are properties and not actual bindings; we don't need
  // to know if they are closed over. So no need to track used name at the
  // global scope. It is not incorrect to track them, this is an
  // optimization.
  //
  // Exceptions:
  //   (a) Track private name references, as the used names tracker is used to
  //       provide early errors for undeclared private name references
  //   (b) If the script has extra bindings, track all references to detect
  //       references to extra bindings
  ParseContext::Scope* scope = pc_->innermostScope();
  if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope() &&
      visibility == NameVisibility::Public &&
      !this->compilationState_.input.hasExtraBindings()) {
    return true;
  }

  return usedNames_.noteUse(fc_, name, visibility, pc_->scriptId(), scope->id(),
                            tokenPosition);
}

template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::
    propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope) {
  // Now that we have all the declared names in the scope, check which
  // functions should exhibit Annex B semantics.
  if (!scope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
    return false;
  }

  if (handler_.reuseClosedOverBindings()) {
    MOZ_ASSERT(pc_->isOutermostOfCurrentCompile());

    // Closed over bindings for all scopes are stored in a contiguous array, in
    // the same order as the order in which scopes are visited, and seprated by
    // TaggedParserAtomIndex::null().
    uint32_t slotCount = scope.declaredCount();
    while (auto parserAtom = handler_.nextLazyClosedOverBinding()) {
      scope.lookupDeclaredName(parserAtom)->value()->setClosedOver();
      MOZ_ASSERT(slotCount > 0);
      slotCount--;
    }

    if (pc_->isGeneratorOrAsync()) {
      scope.setOwnStackSlotCount(slotCount);
    }
    return true;
  }

  constexpr bool isSyntaxParser =
      std::is_same_v<ParseHandler, SyntaxParseHandler>;
  uint32_t scriptId = pc_->scriptId();
  uint32_t scopeId = scope.id();

  uint32_t slotCount = 0;
  for (BindingIter bi = scope.bindings(pc_); bi; bi++) {
    bool closedOver = false;
    if (UsedNamePtr p = usedNames_.lookup(bi.name())) {
      p->value().noteBoundInScope(scriptId, scopeId, &closedOver);
      if (closedOver) {
        bi.setClosedOver();

        if constexpr (isSyntaxParser) {
          if (!pc_->closedOverBindingsForLazy().append(
                  TrivialTaggedParserAtomIndex::from(bi.name()))) {
            ReportOutOfMemory(fc_);
            return false;
          }
        }
      }
    }

    if constexpr (!isSyntaxParser) {
      if (!closedOver) {
        slotCount++;
      }
    }
  }
  if constexpr (!isSyntaxParser) {
    if (pc_->isGeneratorOrAsync()) {
      scope.setOwnStackSlotCount(slotCount);
    }
  }

  // Append a nullptr to denote end-of-scope.
  if constexpr (isSyntaxParser) {
    if (!pc_->closedOverBindingsForLazy().append(
            TrivialTaggedParserAtomIndex::null())) {
      ReportOutOfMemory(fc_);
      return false;
    }
  }

  return true;
}

template <typename Unit>
bool Parser<FullParseHandler, Unit>::checkStatementsEOF() {
  // This is designed to be paired with parsing a statement list at the top
  // level.
  //
  // The statementList() call breaks on TokenKind::RightCurly, so make sure
  // we've reached EOF here.
  TokenKind tt;
  if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
    return false;
  }
  if (tt != TokenKind::Eof) {
    error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
    return false;
  }
  return true;
}

template <typename ScopeT>
typename ScopeT::ParserData* NewEmptyBindingData(FrontendContext* fc,
                                                 LifoAlloc& alloc,
                                                 uint32_t numBindings) {
  using Data = typename ScopeT::ParserData;
  size_t allocSize = SizeOfScopeData<Data>(numBindings);
  auto* bindings = alloc.newWithSize<Data>(allocSize, numBindings);
  if (!bindings) {
    ReportOutOfMemory(fc);
  }
  return bindings;
}

GlobalScope::ParserData* NewEmptyGlobalScopeData(FrontendContext* fc,
                                                 LifoAlloc& alloc,
                                                 uint32_t numBindings) {
  return NewEmptyBindingData<GlobalScope>(fc, alloc, numBindings);
}

LexicalScope::ParserData* NewEmptyLexicalScopeData(FrontendContext* fc,
                                                   LifoAlloc& alloc,
                                                   uint32_t numBindings) {
  return NewEmptyBindingData<LexicalScope>(fc, alloc, numBindings);
}

FunctionScope::ParserData* NewEmptyFunctionScopeData(FrontendContext* fc,
                                                     LifoAlloc& alloc,
                                                     uint32_t numBindings) {
  return NewEmptyBindingData<FunctionScope>(fc, alloc, numBindings);
}

namespace detail {

template <class SlotInfo>
static MOZ_ALWAYS_INLINE ParserBindingName* InitializeIndexedBindings(
    SlotInfo& slotInfo, ParserBindingName* start, ParserBindingName* cursor) {
  return cursor;
}

template <class SlotInfo, typename UnsignedInteger, typename... Step>
static MOZ_ALWAYS_INLINE ParserBindingName* InitializeIndexedBindings(
    SlotInfo& slotInfo, ParserBindingName* start, ParserBindingName* cursor,
    UnsignedInteger SlotInfo::* field, const ParserBindingNameVector& bindings,
    Step&&... step) {
  slotInfo.*field =
      AssertedCast<UnsignedInteger>(PointerRangeSize(start, cursor));

  ParserBindingName* newCursor =
      std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);

  return InitializeIndexedBindings(slotInfo, start, newCursor,
                                   std::forward<Step>(step)...);
}

}  // namespace detail

// Initialize the trailing name bindings of |data|, then set |data->length| to
// the count of bindings added (which must equal |count|).
//
// First, |firstBindings| are added to the trailing names.  Then any
// "steps" present are performed first to last.  Each step is 1) a pointer to a
// member of |data| to be set to the current number of bindings added, and 2) a
// vector of |ParserBindingName|s to then copy into |data->trailingNames|.
// (Thus each |data| member field indicates where the corresponding vector's
//  names start.)
template <class Data, typename... Step>
static MOZ_ALWAYS_INLINE void InitializeBindingData(
    Data* data, uint32_t count, const ParserBindingNameVector& firstBindings,
    Step&&... step) {
  MOZ_ASSERT(data->length == 0, "data shouldn't be filled yet");

  ParserBindingName* start = GetScopeDataTrailingNamesPointer(data);
  ParserBindingName* cursor = std::uninitialized_copy(
      firstBindings.begin(), firstBindings.end(), start);

#ifdef DEBUG
  ParserBindingName* end =
#endif
      detail::InitializeIndexedBindings(data->slotInfo, start, cursor,
                                        std::forward<Step>(step)...);

  MOZ_ASSERT(PointerRangeSize(start, end) == count);
  data->length = count;
}

static Maybe<GlobalScope::ParserData*> NewGlobalScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
    ParseContext* pc) {
  ParserBindingNameVector vars(fc);
  ParserBindingNameVector lets(fc);
  ParserBindingNameVector consts(fc);

  bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    bool closedOver = allBindingsClosedOver || bi.closedOver();

    switch (bi.kind()) {
      case BindingKind::Var: {
        bool isTopLevelFunction =
            bi.declarationKind() == DeclarationKind::BodyLevelFunction;

        ParserBindingName binding(bi.name(), closedOver, isTopLevelFunction);
        if (!vars.append(binding)) {
          return Nothing();
        }
        break;
      }
      case BindingKind::Let: {
        ParserBindingName binding(bi.name(), closedOver);
        if (!lets.append(binding)) {
          return Nothing();
        }
        break;
      }
      case BindingKind::Const: {
        ParserBindingName binding(bi.name(), closedOver);
        if (!consts.append(binding)) {
          return Nothing();
        }
        break;
      }
      default:
        MOZ_CRASH("Bad global scope BindingKind");
    }
  }

  GlobalScope::ParserData* bindings = nullptr;
  uint32_t numBindings = vars.length() + lets.length() + consts.length();

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<GlobalScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    // The ordering here is important. See comments in GlobalScope.
    InitializeBindingData(bindings, numBindings, vars,
                          &ParserGlobalScopeSlotInfo::letStart, lets,
                          &ParserGlobalScopeSlotInfo::constStart, consts);
  }

  return Some(bindings);
}

Maybe<GlobalScope::ParserData*> ParserBase::newGlobalScopeData(
    ParseContext::Scope& scope) {
  return NewGlobalScopeData(fc_, scope, stencilAlloc(), pc_);
}

static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
    ParseContext* pc) {
  ParserBindingNameVector imports(fc);
  ParserBindingNameVector vars(fc);
  ParserBindingNameVector lets(fc);
  ParserBindingNameVector consts(fc);
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
  ParserBindingNameVector usings(fc);
#endif

  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    // Imports are indirect bindings and must not be given known slots.
    ParserBindingName binding(bi.name(),
                              (allBindingsClosedOver || bi.closedOver()) &&
                                  bi.kind() != BindingKind::Import);
    switch (bi.kind()) {
      case BindingKind::Import:
        if (!imports.append(binding)) {
          return Nothing();
        }
        break;
      case BindingKind::Var:
        if (!vars.append(binding)) {
          return Nothing();
        }
        break;
      case BindingKind::Let:
        if (!lets.append(binding)) {
          return Nothing();
        }
        break;
      case BindingKind::Const:
        if (!consts.append(binding)) {
          return Nothing();
        }
        break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
      case BindingKind::Using:
        if (!usings.append(binding)) {
          return Nothing();
        }
        break;
#endif
      default:
        MOZ_CRASH("Bad module scope BindingKind");
    }
  }

  ModuleScope::ParserData* bindings = nullptr;
  uint32_t numBindings = imports.length() + vars.length() + lets.length() +
                         consts.length()
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
                         + usings.length()
#endif
      ;

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<ModuleScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    // The ordering here is important. See comments in ModuleScope.
    InitializeBindingData(bindings, numBindings, imports,
                          &ParserModuleScopeSlotInfo::varStart, vars,
                          &ParserModuleScopeSlotInfo::letStart, lets,
                          &ParserModuleScopeSlotInfo::constStart, consts
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
                          ,
                          &ParserModuleScopeSlotInfo::usingStart, usings
#endif
    );
  }

  return Some(bindings);
}

Maybe<ModuleScope::ParserData*> ParserBase::newModuleScopeData(
    ParseContext::Scope& scope) {
  return NewModuleScopeData(fc_, scope, stencilAlloc(), pc_);
}

static Maybe<EvalScope::ParserData*> NewEvalScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
    ParseContext* pc) {
  ParserBindingNameVector vars(fc);

  // Treat all bindings as closed over in non-strict eval.
  bool allBindingsClosedOver =
      !pc->sc()->strict() || pc->sc()->allBindingsClosedOver();
  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    // Eval scopes only contain 'var' bindings.
    MOZ_ASSERT(bi.kind() == BindingKind::Var);
    bool isTopLevelFunction =
        bi.declarationKind() == DeclarationKind::BodyLevelFunction;
    bool closedOver = allBindingsClosedOver || bi.closedOver();

    ParserBindingName binding(bi.name(), closedOver, isTopLevelFunction);
    if (!vars.append(binding)) {
      return Nothing();
    }
  }

  EvalScope::ParserData* bindings = nullptr;
  uint32_t numBindings = vars.length();

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<EvalScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    InitializeBindingData(bindings, numBindings, vars);
  }

  return Some(bindings);
}

Maybe<EvalScope::ParserData*> ParserBase::newEvalScopeData(
    ParseContext::Scope& scope) {
  return NewEvalScopeData(fc_, scope, stencilAlloc(), pc_);
}

static Maybe<FunctionScope::ParserData*> NewFunctionScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, bool hasParameterExprs,
    LifoAlloc& alloc, ParseContext* pc) {
  ParserBindingNameVector positionalFormals(fc);
  ParserBindingNameVector formals(fc);
  ParserBindingNameVector vars(fc);

  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();
  bool argumentBindingsClosedOver =
      allBindingsClosedOver || pc->isGeneratorOrAsync();
  bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;

  // Positional parameter names must be added in order of appearance as they are
  // referenced using argument slots.
  for (size_t i = 0; i < pc->positionalFormalParameterNames().length(); i++) {
    TaggedParserAtomIndex name = pc->positionalFormalParameterNames()[i];

    ParserBindingName bindName;
    if (name) {
      DeclaredNamePtr p = scope.lookupDeclaredName(name);

      // Do not consider any positional formal parameters closed over if
      // there are parameter defaults. It is the binding in the defaults
      // scope that is closed over instead.
      bool closedOver =
          argumentBindingsClosedOver || (p && p->value()->closedOver());

      // If the parameter name has duplicates, only the final parameter
      // name should be on the environment, as otherwise the environment
      // object would have multiple, same-named properties.
      if (hasDuplicateParams) {
        for (size_t j = pc->positionalFormalParameterNames().length() - 1;
             j > i; j--) {
          if (TaggedParserAtomIndex(pc->positionalFormalParameterNames()[j]) ==
              name) {
            closedOver = false;
            break;
          }
        }
      }

      bindName = ParserBindingName(name, closedOver);
    }

    if (!positionalFormals.append(bindName)) {
      return Nothing();
    }
  }

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    ParserBindingName binding(bi.name(),
                              allBindingsClosedOver || bi.closedOver());
    switch (bi.kind()) {
      case BindingKind::FormalParameter:
        // Positional parameter names are already handled above.
        if (bi.declarationKind() == DeclarationKind::FormalParameter) {
          if (!formals.append(binding)) {
            return Nothing();
          }
        }
        break;
      case BindingKind::Var:
        // The only vars in the function scope when there are parameter
        // exprs, which induces a separate var environment, should be the
        // special bindings.
        MOZ_ASSERT_IF(hasParameterExprs,
                      FunctionScope::isSpecialName(bi.name()));
        if (!vars.append(binding)) {
          return Nothing();
        }
        break;
      case BindingKind::Let:
      case BindingKind::Const:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
      case BindingKind::Using:
#endif
        break;
      default:
        MOZ_CRASH("bad function scope BindingKind");
        break;
    }
  }

  FunctionScope::ParserData* bindings = nullptr;
  uint32_t numBindings =
      positionalFormals.length() + formals.length() + vars.length();

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<FunctionScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    // The ordering here is important. See comments in FunctionScope.
    InitializeBindingData(
        bindings, numBindings, positionalFormals,
        &ParserFunctionScopeSlotInfo::nonPositionalFormalStart, formals,
        &ParserFunctionScopeSlotInfo::varStart, vars);
  }

  return Some(bindings);
}

// Compute if `NewFunctionScopeData` would return any binding list with any
// entry marked as closed-over. This is done without the need to allocate the
// binding list. If true, an EnvironmentObject will be needed at runtime.
bool FunctionScopeHasClosedOverBindings(ParseContext* pc) {
  bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver() ||
                               pc->functionScope().tooBigToOptimize();

  for (BindingIter bi = pc->functionScope().bindings(pc); bi; bi++) {
    switch (bi.kind()) {
      case BindingKind::FormalParameter:
      case BindingKind::Var:
        if (allBindingsClosedOver || bi.closedOver()) {
          return true;
        }
        break;

      default:
        break;
    }
  }

  return false;
}

Maybe<FunctionScope::ParserData*> ParserBase::newFunctionScopeData(
    ParseContext::Scope& scope, bool hasParameterExprs) {
  return NewFunctionScopeData(fc_, scope, hasParameterExprs, stencilAlloc(),
                              pc_);
}

VarScope::ParserData* NewEmptyVarScopeData(FrontendContext* fc,
                                           LifoAlloc& alloc,
                                           uint32_t numBindings) {
  return NewEmptyBindingData<VarScope>(fc, alloc, numBindings);
}

static Maybe<VarScope::ParserData*> NewVarScopeData(FrontendContext* fc,
                                                    ParseContext::Scope& scope,
                                                    LifoAlloc& alloc,
                                                    ParseContext* pc) {
  ParserBindingNameVector vars(fc);

  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    if (bi.kind() == BindingKind::Var) {
      ParserBindingName binding(bi.name(),
                                allBindingsClosedOver || bi.closedOver());
      if (!vars.append(binding)) {
        return Nothing();
      }
    } else {
      MOZ_ASSERT(bi.kind() == BindingKind::Let ||
                     bi.kind() == BindingKind::Const
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
                     || bi.kind() == BindingKind::Using
#endif
                 ,
                 "bad var scope BindingKind");
    }
  }

  VarScope::ParserData* bindings = nullptr;
  uint32_t numBindings = vars.length();

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<VarScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    InitializeBindingData(bindings, numBindings, vars);
  }

  return Some(bindings);
}

// Compute if `NewVarScopeData` would return any binding list. This is done
// without allocate the binding list.
static bool VarScopeHasBindings(ParseContext* pc) {
  for (BindingIter bi = pc->varScope().bindings(pc); bi; bi++) {
    if (bi.kind() == BindingKind::Var) {
      return true;
    }
  }

  return false;
}

Maybe<VarScope::ParserData*> ParserBase::newVarScopeData(
    ParseContext::Scope& scope) {
  return NewVarScopeData(fc_, scope, stencilAlloc(), pc_);
}

static Maybe<LexicalScope::ParserData*> NewLexicalScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
    ParseContext* pc) {
  ParserBindingNameVector lets(fc);
  ParserBindingNameVector consts(fc);
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
  ParserBindingNameVector usings(fc);
#endif

  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    ParserBindingName binding(bi.name(),
                              allBindingsClosedOver || bi.closedOver());
    switch (bi.kind()) {
      case BindingKind::Let:
        if (!lets.append(binding)) {
          return Nothing();
        }
        break;
      case BindingKind::Const:
        if (!consts.append(binding)) {
          return Nothing();
        }
        break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
      case BindingKind::Using:
        if (!usings.append(binding)) {
          return Nothing();
        }
        break;
#endif
      case BindingKind::Var:
      case BindingKind::FormalParameter:
        break;
      default:
        MOZ_CRASH("Bad lexical scope BindingKind");
        break;
    }
  }

  LexicalScope::ParserData* bindings = nullptr;
  uint32_t numBindings = lets.length() + consts.length()
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
                         + usings.length()
#endif
      ;

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<LexicalScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }

    // The ordering here is important. See comments in LexicalScope.
    InitializeBindingData(bindings, numBindings, lets,
                          &ParserLexicalScopeSlotInfo::constStart, consts
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
                          ,
                          &ParserLexicalScopeSlotInfo::usingStart, usings
#endif
    );
  }

  return Some(bindings);
}

// Compute if `NewLexicalScopeData` would return any binding list with any entry
// marked as closed-over. This is done without the need to allocate the binding
// list. If true, an EnvironmentObject will be needed at runtime.
bool LexicalScopeHasClosedOverBindings(ParseContext* pc,
                                       ParseContext::Scope& scope) {
  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    switch (bi.kind()) {
      case BindingKind::Let:
      case BindingKind::Const:
        if (allBindingsClosedOver || bi.closedOver()) {
          return true;
        }
        break;

      default:
        break;
    }
  }

  return false;
}

Maybe<LexicalScope::ParserData*> ParserBase::newLexicalScopeData(
    ParseContext::Scope& scope) {
  return NewLexicalScopeData(fc_, scope, stencilAlloc(), pc_);
}

static Maybe<ClassBodyScope::ParserData*> NewClassBodyScopeData(
    FrontendContext* fc, ParseContext::Scope& scope, LifoAlloc& alloc,
    ParseContext* pc) {
  ParserBindingNameVector privateBrand(fc);
  ParserBindingNameVector synthetics(fc);
  ParserBindingNameVector privateMethods(fc);

  bool allBindingsClosedOver =
      pc->sc()->allBindingsClosedOver() || scope.tooBigToOptimize();

  for (BindingIter bi = scope.bindings(pc); bi; bi++) {
    ParserBindingName binding(bi.name(),
                              allBindingsClosedOver || bi.closedOver());
    switch (bi.kind()) {
      case BindingKind::Synthetic:
        if (bi.name() ==
            TaggedParserAtomIndex::WellKnown::dot_privateBrand_()) {
          MOZ_ASSERT(privateBrand.empty());
          if (!privateBrand.append(binding)) {
            return Nothing();
          }
        } else {
          if (!synthetics.append(binding)) {
            return Nothing();
          }
        }
        break;

      case BindingKind::PrivateMethod:
        if (!privateMethods.append(binding)) {
          return Nothing();
        }
        break;

      default:
        MOZ_CRASH("bad class body scope BindingKind");
        break;
    }
  }

  // We should have zero or one private brands.
  MOZ_ASSERT(privateBrand.length() == 0 || privateBrand.length() == 1);

  ClassBodyScope::ParserData* bindings = nullptr;
  uint32_t numBindings =
      privateBrand.length() + synthetics.length() + privateMethods.length();

  if (numBindings > 0) {
    bindings = NewEmptyBindingData<ClassBodyScope>(fc, alloc, numBindings);
    if (!bindings) {
      return Nothing();
    }
    // To simplify initialization of the bindings, we concatenate the
    // synthetics+privateBrand vector such that the private brand is always the
    // first element, as ordering is important. See comments in ClassBodyScope.
    ParserBindingNameVector brandAndSynthetics(fc);
    if (!brandAndSynthetics.appendAll(privateBrand)) {
      return Nothing();
    }
    if (!brandAndSynthetics.appendAll(synthetics)) {
      return Nothing();
    }

    // The ordering here is important. See comments in ClassBodyScope.
    InitializeBindingData(bindings, numBindings, brandAndSynthetics,
                          &ParserClassBodyScopeSlotInfo::privateMethodStart,
                          privateMethods);
  }

  // `EmitterScope::lookupPrivate()` requires `.privateBrand` to be stored in a
  // predictable slot: the first slot available in the environment object,
  // `ClassBodyLexicalEnvironmentObject::privateBrandSlot()`. We assume that
  // if `.privateBrand` is first in the scope, it will be stored there.
  MOZ_ASSERT_IF(!privateBrand.empty(),
                GetScopeDataTrailingNames(bindings)[0].name() ==
                    TaggedParserAtomIndex::WellKnown::dot_privateBrand_());

  return Some(bindings);
}

Maybe<ClassBodyScope::ParserData*> ParserBase::newClassBodyScopeData(
    ParseContext::Scope& scope) {
  return NewClassBodyScopeData(fc_, scope, stencilAlloc(), pc_);
}

template <>
SyntaxParseHandler::LexicalScopeNodeResult
PerHandlerParser<SyntaxParseHandler>::finishLexicalScope(
    ParseContext::Scope& scope, Node body, ScopeKind kind) {
  if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
    return errorResult();
  }

  return handler_.newLexicalScope(body);
}

template <>
FullParseHandler::LexicalScopeNodeResult
PerHandlerParser<FullParseHandler>::finishLexicalScope(
    ParseContext::Scope& scope, ParseNode* body, ScopeKind kind) {
  if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
    return errorResult();
  }

  Maybe<LexicalScope::ParserData*> bindings = newLexicalScopeData(scope);
  if (!bindings) {
    return errorResult();
  }

  return handler_.newLexicalScope(*bindings, body, kind);
}

template <>
SyntaxParseHandler::ClassBodyScopeNodeResult
PerHandlerParser<SyntaxParseHandler>::finishClassBodyScope(
    ParseContext::Scope& scope, ListNodeType body) {
  if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
    return errorResult();
  }

  return handler_.newClassBodyScope(body);
}

template <>
FullParseHandler::ClassBodyScopeNodeResult
PerHandlerParser<FullParseHandler>::finishClassBodyScope(
    ParseContext::Scope& scope, ListNode* body) {
  if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
    return errorResult();
  }

  Maybe<ClassBodyScope::ParserData*> bindings = newClassBodyScopeData(scope);
  if (!bindings) {
    return errorResult();
  }

  return handler_.newClassBodyScope(*bindings, body);
}

template <class ParseHandler>
bool PerHandlerParser<ParseHandler>::checkForUndefinedPrivateFields(
    EvalSharedContext* evalSc) {
  if (!this->compilationState_.isInitialStencil()) {
    // We're delazifying -- so we already checked private names during first
    // parse.
    return true;
  }

  Vector<UnboundPrivateName, 8> unboundPrivateNames(fc_);
  if (!usedNames_.getUnboundPrivateNames(unboundPrivateNames)) {
    return false;
  }

  // No unbound names, let's get out of here!
  if (unboundPrivateNames.empty()) {
    return true;
  }

  // It is an early error if there's private name references unbound,
  // unless it's an eval, in which case we need to check the scope
  // chain.
  if (!evalSc) {
    // The unbound private names are sorted, so just grab the first one.
    UnboundPrivateName minimum = unboundPrivateNames[0];
    UniqueChars str = this->parserAtoms().toPrintableString(minimum.atom);
    if (!str) {
      ReportOutOfMemory(this->fc_);
      return false;
    }

    errorAt(minimum.position.begin, JSMSG_MISSING_PRIVATE_DECL, str.get());
    return false;
  }

  // It's important that the unbound private names are sorted, as we
  // want our errors to always be issued to the first textually.
  for (UnboundPrivateName unboundName : unboundPrivateNames) {
    // If the enclosingScope is non-syntactic, then we are in a
    // Debugger.Frame.prototype.eval call. In order to find the declared private
    // names, we must use the effective scope that was determined when creating
    // the scopeContext.
    if (!this->compilationState_.scopeContext
             .effectiveScopePrivateFieldCacheHas(unboundName.atom)) {
      UniqueChars str = this->parserAtoms().toPrintableString(unboundName.atom);
      if (!str) {
        ReportOutOfMemory(this->fc_);
        return false;
      }
      errorAt(unboundName.position.begin, JSMSG_MISSING_PRIVATE_DECL,
              str.get());
      return false;
    }
  }

  return true;
}

template <typename Unit>
FullParseHandler::LexicalScopeNodeResult
Parser<FullParseHandler, Unit>::evalBody(EvalSharedContext* evalsc) {
  SourceParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
  if (!evalpc.init()) {
    return errorResult();
  }

  ParseContext::VarScope varScope(this);
  if (!varScope.init(pc_)) {
    return errorResult();
  }

  LexicalScopeNode* body;
  {
    // All evals have an implicit non-extensible lexical scope.
    ParseContext::Scope lexicalScope(this);
    if (!lexicalScope.init(pc_)) {
      return errorResult();
    }

    ListNode* list;
    MOZ_TRY_VAR(list, statementList(YieldIsName));

    if (!checkStatementsEOF()) {
      return errorResult();
    }

    // Private names not lexically defined must trigger a syntax error.
    if (!checkForUndefinedPrivateFields(evalsc)) {
      return errorResult();
    }

    MOZ_TRY_VAR(body, finishLexicalScope(lexicalScope, list));
  }

#ifdef DEBUG
  if (evalpc.superScopeNeedsHomeObject() &&
      !this->compilationState_.input.enclosingScope.isNull()) {
    // If superScopeNeedsHomeObject_ is set and we are an entry-point
    // ParseContext, then we must be emitting an eval script, and the
    // outer function must already be marked as needing a home object
    // since it contains an eval.
    MOZ_ASSERT(
        this->compilationState_.scopeContext.hasFunctionNeedsHomeObjectOnChain,
        "Eval must have found an enclosing function box scope that "
        "allows super.property");
  }
#endif

  if (!CheckParseTree(this->fc_, alloc_, body)) {
    return errorResult();
  }

  ParseNode* node = body;
  // Don't constant-fold inside "use asm" code, as this could create a parse
  // tree that doesn't type-check as asm.js.
  if (!pc_->useAsmOrInsideUseAsm()) {
    if (!FoldConstants(this->fc_, this->parserAtoms(), this->bigInts(), &node,
                       &handler_)) {
      return errorResult();
    }
  }
  body = handler_.asLexicalScopeNode(node);

  if (!this->setSourceMapInfo()) {
    return errorResult();
  }

  if (pc_->sc()->strict()) {
    if (!propagateFreeNamesAndMarkClosedOverBindings(varScope)) {
      return errorResult();
    }
  } else {
    // For non-strict eval scripts, since all bindings are automatically
    // considered closed over, we don't need to call propagateFreeNames-
    // AndMarkClosedOverBindings. However, Annex B.3.3 functions still need to
    // be marked.
    if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
      return errorResult();
    }
  }

  Maybe<EvalScope::ParserData*> bindings = newEvalScopeData(pc_->varScope());
  if (!bindings) {
    return errorResult();
  }
  evalsc->bindings = *bindings;

  return body;
}

template <typename Unit>
FullParseHandler::ListNodeResult Parser<FullParseHandler, Unit>::globalBody(
    GlobalSharedContext* globalsc) {
  SourceParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
  if (!globalpc.init()) {
    return errorResult();
  }

  ParseContext::VarScope varScope(this);
  if (!varScope.init(pc_)) {
    return errorResult();
  }

  ListNode* body;
  MOZ_TRY_VAR(body, statementList(YieldIsName));

  if (!checkStatementsEOF()) {
    return errorResult();
  }

  if (!CheckParseTree(this->fc_, alloc_, body)) {
    return errorResult();
  }

  if (!checkForUndefinedPrivateFields()) {
    return errorResult();
  }

  ParseNode* node = body;
  // Don't constant-fold inside "use asm" code, as this could create a parse
  // tree that doesn't type-check as asm.js.
  if (!pc_->useAsmOrInsideUseAsm()) {
    if (!FoldConstants(this->fc_, this->parserAtoms(), this->bigInts(), &node,
                       &handler_)) {
      return errorResult();
    }
  }
  body = &node->as<ListNode>();

  if (!this->setSourceMapInfo()) {
    return errorResult();
  }

  // For global scripts, whether bindings are closed over or not doesn't
  // matter, so no need to call propagateFreeNamesAndMarkClosedOver-
  // Bindings. However, Annex B.3.3 functions still need to be marked.
  if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_, this)) {
    return errorResult();
  }

  Maybe<GlobalScope::ParserData*> bindings =
      newGlobalScopeData(pc_->varScope());
  if (!bindings) {
    return errorResult();
  }
  globalsc->bindings = *bindings;

  return body;
}

template <typename Unit>
FullParseHandler::ModuleNodeResult Parser<FullParseHandler, Unit>::moduleBody(
    ModuleSharedContext* modulesc) {
  MOZ_ASSERT(checkOptionsCalled_);

  this->compilationState_.moduleMetadata =
      fc_->getAllocator()->template new_<StencilModuleMetadata>();
  if (!this->compilationState_.moduleMetadata) {
    return errorResult();
  }

  SourceParseContext modulepc(this, modulesc, nullptr);
  if (!modulepc.init()) {
    return errorResult();
  }

  ParseContext::VarScope varScope(this);
  if (!varScope.init(pc_)) {
    return errorResult();
  }

  ModuleNodeType moduleNode;
  MOZ_TRY_VAR(moduleNode, handler_.newModule(pos()));

  AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(
      this, AwaitIsModuleKeyword);
  ListNode* stmtList;
  MOZ_TRY_VAR(stmtList, statementList(YieldIsName));

  MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
  moduleNode->setBody(&stmtList->template as<ListNode>());

  if (pc_->isAsync()) {
    if (!noteUsedName(TaggedParserAtomIndex::WellKnown::dot_generator_())) {
      return errorResult();
    }

    if (!pc_->declareTopLevelDotGeneratorName()) {
      return errorResult();
    }
  }

  TokenKind tt;
  if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
    return errorResult();
  }
  if (tt != TokenKind::Eof) {
    error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
    return errorResult();
  }

  // Set the module to async if an await keyword was found at the top level.
  if (pc_->isAsync()) {
    pc_->sc()->asModuleContext()->builder.noteAsync(
        *this->compilationState_.moduleMetadata);
  }

  // Generate the Import/Export tables and store in CompilationState.
  if (!modulesc->builder.buildTables(*this->compilationState_.moduleMetadata)) {
    return errorResult();
  }

  // Check exported local bindings exist and mark them as closed over.
  StencilModuleMetadata& moduleMetadata =
      *this->compilationState_.moduleMetadata;
  for (auto entry : moduleMetadata.localExportEntries) {
    DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(entry.localName);
    if (!p) {
      UniqueChars str = this->parserAtoms().toPrintableString(entry.localName);
      if (!str) {
        ReportOutOfMemory(this->fc_);
        return errorResult();
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=90 H=94 G=91

¤ Dauer der Verarbeitung: 0.39 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.