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 27 kB image not shown  

Quelle  ParseContext.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/. */


#include "frontend/ParseContext-inl.h"

#include "frontend/CompilationStencil.h"  // ScopeContext
#include "frontend/Parser.h"              // ParserBase
#include "js/friend/ErrorMessages.h"      // JSMSG_*

using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;

namespace js {
namespace frontend {

using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;

const char* DeclarationKindString(DeclarationKind kind) {
  switch (kind) {
    case DeclarationKind::PositionalFormalParameter:
    case DeclarationKind::FormalParameter:
      return "formal parameter";
    case DeclarationKind::CoverArrowParameter:
      return "cover arrow parameter";
    case DeclarationKind::Var:
      return "var";
    case DeclarationKind::Let:
      return "let";
    case DeclarationKind::Const:
      return "const";
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    case DeclarationKind::Using:
      return "using";
    case DeclarationKind::AwaitUsing:
      return "await using";
#endif
    case DeclarationKind::Class:
      return "class";
    case DeclarationKind::Import:
      return "import";
    case DeclarationKind::BodyLevelFunction:
    case DeclarationKind::ModuleBodyLevelFunction:
    case DeclarationKind::LexicalFunction:
    case DeclarationKind::SloppyLexicalFunction:
      return "function";
    case DeclarationKind::VarForAnnexBLexicalFunction:
      return "annex b var";
    case DeclarationKind::SimpleCatchParameter:
    case DeclarationKind::CatchParameter:
      return "catch parameter";
    case DeclarationKind::PrivateName:
      return "private name";
    case DeclarationKind::Synthetic:
      return "synthetic";
    case DeclarationKind::PrivateMethod:
      return "private method";
  }

  MOZ_CRASH("Bad DeclarationKind");
}

bool DeclarationKindIsVar(DeclarationKind kind) {
  return kind == DeclarationKind::Var ||
         kind == DeclarationKind::BodyLevelFunction ||
         kind == DeclarationKind::VarForAnnexBLexicalFunction;
}

bool DeclarationKindIsParameter(DeclarationKind kind) {
  return kind == DeclarationKind::PositionalFormalParameter ||
         kind == DeclarationKind::FormalParameter;
}

bool UsedNameTracker::noteUse(FrontendContext* fc, TaggedParserAtomIndex name,
                              NameVisibility visibility, uint32_t scriptId,
                              uint32_t scopeId,
                              mozilla::Maybe<TokenPos> tokenPosition) {
  if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
    p->value().maybeUpdatePos(tokenPosition);

    if (!p->value().noteUsedInScope(scriptId, scopeId)) {
      return false;
    }
  } else {
    // We need a token position precisely where we have private visibility.
    MOZ_ASSERT(tokenPosition.isSome() ==
               (visibility == NameVisibility::Private));

    if (visibility == NameVisibility::Private) {
      // We have seen at least one private name
      hasPrivateNames_ = true;
    }

    UsedNameInfo info(fc, visibility, tokenPosition);

    if (!info.noteUsedInScope(scriptId, scopeId)) {
      return false;
    }
    if (!map_.add(p, name, std::move(info))) {
      return false;
    }
  }

  return true;
}

bool UsedNameTracker::getUnboundPrivateNames(
    Vector<UnboundPrivateName, 8>& unboundPrivateNames) {
  // We never saw any private names, so can just return early
  if (!hasPrivateNames_) {
    return true;
  }

  for (auto iter = map_.iter(); !iter.done(); iter.next()) {
    // Don't care about public;
    if (iter.get().value().isPublic()) {
      continue;
    }

    // empty list means all bound
    if (iter.get().value().empty()) {
      continue;
    }

    if (!unboundPrivateNames.emplaceBack(iter.get().key(),
                                         *iter.get().value().pos())) {
      return false;
    }
  }

  // Return a sorted list in ascendng order of position.
  auto comparePosition = [](const auto& a, const auto& b) {
    return a.position < b.position;
  };
  std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
            comparePosition);

  return true;
}

bool UsedNameTracker::hasUnboundPrivateNames(
    FrontendContext* fc, mozilla::Maybe<UnboundPrivateName>& maybeUnboundName) {
  // We never saw any private names, so can just return early
  if (!hasPrivateNames_) {
    return true;
  }

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

  if (unboundPrivateNames.empty()) {
    return true;
  }

  // GetUnboundPrivateNames returns the list sorted.
  maybeUnboundName.emplace(unboundPrivateNames[0]);
  return true;
}

void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
                                                 uint32_t scopeId) {
  while (!uses_.empty()) {
    Use& innermost = uses_.back();
    if (innermost.scopeId < scopeId) {
      break;
    }
    MOZ_ASSERT(innermost.scriptId >= scriptId);
    uses_.popBack();
  }
}

void UsedNameTracker::rewind(RewindToken token) {
  scriptCounter_ = token.scriptId;
  scopeCounter_ = token.scopeId;

  for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
    r.front().value().resetToScope(token.scriptId, token.scopeId);
  }
}

#if defined(DEBUG) || defined(JS_JITSPEW)
void UsedNameTracker::dump(ParserAtomsTable& table) {
  js::Fprinter out(stderr);

  out.printf("Used names:\n");

  for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
    const auto& item = r.front();

    const auto& name = item.key();
    const auto& nameInfo = item.value();

    out.put(" ");
    table.dumpCharsNoQuote(out, name);
    out.put("\n");

    if (nameInfo.visibility_ == NameVisibility::Private) {
      out.put(" visibility: private\n");
    }

    if (nameInfo.firstUsePos_) {
      const auto& pos = *nameInfo.firstUsePos_;
      out.printf(" first use pos: %u\n", pos.begin);
    }

    out.printf(" %zu user(s)", nameInfo.uses_.length());
    bool first = true;
    for (const auto& use : nameInfo.uses_) {
      if (first) {
        first = false;
        out.put(" (");
      } else {
        out.put(", ");
      }
      out.printf("%u/%u", use.scriptId, use.scopeId);
    }
    if (!first) {
      out.put(")");
    }
    out.put("\n");
  }
}
#endif

void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
  fprintf(stdout, "ParseScope %p"this);

  fprintf(stdout, "\n decls:\n");
  for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
    auto index = r.front().key();
    UniqueChars bytes = parser->parserAtoms().toPrintableString(index);
    if (!bytes) {
      ReportOutOfMemory(pc->sc()->fc_);
      return;
    }
    DeclaredNameInfo& info = r.front().value().wrapped;
    fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
            bytes.get(), info.closedOver() ? " (closed over)" : "");
  }

  fprintf(stdout, "\n");
}

bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
                                                       FunctionBox* funbox) {
  if (!possibleAnnexBFunctionBoxes_) {
    if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->fc_)) {
      return false;
    }
  }

  return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
}

bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
    ParseContext* pc, ParserBase* parser) {
  // Strict mode doesn't have wack Annex B function semantics.
  if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
      possibleAnnexBFunctionBoxes_->empty()) {
    return true;
  }

  if (this == &pc->varScope()) {
    // Base case: actually declare the Annex B vars and mark applicable
    // function boxes as Annex B.
    Maybe<DeclarationKind> redeclaredKind;
    uint32_t unused;
    for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
      bool annexBApplies;
      if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
              funbox, parser, &annexBApplies)) {
        return false;
      }
      if (annexBApplies) {
        if (!pc->tryDeclareVar(funbox->explicitName(), parser,
                               DeclarationKind::VarForAnnexBLexicalFunction,
                               DeclaredNameInfo::npos, &redeclaredKind,
                               &unused)) {
          return false;
        }

        MOZ_ASSERT(!redeclaredKind);
        funbox->isAnnexB = true;
      }
    }
  } else {
    // Inner scope case: propagate still applicable function boxes to the
    // enclosing scope.
    for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
      bool annexBApplies;
      if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
              funbox, parser, &annexBApplies)) {
        return false;
      }
      if (annexBApplies) {
        if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
          return false;
        }
      }
    }
  }

  return true;
}

static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
  return kind == DeclarationKind::SimpleCatchParameter ||
         kind == DeclarationKind::CatchParameter;
}

bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
                                             Scope& catchParamScope) {
  if (pc->useAsmOrInsideUseAsm()) {
    return true;
  }

  for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
       r.popFront()) {
    DeclarationKind kind = r.front().value()->kind();
    uint32_t pos = r.front().value()->pos();
    MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
    auto name = r.front().key();
    AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
    MOZ_ASSERT(!p);
    if (!addDeclaredName(pc, p, name, kind, pos)) {
      return false;
    }
  }

  return true;
}

void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
                                                Scope& catchParamScope) {
  if (pc->useAsmOrInsideUseAsm()) {
    return;
  }

  for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
       r.popFront()) {
    auto name = r.front().key();
    DeclaredNamePtr p = declared_->lookup(name);
    MOZ_ASSERT(p);

    // This check is needed because the catch body could have declared
    // vars, which would have been added to catchParamScope.
    if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
      declared_->remove(p);
    }
  }
}

ParseContext::ParseContext(FrontendContext* fc, ParseContext*& parent,
                           SharedContext* sc, ErrorReporter& errorReporter,
                           CompilationState& compilationState,
                           Directives* newDirectives, bool isFull)
    : Nestable<ParseContext>(&parent),
      sc_(sc),
      errorReporter_(errorReporter),
      innermostStatement_(nullptr),
      innermostScope_(nullptr),
      varScope_(nullptr),
      positionalFormalParameterNames_(fc->nameCollectionPool()),
      closedOverBindingsForLazy_(fc->nameCollectionPool()),
      innerFunctionIndexesForLazy(sc->fc_),
      newDirectives(newDirectives),
      lastYieldOffset(NoYieldOffset),
      lastAwaitOffset(NoAwaitOffset),
      scriptId_(compilationState.usedNames.nextScriptId()),
      superScopeNeedsHomeObject_(false) {
  if (isFunctionBox()) {
    if (functionBox()->isNamedLambda()) {
      namedLambdaScope_.emplace(fc, parent, compilationState.usedNames);
    }
    functionScope_.emplace(fc, parent, compilationState.usedNames);
  }
}

bool ParseContext::init() {
  if (scriptId_ == UINT32_MAX) {
    errorReporter_.errorNoOffset(JSMSG_NEED_DIET, "script");
    return false;
  }

  FrontendContext* fc = sc()->fc_;

  if (isFunctionBox()) {
    // Named lambdas always need a binding for their own name. If this
    // binding is closed over when we finish parsing the function iNn
    // finishFunctionScopes, the function box needs to be marked as
    // needing a dynamic DeclEnv object.
    if (functionBox()->isNamedLambda()) {
      if (!namedLambdaScope_->init(this)) {
        return false;
      }
      AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
          functionBox()->explicitName());
      MOZ_ASSERT(!p);
      if (!namedLambdaScope_->addDeclaredName(
              this, p, functionBox()->explicitName(), DeclarationKind::Const,
              DeclaredNameInfo::npos)) {
        return false;
      }
    }

    if (!functionScope_->init(this)) {
      return false;
    }

    if (!positionalFormalParameterNames_.acquire(fc)) {
      return false;
    }
  }

  if (!closedOverBindingsForLazy_.acquire(fc)) {
    return false;
  }

  return true;
}

bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
    FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
  MOZ_ASSERT(!sc()->strict());

  TaggedParserAtomIndex name = funbox->explicitName();
  Maybe<DeclarationKind> redeclaredKind;
  if (!isVarRedeclaredInInnermostScope(
          name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
          &redeclaredKind)) {
    return false;
  }

  if (!redeclaredKind && isFunctionBox()) {
    Scope& funScope = functionScope();
    if (&funScope != &varScope()) {
      // Annex B.3.3.1 disallows redeclaring parameter names. In the
      // presence of parameter expressions, parameter names are on the
      // function scope, which encloses the var scope. This means the
      // isVarRedeclaredInInnermostScope call above would not catch this
      // case, so test it manually.
      if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
        DeclarationKind declaredKind = p->value()->kind();
        if (DeclarationKindIsParameter(declaredKind)) {
          redeclaredKind = Some(declaredKind);
        } else {
          MOZ_ASSERT(FunctionScope::isSpecialName(name));
        }
      }
    }
  }

  // If an early error would have occurred already, this function should not
  // exhibit Annex B.3.3 semantics.
  *annexBApplies = !redeclaredKind;
  return true;
}

bool ParseContext::isVarRedeclaredInInnermostScope(
    TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
    mozilla::Maybe<DeclarationKind>* out) {
  uint32_t unused;
  return tryDeclareVarHelper<DryRunInnermostScopeOnly>(
      name, parser, kind, DeclaredNameInfo::npos, out, &unused);
}

bool ParseContext::isVarRedeclaredInEval(TaggedParserAtomIndex name,
                                         ParserBase* parser,
                                         DeclarationKind kind,
                                         Maybe<DeclarationKind>* out) {
  auto maybeKind = parser->getCompilationState()
                       .scopeContext.lookupLexicalBindingInEnclosingScope(name);
  if (!maybeKind) {
    *out = Nothing();
    return true;
  }

  switch (*maybeKind) {
    case ScopeContext::EnclosingLexicalBindingKind::Let:
      *out = Some(DeclarationKind::Let);
      break;
    case ScopeContext::EnclosingLexicalBindingKind::Const:
      *out = Some(DeclarationKind::Const);
      break;
    case ScopeContext::EnclosingLexicalBindingKind::CatchParameter:
      *out = Some(DeclarationKind::CatchParameter);
      break;
    case ScopeContext::EnclosingLexicalBindingKind::Synthetic:
      *out = Some(DeclarationKind::Synthetic);
      break;
    case ScopeContext::EnclosingLexicalBindingKind::PrivateMethod:
      *out = Some(DeclarationKind::PrivateMethod);
      break;
  }
  return true;
}

bool ParseContext::tryDeclareVar(TaggedParserAtomIndex name, ParserBase* parser,
                                 DeclarationKind kind, uint32_t beginPos,
                                 Maybe<DeclarationKind>* redeclaredKind,
                                 uint32_t* prevPos) {
  return tryDeclareVarHelper<NotDryRun>(name, parser, kind, beginPos,
                                        redeclaredKind, prevPos);
}

template <ParseContext::DryRunOption dryRunOption>
bool ParseContext::tryDeclareVarHelper(TaggedParserAtomIndex name,
                                       ParserBase* parser, DeclarationKind kind,
                                       uint32_t beginPos,
                                       Maybe<DeclarationKind>* redeclaredKind,
                                       uint32_t* prevPos) {
  MOZ_ASSERT(DeclarationKindIsVar(kind));

  // It is an early error if a 'var' declaration appears inside a
  // scope contour that has a lexical declaration of the same name. For
  // example, the following are early errors:
  //
  //   { let x; var x; }
  //   { { var x; } let x; }
  //
  // And the following are not:
  //
  //   { var x; var x; }
  //   { { let x; } var x; }

  for (ParseContext::Scope* scope = innermostScope();
       scope != varScope().enclosing(); scope = scope->enclosing()) {
    if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
      DeclarationKind declaredKind = p->value()->kind();
      if (DeclarationKindIsVar(declaredKind)) {
        if (dryRunOption == NotDryRun) {
          RedeclareVar(p, kind);
        }
      } else if (!DeclarationKindIsParameter(declaredKind)) {
        // Annex B.3.5 allows redeclaring simple (non-destructured)
        // catch parameters with var declarations.
        bool annexB35Allowance =
            declaredKind == DeclarationKind::SimpleCatchParameter;

        // Annex B.3.3 allows redeclaring functions in the same block.
        bool annexB33Allowance =
            declaredKind == DeclarationKind::SloppyLexicalFunction &&
            kind == DeclarationKind::VarForAnnexBLexicalFunction &&
            scope == innermostScope();

        if (!annexB35Allowance && !annexB33Allowance) {
          *redeclaredKind = Some(declaredKind);
          *prevPos = p->value()->pos();
          return true;
        }
      } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
        MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));

        // Annex B.3.3.1 disallows redeclaring parameter names.
        // We don't need to set *prevPos here since this case is not
        // an error.
        *redeclaredKind = Some(declaredKind);
        return true;
      }
    } else if (dryRunOption == NotDryRun) {
      if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
        return false;
      }
    }

    // DryRunOption is used for propagating Annex B functions: we don't
    // want to declare the synthesized Annex B vars until we exit the var
    // scope and know that no early errors would have occurred. In order
    // to avoid quadratic search, we only check for var redeclarations in
    // the innermost scope when doing a dry run.
    if (dryRunOption == DryRunInnermostScopeOnly) {
      break;
    }
  }

  if (!sc()->strict() && sc()->isEvalContext() &&
      (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
    if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
      return false;
    }
    // We don't have position information at runtime.
    *prevPos = DeclaredNameInfo::npos;
  }

  return true;
}

bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
                               TaggedParserAtomIndex name) {
  if (auto p = usedNames.lookup(name)) {
    return p->value().isUsedInScript(scriptId());
  }
  return false;
}

bool ParseContext::hasClosedOverName(const UsedNameTracker& usedNames,
                                     TaggedParserAtomIndex name) {
  if (auto p = usedNames.lookup(name)) {
    return p->value().isClosedOver(scriptId());
  }
  return false;
}

bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
                                              TaggedParserAtomIndex name) {
  MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
             name == TaggedParserAtomIndex::WellKnown::dot_this_() ||
             name == TaggedParserAtomIndex::WellKnown::dot_newTarget_());
  return hasUsedName(usedNames, name) ||
         functionBox()->bindingsAccessedDynamically();
}

bool ParseContext::hasClosedOverFunctionSpecialName(
    const UsedNameTracker& usedNames, TaggedParserAtomIndex name) {
  MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments());
  return hasClosedOverName(usedNames, name) ||
         functionBox()->bindingsAccessedDynamically();
}

bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
                                       bool canSkipLazyClosedOverBindings) {
  // The asm.js validator does all its own symbol-table management so, as an
  // optimization, avoid doing any work here.
  if (useAsmOrInsideUseAsm()) {
    return true;
  }

  // Derived class constructors emit JSOp::CheckReturn, which requires
  // '.this' to be bound. Class field initializers implicitly read `.this`.
  // Therefore we unconditionally declare `.this` in all class constructors.
  FunctionBox* funbox = functionBox();
  auto dotThis = TaggedParserAtomIndex::WellKnown::dot_this_();

  bool declareThis;
  if (canSkipLazyClosedOverBindings) {
    declareThis = funbox->functionHasThisBinding();
  } else {
    declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
                  funbox->isClassConstructor();
  }

  if (declareThis) {
    ParseContext::Scope& funScope = functionScope();
    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
    MOZ_ASSERT(!p);
    if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
                                  DeclaredNameInfo::npos)) {
      return false;
    }
    funbox->setFunctionHasThisBinding();
  }

  return true;
}

bool ParseContext::declareFunctionArgumentsObject(
    const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
  FunctionBox* funbox = functionBox();
  ParseContext::Scope& funScope = functionScope();
  ParseContext::Scope& _varScope = varScope();

  bool hasExtraBodyVarScope = &funScope != &_varScope;

  // Time to implement the odd semantics of 'arguments'.
  auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();

  bool tryDeclareArguments = false;
  bool needsArgsObject = false;

  // When delazifying simply defer to the function box.
  if (canSkipLazyClosedOverBindings) {
    tryDeclareArguments = funbox->shouldDeclareArguments();
    needsArgsObject = funbox->needsArgsObj();
  } else {
    // We cannot compute these values when delazifying, hence why we need to
    // rely on the function box flags instead.
    bool bindingClosedOver =
        hasClosedOverFunctionSpecialName(usedNames, argumentsName);
    bool bindingUsedOnlyHere =
        hasUsedFunctionSpecialName(usedNames, argumentsName) &&
        !bindingClosedOver;

    // Declare arguments if there's a closed-over consumer of the binding, or if
    // there is a non-length use and we will reference the binding during
    // bytecode emission.
    tryDeclareArguments =
        !funbox->isEligibleForArgumentsLength() || bindingClosedOver;
    // If we have a use and the binding isn't closed over, then we will do
    // bytecode emission with the arguments intrinsic.
    if (bindingUsedOnlyHere && funbox->isEligibleForArgumentsLength()) {
      // If we're using the intrinsic we should not be declaring the binding.
      MOZ_ASSERT(!tryDeclareArguments);
      funbox->setUsesArgumentsIntrinsics();
    } else if (tryDeclareArguments) {
      needsArgsObject = true;
    }
  }

  // ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
  // and body-level functions named 'arguments' shadow the arguments
  // object.
  //
  // So even if there wasn't a free use of 'arguments' but there is a var
  // binding of 'arguments', we still might need the arguments object.
  //
  // If we have an extra var scope due to parameter expressions and the body
  // declared 'var arguments', we still need to declare 'arguments' in the
  // function scope.
  DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
  if (p && p->value()->kind() == DeclarationKind::Var) {
    if (hasExtraBodyVarScope) {
      // While there is a binding in the var scope, we should declare
      // the binding in the function scope.
      tryDeclareArguments = true;
    } else {
      // A binding in the function scope (since varScope and functionScope are
      // the same) exists, so arguments is used.
      if (needsArgsObject) {
        funbox->setNeedsArgsObj();
      }

      // There is no point in continuing on below: We know we already have
      // a declaration of arguments in the function scope.
      return true;
    }
  }

  if (tryDeclareArguments) {
    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
    if (!p) {
      if (!funScope.addDeclaredName(this, p, argumentsName,
                                    DeclarationKind::Var,
                                    DeclaredNameInfo::npos)) {
        return false;
      }
      funbox->setShouldDeclareArguments();
      if (needsArgsObject) {
        funbox->setNeedsArgsObj();
      }
    }
  }
  return true;
}

bool ParseContext::declareNewTarget(const UsedNameTracker& usedNames,
                                    bool canSkipLazyClosedOverBindings) {
  // The asm.js validator does all its own symbol-table management so, as an
  // optimization, avoid doing any work here.
  if (useAsmOrInsideUseAsm()) {
    return true;
  }

  FunctionBox* funbox = functionBox();
  auto dotNewTarget = TaggedParserAtomIndex::WellKnown::dot_newTarget_();

  bool declareNewTarget;
  if (canSkipLazyClosedOverBindings) {
    declareNewTarget = funbox->functionHasNewTargetBinding();
  } else {
    declareNewTarget = hasUsedFunctionSpecialName(usedNames, dotNewTarget);
  }

  if (declareNewTarget) {
    ParseContext::Scope& funScope = functionScope();
    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotNewTarget);
    MOZ_ASSERT(!p);
    if (!funScope.addDeclaredName(this, p, dotNewTarget, DeclarationKind::Var,
                                  DeclaredNameInfo::npos)) {
      return false;
    }
    funbox->setFunctionHasNewTargetBinding();
  }

  return true;
}

bool ParseContext::declareDotGeneratorName() {
  // The special '.generator' binding must be on the function scope, and must
  // be marked closed-over, as generators expect to find it on the CallObject.
  ParseContext::Scope& funScope = functionScope();
  auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
  AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
  if (!p) {
    if (!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
                                  DeclaredNameInfo::npos, ClosedOver::Yes)) {
      return false;
    }
  }
  return true;
}

bool ParseContext::declareTopLevelDotGeneratorName() {
  // Provide a .generator binding on the module scope for compatibility with
  // generator code, which expect to find it on the CallObject for normal
  // generators.
  MOZ_ASSERT(
      sc()->isModuleContext(),
      "Tried to declare top level dot generator in a non-module context.");
  ParseContext::Scope& modScope = varScope();
  auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
  AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
  return p ||
         modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
                                  DeclaredNameInfo::npos, ClosedOver::Yes);
}

}  // namespace frontend

}  // namespace js

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

¤ Dauer der Verarbeitung: 0.14 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.