js/src/frontend/Parser.cpp
author Jeff Walden <jwalden@mit.edu>
Tue, 16 Oct 2018 15:41:32 -0700
changeset 489847 0522e105ea10e64fcd421dd082e0ba1cd02dfae1
parent 489716 847c7c6af1db86f0edcae2986a9a9582160f4f4b
child 490631 430db29f46858faff930e2ec3ed45fbf13a73a20
permissions -rw-r--r--
Rename the current CharT typename parameter, used for either char16_t or mozilla::Utf8Unit, to Unit -- so that CharT can be used for actual C++ character types, when such are needed to intermesh with character-demanding APIs. Also change a few "chars" in function/variable names to "units" for consistency. No bug, rs=jorendorff over IRC

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * 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/Range.h"
#include "mozilla/Sprintf.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Unused.h"
#include "mozilla/Utf8.h"

#include <memory>
#include <new>

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

#include "builtin/ModuleObject.h"
#include "builtin/SelfHostingDefines.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/FoldConstants.h"
#include "frontend/ParseNode.h"
#include "frontend/TokenStream.h"
#include "irregexp/RegExpParser.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSAtom.h"
#include "vm/JSContext.h"
#include "vm/JSFunction.h"
#include "vm/JSScript.h"
#include "vm/RegExpObject.h"
#include "vm/StringType.h"
#include "wasm/AsmJS.h"

#include "frontend/ParseContext-inl.h"
#include "vm/EnvironmentObject-inl.h"

using namespace js;

using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::Some;
using mozilla::Unused;
using mozilla::Utf8Unit;

using JS::AutoGCRooter;
using JS::ReadOnlyCompileOptions;

namespace js {
namespace frontend {

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

using BindingNameVector = Vector<BindingName, 6>;

// Read a token. Report an error and return null() if that token doesn't match
// to the condition.  Do not use MUST_MATCH_TOKEN_INTERNAL directly.
#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport, failureValue)                \
    JS_BEGIN_MACRO                                                                          \
        TokenKind token;                                                                    \
        if (!tokenStream.getToken(&token, modifier))                                        \
            return failureValue;                                                            \
        if (!(cond)) {                                                                      \
            errorReport;                                                                    \
            return failureValue;                                                            \
        }                                                                                   \
    JS_END_MACRO

#define MUST_MATCH_TOKEN_MOD_OR(tt, modifier, errorNumber, failureValue) \
    MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber), failureValue)

#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
    MUST_MATCH_TOKEN_MOD_OR(tt, modifier, errorNumber, null())

#define MUST_MATCH_TOKEN_OR(tt, errorNumber, failureValue) \
    MUST_MATCH_TOKEN_MOD_OR(tt, TokenStream::None, errorNumber, failureValue)

#define MUST_MATCH_TOKEN(tt, errorNumber) \
    MUST_MATCH_TOKEN_OR(tt, errorNumber, null())

#define MUST_MATCH_TOKEN_FUNC_MOD_OR(func, modifier, errorNumber, failureValue) \
    MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber), failureValue)

#define MUST_MATCH_TOKEN_FUNC_OR(func, errorNumber, failureValue) \
    MUST_MATCH_TOKEN_FUNC_MOD_OR(func, TokenStream::None, errorNumber, failureValue)

#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \
    MUST_MATCH_TOKEN_FUNC_OR(func, errorNumber, null())

#define MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(tt, modifier, errorReport, failureValue) \
    MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport, failureValue)

#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \
    MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(tt, modifier, errorReport, null())

template <class T, class U>
static inline void
PropagateTransitiveParseFlags(const T* inner, U* outer)
{
    if (inner->bindingsAccessedDynamically()) {
        outer->setBindingsAccessedDynamically();
    }
    if (inner->hasDebuggerStatement()) {
        outer->setHasDebuggerStatement();
    }
    if (inner->hasDirectEval()) {
        outer->setHasDirectEval();
    }
}

static 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";
      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::ForOfVar:
        return "var in for-of";
      case DeclarationKind::SimpleCatchParameter:
      case DeclarationKind::CatchParameter:
        return "catch parameter";
    }

    MOZ_CRASH("Bad DeclarationKind");
}

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

void
ParseContext::Scope::dump(ParseContext* pc)
{
    JSContext* cx = pc->sc()->context;

    fprintf(stdout, "ParseScope %p", this);

    fprintf(stdout, "\n  decls:\n");
    for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
        UniqueChars bytes = AtomToPrintableString(cx, r.front().key());
        if (!bytes) {
            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()->context)) {
            return false;
        }
    }

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

bool
ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(ParseContext* pc)
{
    // 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.
        RootedPropertyName name(pc->sc()->context);
        Maybe<DeclarationKind> redeclaredKind;
        uint32_t unused;
        for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
            if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
                name = funbox->function()->explicitName()->asPropertyName();
                if (!pc->tryDeclareVar(name,
                                       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_) {
            if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
                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));
        JSAtom* 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()) {
        DeclaredNamePtr p = declared_->lookup(r.front().key());
        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);
        }
    }
}

void
SharedContext::computeAllowSyntax(Scope* scope)
{
    for (ScopeIter si(scope); si; si++) {
        if (si.kind() == ScopeKind::Function) {
            JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
            if (fun->isArrow()) {
                continue;
            }
            allowNewTarget_ = true;
            allowSuperProperty_ = fun->allowSuperProperty();
            allowSuperCall_ = fun->isDerivedClassConstructor();
            return;
        }
    }
}

void
SharedContext::computeThisBinding(Scope* scope)
{
    for (ScopeIter si(scope); si; si++) {
        if (si.kind() == ScopeKind::Module) {
            thisBinding_ = ThisBinding::Module;
            return;
        }

        if (si.kind() == ScopeKind::Function) {
            JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();

            // Arrow functions don't have their own `this` binding.
            if (fun->isArrow()) {
                continue;
            }

            // Derived class constructors (including nested arrow functions and
            // eval) need TDZ checks when accessing |this|.
            if (fun->isDerivedClassConstructor()) {
                needsThisTDZChecks_ = true;
            }

            thisBinding_ = ThisBinding::Function;
            return;
        }
    }

    thisBinding_ = ThisBinding::Global;
}

void
SharedContext::computeInWith(Scope* scope)
{
    for (ScopeIter si(scope); si; si++) {
        if (si.kind() == ScopeKind::With) {
            inWith_ = true;
            break;
        }
    }
}

EvalSharedContext::EvalSharedContext(JSContext* cx, JSObject* enclosingEnv,
                                     Scope* enclosingScope, Directives directives,
                                     bool extraWarnings)
  : SharedContext(cx, Kind::Eval, directives, extraWarnings),
    enclosingScope_(cx, enclosingScope),
    bindings(cx)
{
    computeAllowSyntax(enclosingScope);
    computeInWith(enclosingScope);
    computeThisBinding(enclosingScope);

    // If this eval is in response to Debugger.Frame.eval, we may have been
    // passed an incomplete scope chain. In order to better determine the 'this'
    // binding type, we traverse the environment chain, looking for a CallObject
    // and recompute the binding type based on its body scope.
    //
    // NOTE: A non-debug eval in a non-syntactic environment will also trigger
    // this code. In that case, we should still compute the same binding type.
    if (enclosingEnv && enclosingScope->hasOnChain(ScopeKind::NonSyntactic)) {
        JSObject* env = enclosingEnv;
        while (env) {
            // Look at target of any DebugEnvironmentProxy, but be sure to use
            // enclosingEnvironment() of the proxy itself.
            JSObject* unwrapped = env;
            if (env->is<DebugEnvironmentProxy>()) {
                unwrapped = &env->as<DebugEnvironmentProxy>().environment();
            }

            if (unwrapped->is<CallObject>()) {
                JSFunction* callee = &unwrapped->as<CallObject>().callee();
                computeThisBinding(callee->nonLazyScript()->bodyScope());
                break;
            }

            env = env->enclosingEnvironment();
        }
    }
}

ParseContext::ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc,
                           ErrorReporter& errorReporter, class UsedNameTracker& usedNames,
                           Directives* newDirectives, bool isFull)
  : Nestable<ParseContext>(&parent),
    traceLog_(sc->context,
              isFull
              ? TraceLogger_ParsingFull
              : TraceLogger_ParsingSyntax,
              errorReporter),
    sc_(sc),
    errorReporter_(errorReporter),
    innermostStatement_(nullptr),
    innermostScope_(nullptr),
    varScope_(nullptr),
    positionalFormalParameterNames_(cx->frontendCollectionPool()),
    closedOverBindingsForLazy_(cx->frontendCollectionPool()),
    innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
    newDirectives(newDirectives),
    lastYieldOffset(NoYieldOffset),
    lastAwaitOffset(NoAwaitOffset),
    scriptId_(usedNames.nextScriptId()),
    isStandaloneFunctionBody_(false),
    superScopeNeedsHomeObject_(false)
{
    if (isFunctionBox()) {
        if (functionBox()->function()->isNamedLambda()) {
            namedLambdaScope_.emplace(cx, parent, usedNames);
        }
        functionScope_.emplace(cx, parent, usedNames);
    }
}

bool
ParseContext::init()
{
    if (scriptId_ == UINT32_MAX) {
        errorReporter_.reportErrorNoOffset(JSMSG_NEED_DIET, js_script_str);
        return false;
    }

    JSContext* cx = sc()->context;

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

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

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

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

    return true;
}

bool
UsedNameTracker::noteUse(JSContext* cx, JSAtom* name, uint32_t scriptId, uint32_t scopeId)
{
    if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
        if (!p || !p->value().noteUsedInScope(scriptId, scopeId)) {
            return false;
        }
    } else {
        UsedNameInfo info(cx);
        if (!info.noteUsedInScope(scriptId, scopeId)) {
            return false;
        }
        if (!map_.add(p, name, std::move(info))) {
            return false;
        }
    }

    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);
    }
}

#ifdef DEBUG
bool
FunctionBox::atomsAreKept()
{
    return context->zone()->hasKeptAtoms();
}
#endif

FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead,
                         JSFunction* fun, uint32_t toStringStart,
                         Directives directives, bool extraWarnings,
                         GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
  : ObjectBox(fun, traceListHead),
    SharedContext(cx, Kind::FunctionBox, directives, extraWarnings),
    enclosingScope_(nullptr),
    namedLambdaBindings_(nullptr),
    functionScopeBindings_(nullptr),
    extraVarScopeBindings_(nullptr),
    functionNode(nullptr),
    bufStart(0),
    bufEnd(0),
    startLine(1),
    startColumn(0),
    toStringStart(toStringStart),
    toStringEnd(0),
    length(0),
    isGenerator_(generatorKind == GeneratorKind::Generator),
    isAsync_(asyncKind == FunctionAsyncKind::AsyncFunction),
    hasDestructuringArgs(false),
    hasParameterExprs(false),
    hasDirectEvalInParameterExpr(false),
    hasDuplicateParameters(false),
    useAsm(false),
    isAnnexB(false),
    wasEmitted(false),
    declaredArguments(false),
    usesArguments(false),
    usesApply(false),
    usesThis(false),
    usesReturn(false),
    hasRest_(false),
    hasExprBody_(false),
    hasExtensibleScope_(false),
    argumentsHasLocalBinding_(false),
    definitelyNeedsArgsObj_(false),
    needsHomeObject_(false),
    isDerivedClassConstructor_(false),
    hasThisBinding_(false),
    hasInnerFunctions_(false)
{
    // Functions created at parse time may be set singleton after parsing and
    // baked into JIT code, so they must be allocated tenured. They are held by
    // the JSScript so cannot be collected during a minor GC anyway.
    MOZ_ASSERT(fun->isTenured());
}

void
FunctionBox::initFromLazyFunction()
{
    JSFunction* fun = function();
    if (fun->lazyScript()->isDerivedClassConstructor()) {
        setDerivedClassConstructor();
    }
    if (fun->lazyScript()->needsHomeObject()) {
        setNeedsHomeObject();
    }
    if (fun->lazyScript()->hasEnclosingScope()) {
        enclosingScope_ = fun->lazyScript()->enclosingScope();
    } else {
        enclosingScope_ = nullptr;
    }
    initWithEnclosingScope(enclosingScope_);
}

void
FunctionBox::initStandaloneFunction(Scope* enclosingScope)
{
    // Standalone functions are Function or Generator constructors and are
    // always scoped to the global.
    MOZ_ASSERT(enclosingScope->is<GlobalScope>());
    enclosingScope_ = enclosingScope;
    allowNewTarget_ = true;
    thisBinding_ = ThisBinding::Function;
}

void
FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind)
{
    SharedContext* sc = enclosing->sc();
    useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();

    JSFunction* fun = function();

    // Arrow functions don't have their own `this` binding.
    if (fun->isArrow()) {
        allowNewTarget_ = sc->allowNewTarget();
        allowSuperProperty_ = sc->allowSuperProperty();
        allowSuperCall_ = sc->allowSuperCall();
        needsThisTDZChecks_ = sc->needsThisTDZChecks();
        thisBinding_ = sc->thisBinding();
    } else {
        allowNewTarget_ = true;
        allowSuperProperty_ = fun->allowSuperProperty();

        if (IsConstructorKind(kind)) {
            auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
            MOZ_ASSERT(stmt);
            stmt->constructorBox = this;

            if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
                setDerivedClassConstructor();
                allowSuperCall_ = true;
                needsThisTDZChecks_ = true;
            }
        }

        thisBinding_ = ThisBinding::Function;
    }

    if (sc->inWith()) {
        inWith_ = true;
    } else {
        auto isWith = [](ParseContext::Statement* stmt) {
            return stmt->kind() == StatementKind::With;
        };

        inWith_ = enclosing->findInnermostStatement(isWith);
    }
}

void
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
{
    if (!function()->isArrow()) {
        allowNewTarget_ = true;
        allowSuperProperty_ = function()->allowSuperProperty();

        if (isDerivedClassConstructor()) {
            setDerivedClassConstructor();
            allowSuperCall_ = true;
            needsThisTDZChecks_ = true;
        }

        thisBinding_ = ThisBinding::Function;
    } else {
        computeAllowSyntax(enclosingScope);
        computeThisBinding(enclosingScope);
    }

    computeInWith(enclosingScope);
}

void
FunctionBox::setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope)
{
    MOZ_ASSERT(isLazyFunctionWithoutEnclosingScope());

    // For lazy functions inside a function which is being compiled, we cache
    // the incomplete scope object while compiling, and store it to the
    // LazyScript once the enclosing script successfully finishes compilation
    // in FunctionBox::finish.
    enclosingScope_ = enclosingScope;
}

void
FunctionBox::finish()
{
    if (!isLazyFunctionWithoutEnclosingScope()) {
        return;
    }
    MOZ_ASSERT(enclosingScope_);
    function()->lazyScript()->setEnclosingScope(enclosingScope_);
}

template <class ParseHandler, typename Unit>
inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
GeneralParser<ParseHandler, Unit>::asFinalParser()
{
    static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
                  "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(mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
                  "inheritance relationship required by the static_cast<> below");

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

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::error(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    if (tokenStream.computeErrorMetadata(&metadata, pos().begin)) {
        ReportCompileError(context, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
    }

    va_end(args);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::errorWithNotes(UniquePtr<JSErrorNotes> notes,
                                                  unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    if (tokenStream.computeErrorMetadata(&metadata, pos().begin)) {
        ReportCompileError(context, std::move(metadata), std::move(notes), JSREPORT_ERROR, errorNumber,
                           args);
    }

    va_end(args);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::errorAt(uint32_t offset, unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    if (tokenStream.computeErrorMetadata(&metadata, offset)) {
        ReportCompileError(context, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
    }

    va_end(args);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::errorWithNotesAt(UniquePtr<JSErrorNotes> notes,
                                                    uint32_t offset, unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    if (tokenStream.computeErrorMetadata(&metadata, offset)) {
        ReportCompileError(context, std::move(metadata), std::move(notes), JSREPORT_ERROR, errorNumber,
                           args);
    }

    va_end(args);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::warning(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    bool result =
        tokenStream.computeErrorMetadata(&metadata, pos().begin) &&
        anyChars.compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);

    va_end(args);
    return result;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::warningAt(uint32_t offset, unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    bool result = tokenStream.computeErrorMetadata(&metadata, offset);
    if (result) {
        result =
            anyChars.compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);
    }

    va_end(args);
    return result;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::extraWarning(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    bool result =
        tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin, errorNumber, &args);

    va_end(args);
    return result;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::extraWarningAt(uint32_t offset, unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    bool result =
        tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);

    va_end(args);
    return result;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::strictModeError(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    bool res =
        tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(),
                                                  errorNumber, &args);

    va_end(args);
    return res;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    bool res =
        tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(),
                                                  errorNumber, &args);

    va_end(args);
    return res;
}

bool
ParserBase::warningNoOffset(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    anyChars.computeErrorMetadataNoOffset(&metadata);

    bool result =
        anyChars.compileWarning(std::move(metadata), nullptr, JSREPORT_WARNING, errorNumber, args);

    va_end(args);
    return result;
}

void
ParserBase::errorNoOffset(unsigned errorNumber, ...)
{
    va_list args;
    va_start(args, errorNumber);

    ErrorMetadata metadata;
    anyChars.computeErrorMetadataNoOffset(&metadata);

    ReportCompileError(context, std::move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);

    va_end(args);
}

ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
                       const ReadOnlyCompileOptions& options,
                       bool foldConstants,
                       UsedNameTracker& usedNames,
                       ScriptSourceObject* sourceObject,
                       ParseGoal parseGoal)
  : AutoGCRooter(cx, AutoGCRooter::Tag::Parser),
    context(cx),
    alloc(alloc),
    anyChars(cx, options, thisForCtor()),
    traceListHead(nullptr),
    pc(nullptr),
    usedNames(usedNames),
    ss(nullptr),
    sourceObject(cx, sourceObject),
    keepAtoms(cx),
    foldConstants(foldConstants),
#ifdef DEBUG
    checkOptionsCalled(false),
#endif
    isUnexpectedEOF_(false),
    awaitHandling_(AwaitIsName),
    inParametersOfAsyncFunction_(false),
    parseGoal_(uint8_t(parseGoal))
{
    cx->frontendCollectionPool().addActiveCompilation();
    tempPoolMark = alloc.mark();
}

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

    return anyChars.checkOptions();
}

ParserBase::~ParserBase()
{
    MOZ_ASSERT(checkOptionsCalled);

    alloc.release(tempPoolMark);

    /*
     * The parser can allocate enormous amounts of memory for large functions.
     * Eagerly free the memory now (which otherwise won't be freed until the
     * next GC) to avoid unnecessary OOMs.
     */
    alloc.freeAllIfHugeAndUnused();

    context->frontendCollectionPool().removeActiveCompilation();
}

template <class ParseHandler>
PerHandlerParser<ParseHandler>::PerHandlerParser(JSContext* cx, LifoAlloc& alloc,
                                                 const ReadOnlyCompileOptions& options,
                                                 bool foldConstants, UsedNameTracker& usedNames,
                                                 LazyScript* lazyOuterFunction,
                                                 ScriptSourceObject* sourceObject,
                                                 ParseGoal parseGoal, void* internalSyntaxParser)
  : ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject, parseGoal),
    handler(cx, alloc, lazyOuterFunction),
    internalSyntaxParser_(internalSyntaxParser)
{

}

template <class ParseHandler, typename Unit>
GeneralParser<ParseHandler, Unit>::GeneralParser(JSContext* cx, LifoAlloc& alloc,
                                                 const ReadOnlyCompileOptions& options,
                                                 const Unit* units, size_t length,
                                                 bool foldConstants,
                                                 UsedNameTracker& usedNames,
                                                 SyntaxParser* syntaxParser,
                                                 LazyScript* lazyOuterFunction,
                                                 ScriptSourceObject* sourceObject,
                                                 ParseGoal parseGoal)
  : Base(cx, alloc, options, foldConstants, usedNames, syntaxParser, lazyOuterFunction,
         sourceObject, parseGoal),
    tokenStream(cx, 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);
}

ObjectBox*
ParserBase::newObjectBox(JSObject* obj)
{
    MOZ_ASSERT(obj);

    /*
     * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
     * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
     * arenas containing the entries must be alive until we are done with
     * scanning, parsing and code generation for the whole script or top-level
     * function.
     */

    ObjectBox* objbox = alloc.template new_<ObjectBox>(obj, traceListHead);
    if (!objbox) {
        ReportOutOfMemory(context);
        return nullptr;
    }

    traceListHead = objbox;

    return objbox;
}

template <class ParseHandler>
FunctionBox*
PerHandlerParser<ParseHandler>::newFunctionBox(CodeNodeType funNode, JSFunction* fun,
                                               uint32_t toStringStart,
                                               Directives inheritedDirectives,
                                               GeneratorKind generatorKind,
                                               FunctionAsyncKind asyncKind)
{
    MOZ_ASSERT(fun);

    /*
     * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
     * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
     * arenas containing the entries must be alive until we are done with
     * scanning, parsing and code generation for the whole script or top-level
     * function.
     */
    FunctionBox* funbox =
        alloc.new_<FunctionBox>(context, traceListHead, fun, toStringStart, inheritedDirectives,
                                options().extraWarningsOption, generatorKind, asyncKind);
    if (!funbox) {
        ReportOutOfMemory(context);
        return nullptr;
    }

    traceListHead = funbox;
    if (funNode) {
        handler.setFunctionBox(funNode, funbox);
    }

    return funbox;
}

ModuleSharedContext::ModuleSharedContext(JSContext* cx, ModuleObject* module,
                                         Scope* enclosingScope, ModuleBuilder& builder)
  : SharedContext(cx, Kind::Module, Directives(true), false),
    module_(cx, module),
    enclosingScope_(cx, enclosingScope),
    bindings(cx),
    builder(builder)
{
    thisBinding_ = ThisBinding::Module;
}

void
ParserBase::trace(JSTracer* trc)
{
    ObjectBox::TraceList(trc, traceListHead);
}

void
TraceParser(JSTracer* trc, AutoGCRooter* parser)
{
    static_cast<ParserBase*>(parser)->trace(trc);
}

bool
ParserBase::setSourceMapInfo()
{
    // 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(context, anyChars.displayURL())) {
            return false;
        }
    }

    if (anyChars.hasSourceMapURL()) {
        MOZ_ASSERT(!ss->hasSourceMapURL());
        if (!ss->setSourceMapURL(context, 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(context, options().sourceMapURL())) {
            return false;
        }
    }

    return true;
}


/*
 * Parse a top-level JS script.
 */
template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::parse()
{
    MOZ_ASSERT(checkOptionsCalled);

    Directives directives(options().strictOption);
    GlobalSharedContext globalsc(context, ScopeKind::Global,
                                 directives, options().extraWarningsOption);
    SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
    if (!globalpc.init()) {
        return null();
    }

    ParseContext::VarScope varScope(this);
    if (!varScope.init(pc)) {
        return null();
    }

    ListNodeType stmtList = statementList(YieldIsName);
    if (!stmtList) {
        return null();
    }

    TokenKind tt;
    if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
        return null();
    }
    if (tt != TokenKind::Eof) {
        error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
        return null();
    }
    if (foldConstants) {
        Node node = stmtList;
        if (!FoldConstants(context, &node, this)) {
            return null();
        }
        stmtList = handler.asList(node);
    }

    return stmtList;
}

/*
 * Strict mode forbids introducing new definitions for 'eval', 'arguments',
 * 'let', 'static', 'yield', or for any strict mode reserved word.
 */
bool
ParserBase::isValidStrictBinding(PropertyName* name)
{
    TokenKind tt = ReservedWordTokenKind(name);
    if (tt == TokenKind::Name) {
        return name != context->names().eval &&
               name != context->names().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->asPropertyName())) {
            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(pc->sc()->context);
        return;
    }

    uint32_t line, column;
    anyChars.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column);

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

    if (!notes->addNoteASCII(pc->sc()->context,
                             getFilename(), line, column,
                             GetErrorMessage, nullptr,
                             noteNumber, lineNumber, columnNumber))
    {
        return;
    }

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

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::reportRedeclaration(HandlePropertyName name,
                                                       DeclarationKind prevKind,
                                                       TokenPos pos, uint32_t prevPos)
{
    UniqueChars bytes = AtomToPrintableString(context, name);
    if (!bytes) {
        return;
    }

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

    auto notes = MakeUnique<JSErrorNotes>();
    if (!notes) {
        ReportOutOfMemory(pc->sc()->context);
        return;
    }

    uint32_t line, column;
    anyChars.srcCoords.lineNumAndColumnIndex(prevPos, &line, &column);

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

    if (!notes->addNoteASCII(pc->sc()->context,
                             getFilename(), line, column,
                             GetErrorMessage, nullptr,
                             JSMSG_REDECLARED_PREV,
                             lineNumber, columnNumber))
    {
        return;
    }

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

// 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(CodeNodeType funNode,
                                                                 HandlePropertyName 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()->needStrictChecks()) {
            UniqueChars bytes = AtomToPrintableString(context, name);
            if (!bytes) {
                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(name)) {
        ReportOutOfMemory(context);
        return false;
    }

    NameNodeType paramNode = newName(name);
    if (!paramNode) {
        return false;
    }

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

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

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

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

Maybe<DeclarationKind>
ParseContext::isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind)
{
    MOZ_ASSERT(DeclarationKindIsVar(kind));
    MOZ_ASSERT(sc()->isEvalContext());

    // In the case of eval, we also need to check enclosing VM scopes to see
    // if the var declaration is allowed in the context.
    //
    // This check is necessary in addition to
    // js::CheckEvalDeclarationConflicts because we only know during parsing
    // if a var is bound by for-of.
    js::Scope* enclosingScope = sc()->compilationEnclosingScope();
    js::Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
    MOZ_ASSERT(varScope);
    for (ScopeIter si(enclosingScope); si; si++) {
        for (js::BindingIter bi(si.scope()); bi; bi++) {
            if (bi.name() != name) {
                continue;
            }

            switch (bi.kind()) {
              case BindingKind::Let: {
                  // Annex B.3.5 allows redeclaring simple (non-destructured)
                  // catch parameters with var declarations, except when it
                  // appears in a for-of.
                  bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch &&
                                           kind != DeclarationKind::ForOfVar;
                  if (!annexB35Allowance) {
                      return Some(ScopeKindIsCatch(si.kind())
                                  ? DeclarationKind::CatchParameter
                                  : DeclarationKind::Let);
                  }
                  break;
              }

              case BindingKind::Const:
                return Some(DeclarationKind::Const);

              case BindingKind::Import:
              case BindingKind::FormalParameter:
              case BindingKind::Var:
              case BindingKind::NamedLambdaCallee:
                break;
            }
        }

        if (si.scope() == varScope) {
            break;
        }
    }

    return Nothing();
}

Maybe<DeclarationKind>
ParseContext::isVarRedeclaredInInnermostScope(HandlePropertyName name, DeclarationKind kind)
{
    Maybe<DeclarationKind> redeclaredKind;
    uint32_t unused;
    MOZ_ALWAYS_TRUE(tryDeclareVarHelper<DryRunInnermostScopeOnly>(name, kind,
                                                                  DeclaredNameInfo::npos,
                                                                  &redeclaredKind, &unused));
    return redeclaredKind;
}

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

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

template <ParseContext::DryRunOption dryRunOption>
bool
ParseContext::tryDeclareVarHelper(HandlePropertyName name, 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)) {
                // Any vars that are redeclared as body-level functions must
                // be recorded as body-level functions.
                //
                // In the case of global and eval scripts, GlobalDeclaration-
                // Instantiation [1] and EvalDeclarationInstantiation [2]
                // check for the declarability of global var and function
                // bindings via CanDeclareVar [3] and CanDeclareGlobal-
                // Function [4]. CanDeclareGlobalFunction is strictly more
                // restrictive than CanDeclareGlobalVar, so record the more
                // restrictive kind. These semantics are implemented in
                // CheckCanDeclareGlobalBinding.
                //
                // For a var previously declared as ForOfVar, this previous
                // DeclarationKind is used only to check for if the
                // 'arguments' binding should be declared. Since body-level
                // functions shadow 'arguments' [5], it is correct to alter
                // the kind to BodyLevelFunction. See
                // declareFunctionArgumentsObject.
                //
                // VarForAnnexBLexicalFunction declarations are declared when
                // the var scope exits. It is not possible for a var to be
                // previously declared as VarForAnnexBLexicalFunction and
                // checked for redeclaration.
                //
                // [1] ES 15.1.11
                // [2] ES 18.2.1.3
                // [3] ES 8.1.1.4.15
                // [4] ES 8.1.1.4.16
                // [5] ES 9.2.12
                if (dryRunOption == NotDryRun && kind == DeclarationKind::BodyLevelFunction) {
                    MOZ_ASSERT(declaredKind != DeclarationKind::VarForAnnexBLexicalFunction);
                    p->value()->alterKind(kind);
                }
            } else if (!DeclarationKindIsParameter(declaredKind)) {
                // Annex B.3.5 allows redeclaring simple (non-destructured)
                // catch parameters with var declarations, except when it
                // appears in a for-of.
                bool annexB35Allowance = declaredKind == DeclarationKind::SimpleCatchParameter &&
                                         kind != DeclarationKind::ForOfVar;

                // 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()))
    {
        *redeclaredKind = isVarRedeclaredInEval(name, kind);
        // We don't have position information at runtime.
        *prevPos = DeclaredNameInfo::npos;
    }

    return true;
}

bool
ParseContext::annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox)
{
    MOZ_ASSERT(!sc()->strict());

    RootedPropertyName name(sc()->context, funbox->function()->explicitName()->asPropertyName());
    Maybe<DeclarationKind> redeclaredKind =
        isVarRedeclaredInInnermostScope(name, DeclarationKind::VarForAnnexBLexicalFunction);

    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 (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) {
                DeclarationKind declaredKind = p->value()->kind();
                if (DeclarationKindIsParameter(declaredKind)) {
                    redeclaredKind = Some(declaredKind);
                } else {
                    MOZ_ASSERT(FunctionScope::isSpecialName(sc()->context, name));
                }
            }
        }
    }

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

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
                                                                              DeclarationKind kind,
                                                                              TokenPos pos)
{
    MOZ_ASSERT(DeclarationKindIsLexical(kind));

    // It is an early error to declare a lexical binding not directly
    // within a block.
    if (!StatementKindIsBraced(stmt.kind()) &&
        stmt.kind() != StatementKind::ForLoopLexicalHead)
    {
        errorAt(pos.begin,
                stmt.kind() == StatementKind::Label
                ? JSMSG_LEXICAL_DECL_LABEL
                : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
                DeclarationKindString(kind));
        return false;
    }

    return true;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::noteDeclaredName(HandlePropertyName name, DeclarationKind kind,
                                                    TokenPos pos)
{
    // 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:
      case DeclarationKind::ForOfVar: {
        Maybe<DeclarationKind> redeclaredKind;
        uint32_t prevPos;
        if (!pc->tryDeclareVar(name, 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)) {
              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)) {
            return false;
        }

        break;
      }

      case DeclarationKind::LexicalFunction: {
        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)) {
            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 more complex than calling checkLexicalDeclarationDirectlyWithin-
        // Block and are done in checkFunctionDefinition.

        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)) {
                return false;
            }
        }

        break;
      }

      case DeclarationKind::Let:
      case DeclarationKind::Const:
      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 == context->names().let) {
            errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
            return false;
        }

        MOZ_FALLTHROUGH;

      case DeclarationKind::Import:
        // Module code is always strict, so 'let' is always a keyword and never a name.
        MOZ_ASSERT(name != context->names().let);
        MOZ_FALLTHROUGH;

      case DeclarationKind::SimpleCatchParameter:
      case DeclarationKind::CatchParameter: {
        if (ParseContext::Statement* stmt = pc->innermostStatement()) {
            if (!checkLexicalDeclarationDirectlyWithinBlock(*stmt, kind, pos)) {
                return false;
            }
        }

        ParseContext::Scope* scope = pc->innermostScope();

        // 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;
            }
        }

        // 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)) {
            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 "
                  "tryDeclareVarForAnnexBLexicalFunction");
        break;
    }

    return true;
}

bool
ParserBase::noteUsedNameInternal(HandlePropertyName name)
{
    // 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.
    ParseContext::Scope* scope = pc->innermostScope();
    if (pc->sc()->isGlobalContext() && scope == &pc->varScope()) {
        return true;
    }

    return usedNames.noteUse(context, name, pc->scriptId(), scope->id());
}

bool
ParserBase::hasUsedName(HandlePropertyName name)
{
    if (UsedNamePtr p = usedNames.lookup(name)) {
        return p->value().isUsedInScript(pc->scriptId());
    }
    return false;
}

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)) {
        return false;
    }

    if (handler.canSkipLazyClosedOverBindings()) {
        // Scopes are nullptr-delimited in the LazyScript closed over bindings
        // array.
        while (JSAtom* name = handler.nextLazyClosedOverBinding()) {
            scope.lookupDeclaredName(name)->value()->setClosedOver();
        }
        return true;
    }

    bool isSyntaxParser = mozilla::IsSame<ParseHandler, SyntaxParseHandler>::value;
    uint32_t scriptId = pc->scriptId();
    uint32_t scopeId = scope.id();
    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        if (UsedNamePtr p = usedNames.lookup(bi.name())) {
            bool closedOver;
            p->value().noteBoundInScope(scriptId, scopeId, &closedOver);
            if (closedOver) {
                bi.setClosedOver();

                if (isSyntaxParser && !pc->closedOverBindingsForLazy().append(bi.name())) {
                    ReportOutOfMemory(context);
                    return false;
                }
            }
        }
    }

    // Append a nullptr to denote end-of-scope.
    if (isSyntaxParser && !pc->closedOverBindingsForLazy().append(nullptr)) {
        ReportOutOfMemory(context);
        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::Operand)) {
        return false;
    }
    if (tt != TokenKind::Eof) {
        error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
        return false;
    }
    return true;
}

template <typename Scope>
typename Scope::Data*
NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings)
{
    using Data = typename Scope::Data;
    size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
    auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
    if (!bindings) {
        ReportOutOfMemory(cx);
    }
    return bindings;
}

/**
 * Copy-construct |BindingName|s from |bindings| into |cursor|, then return
 * the location one past the newly-constructed |BindingName|s.
 */
static MOZ_MUST_USE BindingName*
FreshlyInitializeBindings(BindingName* cursor, const BindingNameVector& bindings)
{
    return std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
}

Maybe<GlobalScope::Data*>
NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector vars(context);
    BindingNameVector lets(context);
    BindingNameVector consts(context);

    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;
            BindingName binding(bi.name(), closedOver, isTopLevelFunction);
            if (!vars.append(binding)) {
                return Nothing();
            }
            break;
          }
          case BindingKind::Let: {
            BindingName binding(bi.name(), closedOver);
            if (!lets.append(binding)) {
                return Nothing();
            }
            break;
          }
          case BindingKind::Const: {
            BindingName binding(bi.name(), closedOver);
            if (!consts.append(binding)) {
                return Nothing();
            }
            break;
          }
          default:
            MOZ_CRASH("Bad global scope BindingKind");
        }
    }

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

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

        // The ordering here is important. See comments in GlobalScope.
        BindingName* start = bindings->trailingNames.start();
        BindingName* cursor = start;

        cursor = FreshlyInitializeBindings(cursor, vars);

        bindings->letStart = cursor - start;
        cursor = FreshlyInitializeBindings(cursor, lets);

        bindings->constStart = cursor - start;
        Unused << FreshlyInitializeBindings(cursor, consts);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<GlobalScope::Data*>
ParserBase::newGlobalScopeData(ParseContext::Scope& scope)
{
    return NewGlobalScopeData(context, scope, alloc, pc);
}

Maybe<ModuleScope::Data*>
NewModuleScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector imports(context);
    BindingNameVector vars(context);
    BindingNameVector lets(context);
    BindingNameVector consts(context);

    bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        // Imports are indirect bindings and must not be given known slots.
        BindingName 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;
          default:
            MOZ_CRASH("Bad module scope BindingKind");
        }
    }

    ModuleScope::Data* bindings = nullptr;
    uint32_t numBindings = imports.length() + vars.length() + lets.length() + consts.length();

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

        // The ordering here is important. See comments in ModuleScope.
        BindingName* start = bindings->trailingNames.start();
        BindingName* cursor = start;

        cursor = FreshlyInitializeBindings(cursor, imports);

        bindings->varStart = cursor - start;
        cursor = FreshlyInitializeBindings(cursor, vars);

        bindings->letStart = cursor - start;
        cursor = FreshlyInitializeBindings(cursor, lets);

        bindings->constStart = cursor - start;
        Unused << FreshlyInitializeBindings(cursor, consts);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<ModuleScope::Data*>
ParserBase::newModuleScopeData(ParseContext::Scope& scope)
{
    return NewModuleScopeData(context, scope, alloc, pc);
}

Maybe<EvalScope::Data*>
NewEvalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector vars(context);

    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        // Eval scopes only contain 'var' bindings. Make all bindings aliased
        // for now.
        MOZ_ASSERT(bi.kind() == BindingKind::Var);
        bool isTopLevelFunction = bi.declarationKind() == DeclarationKind::BodyLevelFunction;
        BindingName binding(bi.name(), true, isTopLevelFunction);
        if (!vars.append(binding)) {
            return Nothing();
        }
    }

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

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

        BindingName* start = bindings->trailingNames.start();
        BindingName* cursor = start;

        Unused << FreshlyInitializeBindings(cursor, vars);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<EvalScope::Data*>
ParserBase::newEvalScopeData(ParseContext::Scope& scope)
{
    return NewEvalScopeData(context, scope, alloc, pc);
}

Maybe<FunctionScope::Data*>
NewFunctionScopeData(JSContext* context, ParseContext::Scope& scope, bool hasParameterExprs, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector positionalFormals(context);
    BindingNameVector formals(context);
    BindingNameVector vars(context);

    bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
    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++) {
        JSAtom* name = pc->positionalFormalParameterNames()[i];

        BindingName 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 = allBindingsClosedOver ||
                              (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 (pc->positionalFormalParameterNames()[j] == name) {
                        closedOver = false;
                        break;
                    }
                }
            }

            bindName = BindingName(name, closedOver);
        }

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

    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        BindingName 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(context, bi.name()));
            if (!vars.append(binding)) {
                return Nothing();
            }
            break;
          default:
            break;
        }
    }

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

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

        // The ordering here is important. See comments in FunctionScope.
        BindingName* start = bindings->trailingNames.start();
        BindingName* cursor = start;

        cursor = FreshlyInitializeBindings(cursor, positionalFormals);

        bindings->nonPositionalFormalStart = cursor - start;
        cursor = FreshlyInitializeBindings(cursor, formals);

        bindings->varStart = cursor - start;
        Unused << FreshlyInitializeBindings(cursor, vars);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<FunctionScope::Data*>
ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
{
    return NewFunctionScopeData(context, scope, hasParameterExprs, alloc, pc);
}

Maybe<VarScope::Data*>
NewVarScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector vars(context);

    bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();

    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        if (bi.kind() == BindingKind::Var) {
            BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
            if (!vars.append(binding)) {
                return Nothing();
            }
        }
    }

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

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

        // The ordering here is important. See comments in FunctionScope.
        BindingName* start = bindings->trailingNames.start();
        BindingName* cursor = start;

        Unused << FreshlyInitializeBindings(cursor, vars);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<VarScope::Data*>
ParserBase::newVarScopeData(ParseContext::Scope& scope)
{
    return NewVarScopeData(context, scope, alloc, pc);
}

Maybe<LexicalScope::Data*>
NewLexicalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
{
    BindingNameVector lets(context);
    BindingNameVector consts(context);

    // Unlike other scopes with bindings which are body-level, it is unknown
    // if pc->sc()->allBindingsClosedOver() is correct at the time of
    // finishing parsing a lexical scope.
    //
    // Instead, pc->sc()->allBindingsClosedOver() is checked in
    // EmitterScope::enterLexical. Also see comment there.
    for (BindingIter bi = scope.bindings(pc); bi; bi++) {
        BindingName binding(bi.name(), 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;
          default:
            break;
        }
    }

    LexicalScope::Data* bindings = nullptr;
    uint32_t numBindings = lets.length() + consts.length();

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

        // The ordering here is important. See comments in LexicalScope.
        BindingName* cursor = bindings->trailingNames.start();
        BindingName* start = cursor;

        cursor = FreshlyInitializeBindings(cursor, lets);

        bindings->constStart = cursor - start;
        Unused << FreshlyInitializeBindings(cursor, consts);

        bindings->length = numBindings;
    }

    return Some(bindings);
}

Maybe<LexicalScope::Data*>
ParserBase::newLexicalScopeData(ParseContext::Scope& scope)
{
    return NewLexicalScopeData(context, scope, alloc, pc);
}

template <>
SyntaxParseHandler::LexicalScopeNodeType
PerHandlerParser<SyntaxParseHandler>::finishLexicalScope(ParseContext::Scope& scope, Node body)
{
    if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
        return null();
    }

    return handler.newLexicalScope(body);
}

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

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

    return handler.newLexicalScope(*bindings, body);
}

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

    ParseContext::VarScope varScope(this);
    if (!varScope.init(pc)) {
        return nullptr;
    }

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

        ParseNode* list = statementList(YieldIsName);
        if (!list) {
            return nullptr;
        }

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

        body = finishLexicalScope(lexicalScope, list);
        if (!body) {
            return nullptr;
        }
    }

#ifdef DEBUG
    if (evalpc.superScopeNeedsHomeObject() && evalsc->compilationEnclosingScope()) {
        // 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.
        ScopeIter si(evalsc->compilationEnclosingScope());
        for (; si; si++) {
            if (si.kind() == ScopeKind::Function) {
                JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
                if (fun->isArrow()) {
                    continue;
                }
                MOZ_ASSERT(fun->allowSuperProperty());
                MOZ_ASSERT(fun->nonLazyScript()->needsHomeObject());
                break;
            }
        }
        MOZ_ASSERT(!si.done(),
                   "Eval must have found an enclosing function box scope that allows super.property");
    }
#endif

    ParseNode* node = body;
    if (!FoldConstants(context, &node, this)) {
        return nullptr;
    }
    body = handler.asLexicalScope(node);

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

    // For eval scripts, since all bindings are automatically considered
    // closed over, we don't need to call propagateFreeNamesAndMarkClosed-
    // OverBindings. However, Annex B.3.3 functions still need to be marked.
    if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc)) {
        return nullptr;
    }

    Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc->varScope());
    if (!bindings) {
        return nullptr;
    }
    evalsc->bindings = *bindings;

    return body;
}

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

    ParseContext::VarScope varScope(this);
    if (!varScope.init(pc)) {
        return nullptr;
    }

    ListNode* body = statementList(YieldIsName);
    if (!body) {
        return nullptr;
    }

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

    ParseNode* node = body;
    if (!FoldConstants(context, &node, this)) {
        return null();
    }
    body = &node->as<ListNode>();

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

    // 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)) {
        return nullptr;
    }

    Maybe<GlobalScope::Data*> bindings = newGlobalScopeData(pc->varScope());
    if (!bindings) {
        return nullptr;
    }
    globalsc->bindings = *bindings;

    return body;
}

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

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

    ParseContext::VarScope varScope(this);
    if (!varScope.init(pc)) {
        return nullptr;
    }

    CodeNodeType moduleNode = handler.newModule(pos());
    if (!moduleNode) {
        return null();
    }

    AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this, AwaitIsModuleKeyword);
    ListNode* stmtList = statementList(YieldIsName);
    if (!stmtList) {
        return null();
    }

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

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

    if (!modulesc->builder.buildTables()) {
        return null();
    }

    // Check exported local bindings exist and mark them as closed over.
    for (auto entry : modulesc->builder.localExportEntries()) {
        JSAtom* name = entry->localName();
        MOZ_ASSERT(name);

        DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
        if (!p) {
            UniqueChars str = AtomToPrintableString(context, name);
            if (!str) {
                return null();
            }

            errorAt(TokenStream::NoOffset, JSMSG_MISSING_EXPORT, str.get());
            return null();
        }

        p->value()->setClosedOver();
    }

    ParseNode* node = stmtList;
    if (!FoldConstants(context, &node, this)) {
        return null();
    }
    stmtList = &node->as<ListNode>();

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

    if (!propagateFreeNamesAndMarkClosedOverBindings(modulepc.varScope())) {
        return null();
    }

    Maybe<ModuleScope::Data*> bindings = newModuleScopeData(modulepc.varScope());
    if (!bindings) {
        return nullptr;
    }

    modulesc->bindings = *bindings;
    return moduleNode;
}

template <typename Unit>
SyntaxParseHandler::CodeNodeType
Parser<SyntaxParseHandler, Unit>::moduleBody(ModuleSharedContext* modulesc)
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return SyntaxParseHandler::NodeFailure;
}

bool
ParserBase::hasUsedFunctionSpecialName(HandlePropertyName name)
{
    MOZ_ASSERT(name == context->names().arguments || name == context->names().dotThis);
    return hasUsedName(name) || pc->functionBox()->bindingsAccessedDynamically();
}

template <class ParseHandler>
bool
PerHandlerParser<ParseHandler>::declareFunctionThis()
{
    // 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;
    }

    // Derived class constructors emit JSOP_CHECKRETURN, which requires
    // '.this' to be bound.
    FunctionBox* funbox = pc->functionBox();
    HandlePropertyName dotThis = context->names().dotThis;

    bool declareThis;
    if (handler.canSkipLazyClosedOverBindings()) {
        declareThis = funbox->function()->lazyScript()->hasThisBinding();
    } else {
        declareThis = hasUsedFunctionSpecialName(dotThis) || funbox->isDerivedClassConstructor();
    }

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

    return true;
}

template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newInternalDotName(HandlePropertyName name)
{
    NameNodeType nameNode = newName(name);
    if (!nameNode) {
        return null();
    }
    if (!noteUsedName(name)) {
        return null();
    }
    return nameNode;
}

template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newThisName()
{
    return newInternalDotName(context->names().dotThis);
}

template <class ParseHandler>
typename ParseHandler::NameNodeType
PerHandlerParser<ParseHandler>::newDotGeneratorName()
{
    return newInternalDotName(context->names().dotGenerator);
}

bool
ParserBase::declareDotGeneratorName()
{
    // The special '.generator' binding must be on the function scope, as
    // generators expect to find it on the CallObject.
    ParseContext::Scope& funScope = pc->functionScope();
    HandlePropertyName dotGenerator = context->names().dotGenerator;
    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
    if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var,
                                        DeclaredNameInfo::npos))
    {
        return false;
    }
    return true;
}

template <class ParseHandler>
bool
PerHandlerParser<ParseHandler>::finishFunctionScopes(bool isStandaloneFunction)
{
    FunctionBox* funbox = pc->functionBox();

    if (funbox->hasParameterExprs) {
        if (!propagateFreeNamesAndMarkClosedOverBindings(pc->functionScope())) {
            return false;
        }
    }

    if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
        if (!propagateFreeNamesAndMarkClosedOverBindings(pc->namedLambdaScope())) {
            return false;
        }
    }

    return true;
}

template <>
bool
PerHandlerParser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
    if (!finishFunctionScopes(isStandaloneFunction)) {
        return false;
    }

    FunctionBox* funbox = pc->functionBox();
    bool hasParameterExprs = funbox->hasParameterExprs;

    if (hasParameterExprs) {
        Maybe<VarScope::Data*> bindings = newVarScopeData(pc->varScope());
        if (!bindings) {
            return false;
        }
        funbox->extraVarScopeBindings().set(*bindings);
    }

    {
        Maybe<FunctionScope::Data*> bindings = newFunctionScopeData(pc->functionScope(),
                                                                    hasParameterExprs);
        if (!bindings) {
            return false;
        }
        funbox->functionScopeBindings().set(*bindings);
    }

    if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
        Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(pc->namedLambdaScope());
        if (!bindings) {
            return false;
        }
        funbox->namedLambdaBindings().set(*bindings);
    }

    return true;
}

template <>
bool
PerHandlerParser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */)
{
    // The LazyScript for a lazily parsed function needs to know its set of
    // free variables and inner functions so that when it is fully parsed, we
    // can skip over any already syntax parsed inner functions and still
    // retain correct scope information.

    if (!finishFunctionScopes(isStandaloneFunction)) {
        return false;
    }

    // There are too many bindings or inner functions to be saved into the
    // LazyScript. Do a full parse.
    if (pc->closedOverBindingsForLazy().length() >= LazyScript::NumClosedOverBindingsLimit ||
        pc->innerFunctionsForLazy.length() >= LazyScript::NumInnerFunctionsLimit)
    {
        MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
        return false;
    }

    FunctionBox* funbox = pc->functionBox();
    RootedFunction fun(context, funbox->function());
    LazyScript* lazy = LazyScript::Create(context, fun, sourceObject,
                                          pc->closedOverBindingsForLazy(),
                                          pc->innerFunctionsForLazy,
                                          funbox->bufStart, funbox->bufEnd,
                                          funbox->toStringStart,
                                          funbox->startLine, funbox->startColumn,
                                          parseGoal());
    if (!lazy) {
        return false;
    }

    // Flags that need to be copied into the JSScript when we do the full
    // parse.
    if (pc->sc()->strict()) {
        lazy->setStrict();
    }
    lazy->setGeneratorKind(funbox->generatorKind());
    lazy->setAsyncKind(funbox->asyncKind());
    if (funbox->hasRest()) {
        lazy->setHasRest();
    }
    if (funbox->isLikelyConstructorWrapper()) {
        lazy->setLikelyConstructorWrapper();
    }
    if (funbox->isDerivedClassConstructor()) {
        lazy->setIsDerivedClassConstructor();
    }
    if (funbox->needsHomeObject()) {
        lazy->setNeedsHomeObject();
    }
    if (funbox->declaredArguments) {
        lazy->setShouldDeclareArguments();
    }
    if (funbox->hasThisBinding()) {
        lazy->setHasThisBinding();
    }

    // Flags that need to copied back into the parser when we do the full
    // parse.
    PropagateTransitiveParseFlags(funbox, lazy);

    fun->initLazyScript(lazy);
    return true;
}

static YieldHandling
GetYieldHandling(GeneratorKind generatorKind)
{
    if (generatorKind == GeneratorKind::NotGenerator) {
        return YieldIsName;
    }
    return YieldIsKeyword;
}

static AwaitHandling
GetAwaitHandling(FunctionAsyncKind asyncKind)
{
    if (asyncKind == FunctionAsyncKind::SyncFunction) {
        return AwaitIsName;
    }
    return AwaitIsKeyword;
}

template <typename Unit>
CodeNode*
Parser<FullParseHandler, Unit>::standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
                                                   const Maybe<uint32_t>& parameterListEnd,
                                                   GeneratorKind generatorKind,
                                                   FunctionAsyncKind asyncKind,
                                                   Directives inheritedDirectives,
                                                   Directives* newDirectives)
{
    MOZ_ASSERT(checkOptionsCalled);

    // Skip prelude.
    TokenKind tt;
    if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
        return null();
    }
    if (asyncKind == FunctionAsyncKind::AsyncFunction) {
        MOZ_ASSERT(tt == TokenKind::Async);
        if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
            return null();
        }
    }
    MOZ_ASSERT(tt == TokenKind::Function);

    if (!tokenStream.getToken(&tt)) {
        return null();
    }
    if (generatorKind == GeneratorKind::Generator) {
        MOZ_ASSERT(tt == TokenKind::Mul);
        if (!tokenStream.getToken(&tt)) {
            return null();
        }
    }

    // Skip function name, if present.
    if (TokenKindIsPossibleIdentifierName(tt)) {
        MOZ_ASSERT(anyChars.currentName() == fun->explicitName());
    } else {
        MOZ_ASSERT(fun->explicitName() == nullptr);
        anyChars.ungetToken();
    }

    CodeNodeType funNode = handler.newFunctionStatement(pos());
    if (!funNode) {
        return null();
    }

    ListNodeType argsbody = handler.newList(ParseNodeKind::ParamsBody, pos());
    if (!argsbody) {
        return null();
    }
    funNode->setBody(argsbody);

    FunctionBox* funbox = newFunctionBox(funNode, fun, /* toStringStart = */ 0,
                                         inheritedDirectives, generatorKind, asyncKind);
    if (!funbox) {
        return null();
    }
    funbox->initStandaloneFunction(enclosingScope);

    SourceParseContext funpc(this, funbox, newDirectives);
    if (!funpc.init()) {
        return null();
    }
    funpc.setIsStandaloneFunctionBody();

    YieldHandling yieldHandling = GetYieldHandling(generatorKind);
    AwaitHandling awaitHandling = GetAwaitHandling(asyncKind);
    AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
    if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode,
                                         FunctionSyntaxKind::Statement,
                                         parameterListEnd, /* isStandaloneFunction = */ true))
    {
        return null();
    }

    if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
        return null();
    }
    if (tt != TokenKind::Eof) {
        error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
        return null();
    }

    ParseNode* node = funNode;
    if (!FoldConstants(context, &node, this)) {
        return null();
    }
    funNode = &node->as<CodeNode>();

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

    return funNode;
}

template <class ParseHandler>
bool
PerHandlerParser<ParseHandler>::declareFunctionArgumentsObject()
{
    FunctionBox* funbox = pc->functionBox();
    ParseContext::Scope& funScope = pc->functionScope();
    ParseContext::Scope& varScope = pc->varScope();

    bool hasExtraBodyVarScope = &funScope != &varScope;

    // Time to implement the odd semantics of 'arguments'.
    HandlePropertyName argumentsName = context->names().arguments;

    bool tryDeclareArguments;
    if (handler.canSkipLazyClosedOverBindings()) {
        tryDeclareArguments = funbox->function()->lazyScript()->shouldDeclareArguments();
    } else {
        tryDeclareArguments = hasUsedFunctionSpecialName(argumentsName);
    }

    // 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 ||
              p->value()->kind() == DeclarationKind::ForOfVar))
    {
        if (hasExtraBodyVarScope) {
            tryDeclareArguments = true;
        } else {
            funbox->usesArguments = true;
        }
    }

    if (tryDeclareArguments) {
        AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
        if (!p) {
            if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var,
                                          DeclaredNameInfo::npos))
            {
                return false;
            }
            funbox->declaredArguments = true;
            funbox->usesArguments = true;
        } else if (hasExtraBodyVarScope) {
            // Formal parameters shadow the arguments object.
            return true;
        }
    }

    // Compute if we need an arguments object.
    if (funbox->usesArguments) {
        // There is an 'arguments' binding. Is the arguments object definitely
        // needed?
        //
        // Also see the flags' comments in ContextFlags.
        funbox->setArgumentsHasLocalBinding();

        // Dynamic scope access destroys all hope of optimization.
        if (pc->sc()->bindingsAccessedDynamically()) {
            funbox->setDefinitelyNeedsArgsObj();
        }

        // If a script contains the debugger statement either directly or
        // within an inner function, the arguments object should be created
        // eagerly so the Debugger API may observe bindings.
        if (pc->sc()->hasDebuggerStatement()) {
            funbox->setDefinitelyNeedsArgsObj();
        }
    }

    return true;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::LexicalScopeNodeType
GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling, YieldHandling yieldHandling,
                                                FunctionSyntaxKind kind, FunctionBodyType type)
{
    MOZ_ASSERT(pc->isFunctionBox());

#ifdef DEBUG
    uint32_t startYieldOffset = pc->lastYieldOffset;
#endif

    Node body;
    if (type == StatementListBody) {
        bool inheritedStrict = pc->sc()->strict();
        body = statementList(yieldHandling);
        if (!body) {
            return null();
        }

        // When we transitioned from non-strict to strict mode, we need to
        // validate that all parameter names are valid strict mode names.
        if (!inheritedStrict && pc->sc()->strict()) {
            MOZ_ASSERT(pc->sc()->hasExplicitUseStrict(),
                       "strict mode should only change when a 'use strict' directive is present");
            if (!hasValidSimpleStrictParameterNames()) {
                // Request that this function be reparsed as strict to report
                // the invalid parameter name at the correct source location.
                pc->newDirectives->setStrict();
                return null();
            }
        }
    } else {
        MOZ_ASSERT(type == ExpressionBody);

        // Async functions are implemented as generators, and generators are
        // assumed to be statement lists, to prepend initial `yield`.
        ListNodeType stmtList = null();
        if (pc->isAsync()) {
            stmtList = handler.newStatementList(pos());
            if (!stmtList) {
                return null();
            }
        }

        Node kid = assignExpr(inHandling, yieldHandling, TripledotProhibited);
        if (!kid) {
            return null();
        }

        body = handler.newExpressionBody(kid);
        if (!body) {
            return null();
        }

        if (pc->isAsync()) {
            handler.addStatementToList(stmtList, body);
            body = stmtList;
        }
    }

    MOZ_ASSERT_IF(!pc->isGenerator() && !pc->isAsync(), pc->lastYieldOffset == startYieldOffset);
    MOZ_ASSERT_IF(pc->isGenerator(), kind != FunctionSyntaxKind::Arrow);
    MOZ_ASSERT_IF(pc->isGenerator(), type == StatementListBody);

    if (pc->needsDotGeneratorName()) {
        MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
        if (!declareDotGeneratorName()) {
            return null();
        }
        NameNodeType generator = newDotGeneratorName();
        if (!generator) {
            return null();
        }
        if (!handler.prependInitialYield(handler.asList(body), generator)) {
            return null();
        }
    }

    // Declare the 'arguments' and 'this' bindings if necessary before
    // finishing up the scope so these special bindings get marked as closed
    // over if necessary. Arrow functions don't have these bindings.
    if (kind != FunctionSyntaxKind::Arrow) {
        if (!declareFunctionArgumentsObject()) {
            return null();
        }
        if (!declareFunctionThis()) {
            return null();
        }
    }

    return finishLexicalScope(pc->varScope(), body);
}

JSFunction*
AllocNewFunction(JSContext* cx, HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
                 FunctionAsyncKind asyncKind, HandleObject proto,
                 bool isSelfHosting /* = false */, bool inFunctionBox /* = false */)
{
    MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, atom != nullptr);

    RootedFunction fun(cx);

    gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
    JSFunction::Flags flags;
#ifdef DEBUG
    bool isGlobalSelfHostedBuiltin = false;
#endif
    switch (kind) {
      case FunctionSyntaxKind::Expression:
        flags = (generatorKind == GeneratorKind::NotGenerator &&
                 asyncKind == FunctionAsyncKind::SyncFunction
                 ? JSFunction::INTERPRETED_LAMBDA
                 : JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
        break;
      case FunctionSyntaxKind::Arrow:
        flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        break;
      case FunctionSyntaxKind::Method:
        flags = (generatorKind == GeneratorKind::NotGenerator &&
                 asyncKind == FunctionAsyncKind::SyncFunction
                 ? JSFunction::INTERPRETED_METHOD
                 : JSFunction::INTERPRETED_METHOD_GENERATOR_OR_ASYNC);
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        break;
      case FunctionSyntaxKind::ClassConstructor:
      case FunctionSyntaxKind::DerivedClassConstructor:
        flags = JSFunction::INTERPRETED_CLASS_CONSTRUCTOR;
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        break;
      case FunctionSyntaxKind::Getter:
        flags = JSFunction::INTERPRETED_GETTER;
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        break;
      case FunctionSyntaxKind::Setter:
        flags = JSFunction::INTERPRETED_SETTER;
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        break;
      default:
        MOZ_ASSERT(kind == FunctionSyntaxKind::Statement);
#ifdef DEBUG
        if (isSelfHosting && !inFunctionBox) {
            isGlobalSelfHostedBuiltin = true;
            allocKind = gc::AllocKind::FUNCTION_EXTENDED;
        }
#endif
        flags = (generatorKind == GeneratorKind::NotGenerator &&
                 asyncKind == FunctionAsyncKind::SyncFunction
                 ? JSFunction::INTERPRETED_NORMAL
                 : JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
    }

    // We store the async wrapper in a slot for later access.
    if (asyncKind == FunctionAsyncKind::AsyncFunction) {
        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
    }

    fun = NewFunctionWithProto(cx, nullptr, 0, flags, nullptr, atom, proto,
                               allocKind, TenuredObject);
    if (!fun) {
        return nullptr;
    }
    if (isSelfHosting) {
        fun->setIsSelfHostedBuiltin();
#ifdef DEBUG
        if (isGlobalSelfHostedBuiltin) {
            fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(false));
        }
#endif
    }
    return fun;
}

JSFunction*
ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
                        GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                        HandleObject proto)
{
    return AllocNewFunction(context, atom, kind, generatorKind, asyncKind, proto,
                            options().selfHostingMode, pc->isFunctionBox());
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::matchOrInsertSemicolon()
{
    TokenKind tt = TokenKind::Eof;
    if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
        return false;
    }
    if (tt != TokenKind::Eof &&
        tt != TokenKind::Eol &&
        tt != TokenKind::Semi &&
        tt != TokenKind::RightCurly)
    {
        /*
         * When current token is `await` and it's outside of async function,
         * it's possibly intended to be an await expression.
         *
         *   await f();
         *        ^
         *        |
         *        tried to insert semicolon here
         *
         * Detect this situation and throw an understandable error.  Otherwise
         * we'd throw a confusing "unexpected token: (unexpected token)" error.
         */
        if (!pc->isAsync() && anyChars.currentToken().type == TokenKind::Await) {
            error(JSMSG_AWAIT_OUTSIDE_ASYNC);
            return false;
        }
        if (!yieldExpressionsSupported() && anyChars.currentToken().type == TokenKind::Yield) {
            error(JSMSG_YIELD_OUTSIDE_GENERATOR);
            return false;
        }

        /* Advance the scanner for proper error location reporting. */
        tokenStream.consumeKnownToken(tt, TokenStream::Operand);
        error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(tt));
        return false;
    }
    bool matched;
    return tokenStream.matchToken(&matched, TokenKind::Semi, TokenStream::Operand);
}

bool
ParserBase::leaveInnerFunction(ParseContext* outerpc)
{
    MOZ_ASSERT(pc != outerpc);

    // If the current function allows super.property but cannot have a home
    // object, i.e., it is an arrow function, we need to propagate the flag to
    // the outer ParseContext.
    if (pc->superScopeNeedsHomeObject()) {
        if (!pc->isArrowFunction()) {
            MOZ_ASSERT(pc->functionBox()->needsHomeObject());
        } else {
            outerpc->setSuperScopeNeedsHomeObject();
        }
    }

    // Lazy functions inner to another lazy function need to be remembered by
    // the inner function so that if the outer function is eventually parsed
    // we do not need any further parsing or processing of the inner function.
    //
    // Append the inner function here unconditionally; the vector is only used
    // if the Parser using outerpc is a syntax parsing. See
    // GeneralParser<SyntaxParseHandler>::finishFunction.
    if (!outerpc->innerFunctionsForLazy.append(pc->functionBox()->function())) {
        return false;
    }

    PropagateTransitiveParseFlags(pc->functionBox(), outerpc->sc());

    return true;
}

JSAtom*
ParserBase::prefixAccessorName(PropertyType propType, HandleAtom propAtom)
{
    RootedAtom prefix(context);
    if (propType == PropertyType::Setter) {
        prefix = context->names().setPrefix;
    } else {
        MOZ_ASSERT(propType == PropertyType::Getter);
        prefix = context->names().getPrefix;
    }

    RootedString str(context, ConcatStrings<CanGC>(context, prefix, propAtom));
    if (!str) {
        return nullptr;
    }

    return AtomizeString(context, str);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::functionArguments(YieldHandling yieldHandling,
                                                     FunctionSyntaxKind kind, CodeNodeType funNode)
{
    FunctionBox* funbox = pc->functionBox();

    bool parenFreeArrow = false;
    // Modifier for the following tokens.
    // TokenStream::None for the following cases:
    //   async a => 1
    //         ^
    //
    //   (a) => 1
    //   ^
    //
    //   async (a) => 1
    //         ^
    //
    //   function f(a) {}
    //             ^
    //
    // TokenStream::Operand for the following case:
    //   a => 1
    //   ^
    Modifier firstTokenModifier = TokenStream::None;

    // Modifier for the the first token in each argument.
    // can be changed to TokenStream::None for the following case:
    //   async a => 1
    //         ^
    Modifier argModifier = TokenStream::Operand;
    if (kind == FunctionSyntaxKind::Arrow) {
        TokenKind tt;
        // In async function, the first token after `async` is already gotten
        // with TokenStream::None.
        // In sync function, the first token is already gotten with
        // TokenStream::Operand.
        firstTokenModifier = funbox->isAsync() ? TokenStream::None : TokenStream::Operand;
        if (!tokenStream.peekToken(&tt, firstTokenModifier)) {
            return false;
        }
        if (TokenKindIsPossibleIdentifier(tt)) {
            parenFreeArrow = true;
            argModifier = firstTokenModifier;
        }
    }

    TokenPos firstTokenPos;
    if (!parenFreeArrow) {
        TokenKind tt;
        if (!tokenStream.getToken(&tt, firstTokenModifier)) {
            return false;
        }
        if (tt != TokenKind::LeftParen) {
            error(kind == FunctionSyntaxKind::Arrow
                  ? JSMSG_BAD_ARROW_ARGS
                  : JSMSG_PAREN_BEFORE_FORMAL);
            return false;
        }

        firstTokenPos = pos();

        // Record the start of function source (for FunctionToString). If we
        // are parenFreeArrow, we will set this below, after consuming the NAME.
        funbox->setStart(anyChars);
    } else {
        // When delazifying, we may not have a current token and pos() is
        // garbage. In that case, substitute the first token's position.
        if (!tokenStream.peekTokenPos(&firstTokenPos, firstTokenModifier)) {
            return false;
        }
    }

    ListNodeType argsbody = handler.newList(ParseNodeKind::ParamsBody, firstTokenPos);
    if (!argsbody) {
        return false;
    }
    handler.setFunctionFormalParametersAndBody(funNode, argsbody);

    bool hasArguments = false;
    if (parenFreeArrow) {
        hasArguments = true;
    } else {
        bool matched;
        if (!tokenStream.matchToken(&matched, TokenKind::RightParen, TokenStream::Operand)) {
            return false;
        }
        if (!matched) {
            hasArguments = true;
        }
    }
    if (hasArguments) {
        bool hasRest = false;
        bool hasDefault = false;
        bool duplicatedParam = false;
        bool disallowDuplicateParams = kind == FunctionSyntaxKind::Arrow ||
                                       kind == FunctionSyntaxKind::Method ||
                                       kind == FunctionSyntaxKind::ClassConstructor;
        AtomVector& positionalFormals = pc->positionalFormalParameterNames();

        if (kind == FunctionSyntaxKind::Getter) {
            error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
            return false;
        }

        while (true) {
            if (hasRest) {
                error(JSMSG_PARAMETER_AFTER_REST);
                return false;
            }

            TokenKind tt;
            if (!tokenStream.getToken(&tt, argModifier)) {
                return false;
            }
            argModifier = TokenStream::Operand;
            MOZ_ASSERT_IF(parenFreeArrow, TokenKindIsPossibleIdentifier(tt));

            if (tt == TokenKind::TripleDot) {
                if (kind == FunctionSyntaxKind::Setter) {
                    error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
                    return false;
                }

                disallowDuplicateParams = true;
                if (duplicatedParam) {
                    // Has duplicated args before the rest parameter.
                    error(JSMSG_BAD_DUP_ARGS);
                    return false;
                }

                hasRest = true;
                funbox->setHasRest();

                if (!tokenStream.getToken(&tt)) {
                    return false;
                }

                if (!TokenKindIsPossibleIdentifier(tt) &&
                    tt != TokenKind::LeftBracket &&
                    tt != TokenKind::LeftCurly)
                {
                    error(JSMSG_NO_REST_NAME);
                    return false;
                }
            }

            switch (tt) {
              case TokenKind::LeftBracket:
              case TokenKind::LeftCurly: {
                disallowDuplicateParams = true;
                if (duplicatedParam) {
                    // Has duplicated args before the destructuring parameter.
                    error(JSMSG_BAD_DUP_ARGS);
                    return false;
                }

                funbox->hasDestructuringArgs = true;

                Node destruct = destructuringDeclarationWithoutYieldOrAwait(
                    DeclarationKind::FormalParameter,
                    yieldHandling, tt);
                if (!destruct) {
                    return false;
                }

                if (!noteDestructuredPositionalFormalParameter(funNode, destruct)) {
                    return false;
                }

                break;
              }

              default: {
                if (!TokenKindIsPossibleIdentifier(tt)) {
                    error(JSMSG_MISSING_FORMAL);
                    return false;
                }

                if (parenFreeArrow) {
                    funbox->setStart(anyChars);
                }

                RootedPropertyName name(context, bindingIdentifier(yieldHandling));
                if (!name) {
                    return false;
                }

                if (!notePositionalFormalParameter(funNode, name, pos().begin,
                                                   disallowDuplicateParams, &duplicatedParam))
                {
                    return false;
                }
                if (duplicatedParam) {
                    funbox->hasDuplicateParameters = true;
                }

                break;
              }
            }

            if (positionalFormals.length() >= ARGNO_LIMIT) {
                error(JSMSG_TOO_MANY_FUN_ARGS);
                return false;
            }

            // The next step is to detect arguments with default expressions,
            // e.g. |function parseInt(str, radix = 10) {}|.  But if we have a
            // parentheses-free arrow function, |a => ...|, the '=' necessary
            // for a default expression would really be an assignment operator:
            // that is, |a = b => 42;| would parse as |a = (b => 42);|.  So we
            // should stop parsing arguments here.
            if (parenFreeArrow) {
                break;
            }

            bool matched;
            if (!tokenStream.matchToken(&matched, TokenKind::Assign, TokenStream::Operand)) {
                return false;
            }
            if (matched) {
                // A default argument without parentheses would look like:
                // a = expr => body, but both operators are right-associative, so
                // that would have been parsed as a = (expr => body) instead.
                // Therefore it's impossible to get here with parenFreeArrow.
                MOZ_ASSERT(!parenFreeArrow);

                if (hasRest) {
                    error(JSMSG_REST_WITH_DEFAULT);
                    return false;
                }
                disallowDuplicateParams = true;
                if (duplicatedParam) {
                    error(JSMSG_BAD_DUP_ARGS);
                    return false;
                }

                if (!hasDefault) {
                    hasDefault = true;

                    // The Function.length property is the number of formals
                    // before the first default argument.
                    funbox->length = positionalFormals.length() - 1;
                }
                funbox->hasParameterExprs = true;

                Node def_expr = assignExprWithoutYieldOrAwait(yieldHandling);
                if (!def_expr) {
                    return false;
                }
                if (!handler.setLastFunctionFormalParameterDefault(funNode, def_expr)) {
                    return false;
                }
            }

            // Setter syntax uniquely requires exactly one argument.
            if (kind == FunctionSyntaxKind::Setter) {
                break;
            }

            if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand)) {
                return false;
            }
            if (!matched) {
                break;
            }

            if (!hasRest) {
                if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
                    return false;
                }
                if (tt == TokenKind::RightParen) {
                    break;
                }
            }
        }

        if (!parenFreeArrow) {
            TokenKind tt;
            if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
                return false;
            }
            if (tt != TokenKind::RightParen) {
                if (kind == FunctionSyntaxKind::Setter) {
                    error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
                    return false;
                }

                error(JSMSG_PAREN_AFTER_FORMAL);
                return false;
            }
        }

        if (!hasDefault) {
            funbox->length = positionalFormals.length() - hasRest;
        }

        if (funbox->hasParameterExprs && funbox->hasDirectEval()) {
            funbox->hasDirectEvalInParameterExpr = true;
        }

        funbox->function()->setArgCount(positionalFormals.length());
    } else if (kind == FunctionSyntaxKind::Setter) {
        error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
        return false;
    }

    return true;
}

template <typename Unit>
bool
Parser<FullParseHandler, Unit>::skipLazyInnerFunction(CodeNode* funNode, uint32_t toStringStart,
                                                      FunctionSyntaxKind kind, bool tryAnnexB)
{
    // When a lazily-parsed function is called, we only fully parse (and emit)
    // that function, not any of its nested children. The initial syntax-only
    // parse recorded the free variables of nested functions and their extents,
    // so we can skip over them after accounting for their free variables.

    RootedFunction fun(context, handler.nextLazyInnerFunction());
    FunctionBox* funbox =
        newFunctionBox(funNode, fun, toStringStart, Directives(/* strict = */ false),
                       fun->generatorKind(), fun->asyncKind());
    if (!funbox) {
        return false;
    }

    LazyScript* lazy = fun->lazyScript();
    if (lazy->needsHomeObject()) {
        funbox->setNeedsHomeObject();
    }

    PropagateTransitiveParseFlags(lazy, pc->sc());

    if (!tokenStream.advance(fun->lazyScript()->sourceEnd())) {
        return false;
    }

    // Append possible Annex B function box only upon successfully parsing.
    if (tryAnnexB && !pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) {
        return false;
    }

    return true;
}

template <typename Unit>
bool
Parser<SyntaxParseHandler, Unit>::skipLazyInnerFunction(CodeNodeType funNode,
                                                        uint32_t toStringStart,
                                                        FunctionSyntaxKind kind, bool tryAnnexB)
{
    MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::skipLazyInnerFunction(CodeNodeType funNode,
                                                         uint32_t toStringStart,
                                                         FunctionSyntaxKind kind, bool tryAnnexB)
{
    return asFinalParser()->skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling,
                                                                  ListNodeType nodeList,
                                                                  TokenKind* ttp)
{
    Node pn = expr(InAllowed, yieldHandling, TripledotProhibited);
    if (!pn) {
        return false;
    }
    handler.addList(nodeList, pn);

    TokenKind tt;
    if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
        return false;
    }
    if (tt != TokenKind::RightCurly) {
        error(JSMSG_TEMPLSTR_UNTERM_EXPR);
        return false;
    }

    return tokenStream.getToken(ttp, TokenStream::TemplateTail);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::taggedTemplate(YieldHandling yieldHandling,
                                                  ListNodeType tagArgsList, TokenKind tt)
{
    CallSiteNodeType callSiteObjNode = handler.newCallSiteObject(pos().begin);
    if (!callSiteObjNode) {
        return false;
    }
    handler.addList(tagArgsList, callSiteObjNode);

    while (true) {
        if (!appendToCallSiteObj(callSiteObjNode)) {
            return false;
        }
        if (tt != TokenKind::TemplateHead) {
            break;
        }

        if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt)) {
            return false;
        }
    }
    handler.setEndPosition(tagArgsList, callSiteObjNode);
    return true;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::templateLiteral(YieldHandling yieldHandling)
{
    NameNodeType literal = noSubstitutionUntaggedTemplate();
    if (!literal) {
        return null();
    }

    ListNodeType nodeList = handler.newList(ParseNodeKind::TemplateStringList, literal);
    if (!nodeList) {
        return null();
    }

    TokenKind tt;
    do {
        if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) {
            return null();
        }

        literal = noSubstitutionUntaggedTemplate();
        if (!literal) {
            return null();
        }

        handler.addList(nodeList, literal);
    } while (tt == TokenKind::TemplateHead);
    return nodeList;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::CodeNodeType
GeneralParser<ParseHandler, Unit>::functionDefinition(CodeNodeType funNode, uint32_t toStringStart,
                                                      InHandling inHandling,
                                                      YieldHandling yieldHandling,
                                                      HandleAtom funName, FunctionSyntaxKind kind,
                                                      GeneratorKind generatorKind,
                                                      FunctionAsyncKind asyncKind,
                                                      bool tryAnnexB /* = false */)
{
    MOZ_ASSERT_IF(kind == FunctionSyntaxKind::Statement, funName);

    // When fully parsing a LazyScript, we do not fully reparse its inner
    // functions, which are also lazy. Instead, their free variables and
    // source extents are recorded and may be skipped.
    if (handler.canSkipLazyInnerFunctions()) {
        if (!skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB)) {
            return null();
        }

        return funNode;
    }

    RootedObject proto(context);
    if (generatorKind == GeneratorKind::Generator ||
        asyncKind == FunctionAsyncKind::AsyncFunction)
    {
        proto = GlobalObject::getOrCreateGeneratorFunctionPrototype(context, context->global());
        if (!proto) {
            return null();
        }
    }
    RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto));
    if (!fun) {
        return null();
    }

    // Speculatively parse using the directives of the parent parsing context.
    // If a directive is encountered (e.g., "use strict") that changes how the
    // function should have been parsed, we backup and reparse with the new set
    // of directives.
    Directives directives(pc);
    Directives newDirectives = directives;

    Position start(keepAtoms, tokenStream);

    // Parse the inner function. The following is a loop as we may attempt to
    // reparse a function due to failed syntax parsing and encountering new
    // "use foo" directives.
    while (true) {
        if (trySyntaxParseInnerFunction(&funNode, fun, toStringStart, inHandling, yieldHandling,
                                        kind, generatorKind, asyncKind, tryAnnexB, directives,
                                        &newDirectives))
        {
            break;
        }

        // Return on error.
        if (anyChars.hadError() || directives == newDirectives) {
            return null();
        }

        // Assignment must be monotonic to prevent infinitely attempting to
        // reparse.
        MOZ_ASSERT_IF(directives.strict(), newDirectives.strict());
        MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
        directives = newDirectives;

        tokenStream.seek(start);

        // functionFormalParametersAndBody may have already set body before
        // failing.
        handler.setFunctionFormalParametersAndBody(funNode, null());
    }

    return funNode;
}

template <typename Unit>
bool
Parser<FullParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNode** funNode, HandleFunction fun,
                                                            uint32_t toStringStart,
                                                            InHandling inHandling,
                                                            YieldHandling yieldHandling,
                                                            FunctionSyntaxKind kind,
                                                            GeneratorKind generatorKind,
                                                            FunctionAsyncKind asyncKind,
                                                            bool tryAnnexB,
                                                            Directives inheritedDirectives,
                                                            Directives* newDirectives)
{
    // Try a syntax parse for this inner function.
    do {
        // If we're assuming this function is an IIFE, always perform a full
        // parse to avoid the overhead of a lazy syntax-only parse. Although
        // the prediction may be incorrect, IIFEs are common enough that it
        // pays off for lots of code.
        if ((*funNode)->isLikelyIIFE() &&
            generatorKind == GeneratorKind::NotGenerator &&
            asyncKind == FunctionAsyncKind::SyncFunction)
        {
            break;
        }

        SyntaxParser* syntaxParser = getSyntaxParser();
        if (!syntaxParser) {
            break;
        }

        UsedNameTracker::RewindToken token = usedNames.getRewindToken();

        // Move the syntax parser to the current position in the stream.
        Position currentPosition(keepAtoms, tokenStream);
        if (!syntaxParser->tokenStream.seek(currentPosition, anyChars)) {
            return false;
        }

        // Make a FunctionBox before we enter the syntax parser, because |pn|
        // still expects a FunctionBox to be attached to it during BCE, and
        // the syntax parser cannot attach one to it.
        FunctionBox* funbox = newFunctionBox(*funNode, fun, toStringStart, inheritedDirectives,
                                             generatorKind, asyncKind);
        if (!funbox) {
            return false;
        }
        funbox->initWithEnclosingParseContext(pc, kind);

        SyntaxParseHandler::Node syntaxNode =
            syntaxParser->innerFunctionForFunctionBox(SyntaxParseHandler::NodeGeneric, pc, funbox,
                                                      inHandling, yieldHandling, kind,
                                                      newDirectives);
        if (!syntaxNode) {
            if (syntaxParser->hadAbortedSyntaxParse()) {
                // Try again with a full parse. UsedNameTracker needs to be
                // rewound to just before we tried the syntax parse for
                // correctness.
                syntaxParser->clearAbortedSyntaxParse();
                usedNames.rewind(token);
                MOZ_ASSERT_IF(!syntaxParser->context->helperThread(),
                              !syntaxParser->context->isExceptionPending());
                break;
            }
            return false;
        }

        // Advance this parser over tokens processed by the syntax parser.
        Position currentSyntaxPosition(keepAtoms, syntaxParser->tokenStream);
        if (!tokenStream.seek(currentSyntaxPosition, syntaxParser->anyChars)) {
            return false;
        }

        // Update the end position of the parse node.
        (*funNode)->pn_pos.end = anyChars.currentToken().pos.end;

        // Append possible Annex B function box only upon successfully parsing.
        if (tryAnnexB) {
            if (!pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) {
                return false;
            }
        }

        return true;
    } while (false);

    // We failed to do a syntax parse above, so do the full parse.
    CodeNodeType innerFunc =
        innerFunction(*funNode, pc, fun, toStringStart, inHandling, yieldHandling, kind,
                      generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
    if (!innerFunc) {
        return false;
    }

    *funNode = innerFunc;
    return true;
}

template <typename Unit>
bool
Parser<SyntaxParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNodeType* funNode,
                                                              HandleFunction fun,
                                                              uint32_t toStringStart,
                                                              InHandling inHandling,
                                                              YieldHandling yieldHandling,
                                                              FunctionSyntaxKind kind,
                                                              GeneratorKind generatorKind,
                                                              FunctionAsyncKind asyncKind,
                                                              bool tryAnnexB,
                                                              Directives inheritedDirectives,
                                                              Directives* newDirectives)
{
    // This is already a syntax parser, so just parse the inner function.
    CodeNodeType innerFunc =
        innerFunction(*funNode, pc, fun, toStringStart, inHandling, yieldHandling, kind,
                      generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);

    if (!innerFunc) {
        return false;
    }

    *funNode = innerFunc;
    return true;
}

template <class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::trySyntaxParseInnerFunction(CodeNodeType* funNode,
                                                               HandleFunction fun,
                                                               uint32_t toStringStart,
                                                               InHandling inHandling,
                                                               YieldHandling yieldHandling,
                                                               FunctionSyntaxKind kind,
                                                               GeneratorKind generatorKind,
                                                               FunctionAsyncKind asyncKind,
                                                               bool tryAnnexB,
                                                               Directives inheritedDirectives,
                                                               Directives* newDirectives)
{
    return asFinalParser()->trySyntaxParseInnerFunction(funNode, fun, toStringStart, inHandling,
                                                        yieldHandling, kind, generatorKind,
                                                        asyncKind, tryAnnexB, inheritedDirectives,
                                                        newDirectives);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::CodeNodeType
GeneralParser<ParseHandler, Unit>::innerFunctionForFunctionBox(CodeNodeType funNode,
                                                               ParseContext* outerpc,
                                                               FunctionBox* funbox,
                                                               InHandling inHandling,
                                                               YieldHandling yieldHandling,
                                                               FunctionSyntaxKind kind,
                                                               Directives* newDirectives)
{
    // Note that it is possible for outerpc != this->pc, as we may be
    // attempting to syntax parse an inner function from an outer full
    // parser. In that case, outerpc is a SourceParseContext from the full parser
    // instead of the current top of the stack of the syntax parser.

    // Push a new ParseContext.
    SourceParseContext funpc(this, funbox, newDirectives);
    if (!funpc.init()) {
        return null();
    }

    if (!functionFormalParametersAndBody(inHandling, yieldHandling, &funNode, kind)) {
        return null();
    }

    if (!leaveInnerFunction(outerpc)) {
        return null();
    }

    return funNode;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::CodeNodeType
GeneralParser<ParseHandler, Unit>::innerFunction(CodeNodeType funNode, ParseContext* outerpc,
                                                 HandleFunction fun, uint32_t toStringStart,
                                                 InHandling inHandling,
                                                 YieldHandling yieldHandling,
                                                 FunctionSyntaxKind kind,
                                                 GeneratorKind generatorKind,
                                                 FunctionAsyncKind asyncKind, bool tryAnnexB,
                                                 Directives inheritedDirectives,
                                                 Directives* newDirectives)
{
    // Note that it is possible for outerpc != this->pc, as we may be
    // attempting to syntax parse an inner function from an outer full
    // parser. In that case, outerpc is a SourceParseContext from the full parser
    // instead of the current top of the stack of the syntax parser.

    FunctionBox* funbox = newFunctionBox(funNode, fun, toStringStart, inheritedDirectives,
                                         generatorKind, asyncKind);
    if (!funbox) {
        return null();
    }
    funbox->initWithEnclosingParseContext(outerpc, kind);

    CodeNodeType innerFunc =
        innerFunctionForFunctionBox(funNode, outerpc, funbox, inHandling, yieldHandling, kind,
                                     newDirectives);
    if (!innerFunc) {
        return null();
    }

    // Append possible Annex B function box only upon successfully parsing.
    if (tryAnnexB) {
        if (!pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox)) {
            return null();
        }
    }

    return innerFunc;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::appendToCallSiteObj(CallSiteNodeType callSiteObj)
{
    Node cookedNode = noSubstitutionTaggedTemplate();
    if (!cookedNode) {
        return false;
    }

    JSAtom* atom = tokenStream.getRawTemplateStringAtom();
    if (!atom) {
        return false;
    }
    NameNodeType rawNode = handler.newTemplateStringLiteral(atom, pos());
    if (!rawNode) {
        return false;
    }

    handler.addToCallSiteObject(callSiteObj, rawNode, cookedNode);
    return true;
}

template <typename Unit>
CodeNode*
Parser<FullParseHandler, Unit>::standaloneLazyFunction(HandleFunction fun, uint32_t toStringStart,
                                                       bool strict, GeneratorKind generatorKind,
                                                       FunctionAsyncKind asyncKind)
{
    MOZ_ASSERT(checkOptionsCalled);

    CodeNodeType funNode = handler.newFunctionStatement(pos());
    if (!funNode) {
        return null();
    }

    Directives directives(strict);
    FunctionBox* funbox = newFunctionBox(funNode, fun, toStringStart, directives, generatorKind,
                                         asyncKind);
    if (!funbox) {
        return null();
    }
    funbox->initFromLazyFunction();

    Directives newDirectives = directives;
    SourceParseContext funpc(this, funbox, &newDirectives);
    if (!funpc.init()) {
        return null();
    }

    // Our tokenStream has no current token, so funNode's position is garbage.
    // Substitute the position of the first token in our source.  If the
    // function is a not-async arrow, use TokenStream::Operand to keep
    // verifyConsistentModifier from complaining (we will use
    // TokenStream::Operand in functionArguments).
    Modifier modifier = (fun->isArrow() && asyncKind == FunctionAsyncKind::SyncFunction)
                        ? TokenStream::Operand
                        : TokenStream::None;
    if (!tokenStream.peekTokenPos(&funNode->pn_pos, modifier)) {
        return null();
    }

    YieldHandling yieldHandling = GetYieldHandling(generatorKind);
    FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
    if (fun->isClassConstructor()) {
        syntaxKind = FunctionSyntaxKind::ClassConstructor;
    } else if (fun->isMethod()) {
        syntaxKind = FunctionSyntaxKind::Method;
    } else if (fun->isGetter()) {
        syntaxKind = FunctionSyntaxKind::Getter;
    } else if (fun->isSetter()) {
        syntaxKind = FunctionSyntaxKind::Setter;
    } else if (fun->isArrow()) {
        syntaxKind = FunctionSyntaxKind::Arrow;
    }

    if (!functionFormalParametersAndBody(InAllowed, yieldHandling, &funNode, syntaxKind)) {
        MOZ_ASSERT(directives == newDirectives);
        return null();
    }

    ParseNode* node = funNode;
    if (!FoldConstants(context, &node, this)) {
        return null();
    }
    funNode = &node->as<CodeNode>();

    return funNode;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::functionFormalParametersAndBody(InHandling inHandling,
                                                                   YieldHandling yieldHandling,
                                                                   CodeNodeType* funNode,
                                                                   FunctionSyntaxKind kind,
                                                                   const Maybe<uint32_t>& parameterListEnd /* = Nothing() */,
                                                                   bool isStandaloneFunction /* = false */)
{
    // Given a properly initialized parse context, try to parse an actual
    // function without concern for conversion to strict mode, use of lazy
    // parsing and such.

    FunctionBox* funbox = pc->functionBox();
    RootedFunction fun(context, funbox->function());

    // See below for an explanation why arrow function parameters and arrow
    // function bodies are parsed with different yield/await settings.
    {
        AwaitHandling awaitHandling =
            (funbox->isAsync() || (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
            ? AwaitIsKeyword
            : AwaitIsName;
        AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, awaitHandling);
        AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this, funbox->isAsync());
        if (!functionArguments(yieldHandling, kind, *funNode)) {
            return false;
        }
    }

    Maybe<ParseContext::VarScope> varScope;
    if (funbox->hasParameterExprs) {
        varScope.emplace(this);
        if (!varScope->init(pc)) {
            return false;
        }
    } else {
        pc->functionScope().useAsVarScope(pc);
    }

    if (kind == FunctionSyntaxKind::Arrow) {
        bool matched;
        if (!tokenStream.matchToken(&matched, TokenKind::Arrow)) {
            return false;
        }
        if (!matched) {
            error(JSMSG_BAD_ARROW_ARGS);
            return false;
        }
    }

    // When parsing something for new Function() we have to make sure to
    // only treat a certain part of the source as a parameter list.
    if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
        error(JSMSG_UNEXPECTED_PARAMLIST_END);
        return false;
    }

    // Parse the function body.
    FunctionBodyType bodyType = StatementListBody;
    TokenKind tt;
    if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
        return false;
    }
    uint32_t openedPos = 0;
    if (tt != TokenKind::LeftCurly) {
        if (kind != FunctionSyntaxKind::Arrow) {
            error(JSMSG_CURLY_BEFORE_BODY);
            return false;
        }

        anyChars.ungetToken();
        bodyType = ExpressionBody;
        funbox->setHasExprBody();
    } else {
        openedPos = pos().begin;
    }

    // Arrow function parameters inherit yieldHandling from the enclosing
    // context, but the arrow body doesn't. E.g. in |(a = yield) => yield|,
    // |yield| in the parameters is either a name or keyword, depending on
    // whether the arrow function is enclosed in a generator function or not.
    // Whereas the |yield| in the function body is always parsed as a name.
    // The same goes when parsing |await| in arrow functions.
    YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
    AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc->asyncKind());
    bool inheritedStrict = pc->sc()->strict();
    LexicalScopeNodeType body;
    {
        AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, bodyAwaitHandling);
        AutoInParametersOfAsyncFunction<ParseHandler, Unit> inParameters(this, false);
        body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
        if (!body) {
            return false;
        }
    }

    // Revalidate the function name when we transitioned to strict mode.
    if ((kind == FunctionSyntaxKind::Statement || kind == FunctionSyntaxKind::Expression) &&
        fun->explicitName() &&
        !inheritedStrict &&
        pc->sc()->strict())
    {
        MOZ_ASSERT(pc->sc()->hasExplicitUseStrict(),
                   "strict mode should only change when a 'use strict' directive is present");

        PropertyName* propertyName = fun->explicitName()->asPropertyName();
        YieldHandling nameYieldHandling;
        if (kind == FunctionSyntaxKind::Expression) {
            // Named lambda has binding inside it.
            nameYieldHandling = bodyYieldHandling;
        } else {
            // Otherwise YieldHandling cannot be checked at this point
            // because of different context.
            // It should already be checked before this point.
            nameYieldHandling = YieldIsName;
        }

        // We already use the correct await-handling at this point, therefore
        // we don't need call AutoAwaitIsKeyword here.

        uint32_t nameOffset = handler.getFunctionNameOffset(*funNode, anyChars);
        if (!checkBindingIdentifier(propertyName, nameOffset, nameYieldHandling)) {
            return false;
        }
    }

    if (bodyType == StatementListBody) {
        MUST_MATCH_TOKEN_MOD_WITH_REPORT_OR(TokenKind::RightCurly, TokenStream::Operand,
                                            reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
                                                                 JSMSG_CURLY_OPENED, openedPos),
                                            false);
        funbox->setEnd(anyChars);
    } else {
        MOZ_ASSERT(kind == FunctionSyntaxKind::Arrow);

        if (anyChars.hadError()) {
            return false;
        }
        funbox->setEnd(anyChars);
        if (kind == FunctionSyntaxKind::Statement && !matchOrInsertSemicolon()) {
            return false;
        }
    }

    if (IsMethodDefinitionKind(kind) && pc->superScopeNeedsHomeObject()) {
        funbox->setNeedsHomeObject();
    }

    if (!finishFunction(isStandaloneFunction)) {
        return false;
    }

    handler.setEndPosition(body, pos().begin);
    handler.setEndPosition(*funNode, pos().end);
    handler.setFunctionBody(*funNode, body);

    return true;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::CodeNodeType
GeneralParser<ParseHandler, Unit>::functionStmt(uint32_t toStringStart,
                                                YieldHandling yieldHandling,
                                                DefaultHandling defaultHandling,
                                                FunctionAsyncKind asyncKind)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));

    // In sloppy mode, Annex B.3.2 allows labelled function declarations.
    // Otherwise it's a parse error.
    ParseContext::Statement* declaredInStmt = pc->innermostStatement();
    if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
        MOZ_ASSERT(!pc->sc()->strict(),
                   "labeled functions shouldn't be parsed in strict mode");

        // Find the innermost non-label statement.  Report an error if it's
        // unbraced: functions can't appear in it.  Otherwise the statement
        // (or its absence) determines the scope the function's bound in.
        while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
            declaredInStmt = declaredInStmt->enclosing();
        }

        if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
            error(JSMSG_SLOPPY_FUNCTION_LABEL);
            return null();
        }
    }

    TokenKind tt;
    if (!tokenStream.getToken(&tt)) {
        return null();
    }

    GeneratorKind generatorKind = GeneratorKind::NotGenerator;
    if (tt == TokenKind::Mul) {
        generatorKind = GeneratorKind::Generator;
        if (!tokenStream.getToken(&tt)) {
            return null();
        }
    }

    RootedPropertyName name(context);
    if (TokenKindIsPossibleIdentifier(tt)) {
        name = bindingIdentifier(yieldHandling);
        if (!name) {
            return null();
        }
    } else if (defaultHandling == AllowDefaultName) {
        name = context->names().default_;
        anyChars.ungetToken();
    } else {
        /* Unnamed function expressions are forbidden in statement context. */
        error(JSMSG_UNNAMED_FUNCTION_STMT);
        return null();
    }

    // Note the declared name and check for early errors.
    DeclarationKind kind;
    if (declaredInStmt) {
        MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
        MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));

        kind = (!pc->sc()->strict() &&
                generatorKind == GeneratorKind::NotGenerator &&
                asyncKind == FunctionAsyncKind::SyncFunction)
                ? DeclarationKind::SloppyLexicalFunction
                : DeclarationKind::LexicalFunction;
    } else {
        kind = pc->atModuleLevel()
               ? DeclarationKind::ModuleBodyLevelFunction
               : DeclarationKind::BodyLevelFunction;
    }

    if (!noteDeclaredName(name, kind, pos())) {
        return null();
    }

    CodeNodeType funNode = handler.newFunctionStatement(pos());
    if (!funNode) {
        return null();
    }

    // Under sloppy mode, try Annex B.3.3 semantics. If making an additional
    // 'var' binding of the same name does not throw an early error, do so.
    // This 'var' binding would be assigned the function object when its
    // declaration is reached, not at the start of the block.
    //
    // This semantics is implemented upon Scope exit in
    // Scope::propagateAndMarkAnnexBFunctionBoxes.
    bool tryAnnexB = kind == DeclarationKind::SloppyLexicalFunction;

    YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
    return functionDefinition(funNode, toStringStart, InAllowed, newYieldHandling, name,
                              FunctionSyntaxKind::Statement, generatorKind, asyncKind, tryAnnexB);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::CodeNodeType
GeneralParser<ParseHandler, Unit>::functionExpr(uint32_t toStringStart, InvokedPrediction invoked,
                                                FunctionAsyncKind asyncKind)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Function));

    AutoAwaitIsKeyword<ParseHandler, Unit> awaitIsKeyword(this, GetAwaitHandling(asyncKind));
    GeneratorKind generatorKind = GeneratorKind::NotGenerator;
    TokenKind tt;
    if (!tokenStream.getToken(&tt)) {
        return null();
    }

    if (tt == TokenKind::Mul) {
        generatorKind = GeneratorKind::Generator;
        if (!tokenStream.getToken(&tt)) {
            return null();
        }
    }

    YieldHandling yieldHandling = GetYieldHandling(generatorKind);

    RootedPropertyName name(context);
    if (TokenKindIsPossibleIdentifier(tt)) {
        name = bindingIdentifier(yieldHandling);
        if (!name) {
            return null();
        }
    } else {
        anyChars.ungetToken();
    }

    CodeNodeType funNode = handler.newFunctionExpression(pos());
    if (!funNode) {
        return null();
    }

    if (invoked) {
        funNode = handler.setLikelyIIFE(funNode);
    }

    return functionDefinition(funNode, toStringStart, InAllowed, yieldHandling, name,
                              FunctionSyntaxKind::Expression, generatorKind, asyncKind);
}

/*
 * Return true if this node, known to be an unparenthesized string literal,
 * could be the string of a directive in a Directive Prologue. Directive
 * strings never contain escape sequences or line continuations.
 * isEscapeFreeStringLiteral, below, checks whether the node itself could be
 * a directive.
 */
static inline bool
IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str)
{
    /*
     * If the string's length in the source code is its length as a value,
     * accounting for the quotes, then it must not contain any escape
     * sequences or line continuations.
     */
    return pos.begin + str->length() + 2 == pos.end;
}

template <typename Unit>
bool
Parser<SyntaxParseHandler, Unit>::asmJS(ListNodeType list)
{
    // While asm.js could technically be validated and compiled during syntax
    // parsing, we have no guarantee that some later JS wouldn't abort the
    // syntax parse and cause us to re-parse (and re-compile) the asm.js module.
    // For simplicity, unconditionally abort the syntax parse when "use asm" is
    // encountered so that asm.js is always validated/compiled exactly once
    // during a full parse.
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());

    // Record that the current script source constains some AsmJS, to disable
    // any incremental encoder, as AsmJS cannot be encoded with XDR at the
    // moment.
    if (ss) {
        ss->setContainsAsmJS();
    }
    return false;
}

template <>
bool
Parser<FullParseHandler, char16_t>::asmJS(ListNodeType list)
{
    // Disable syntax parsing in anything nested inside the asm.js module.
    disableSyntaxParser();

    // We should be encountering the "use asm" directive for the first time; if
    // the directive is already, we must have failed asm.js validation and we're
    // reparsing. In that case, don't try to validate again. A non-null
    // newDirectives means we're not in a normal function.
    if (!pc->newDirectives || pc->newDirectives->asmJS()) {
        return true;
    }

    // If there is no ScriptSource, then we are doing a non-compiling parse and
    // so we shouldn't (and can't, without a ScriptSource) compile.
    if (ss == nullptr) {
        return true;
    }

    ss->setContainsAsmJS();
    pc->functionBox()->useAsm = true;

    // Attempt to validate and compile this asm.js module. On success, the
    // tokenStream has been advanced to the closing }. On failure, the
    // tokenStream is in an indeterminate state and we must reparse the
    // function from the beginning. Reparsing is triggered by marking that a
    // new directive has been encountered and returning 'false'.
    bool validated;
    if (!CompileAsmJS(context, *this, list, &validated)) {
        return false;
    }
    if (!validated) {
        pc->newDirectives->setAsmJS();
        return false;
    }

    return true;
}

template <>
bool
Parser<FullParseHandler, Utf8Unit>::asmJS(ListNodeType list)
{
    // Just succeed without setting the asm.js directive flag.  Given Web
    // Assembly's rapid advance, it's probably not worth the trouble to really
    // support UTF-8 asm.js.
    return true;
}

template <class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::asmJS(ListNodeType list)
{
    return asFinalParser()->asmJS(list);
}

/*
 * Recognize Directive Prologue members and directives. Assuming |pn| is a
 * candidate for membership in a directive prologue, recognize directives and
 * set |pc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
 * |prologue| flag.
 *
 * Note that the following is a strict mode function:
 *
 * function foo() {
 *   "blah" // inserted semi colon
 *        "blurgh"
 *   "use\x20loose"
 *   "use strict"
 * }
 *
 * That is, even though "use\x20loose" can never be a directive, now or in the
 * future (because of the hex escape), the Directive Prologue extends through it
 * to the "use strict" statement, which is indeed a directive.
 */
template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::maybeParseDirective(ListNodeType list, Node possibleDirective,
                                                       bool* cont)
{
    TokenPos directivePos;
    JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos);

    *cont = !!directive;
    if (!*cont) {
        return true;
    }

    if (IsEscapeFreeStringLiteral(directivePos, directive)) {
        // Mark this statement as being a possibly legitimate part of a
        // directive prologue, so the bytecode emitter won't warn about it being
        // useless code. (We mustn't just omit the statement entirely yet, as it
        // could be producing the value of an eval or JSScript execution.)
        //
        // Note that even if the string isn't one we recognize as a directive,
        // the emitter still shouldn't flag it as useless, as it could become a
        // directive in the future. We don't want to interfere with people
        // taking advantage of directive-prologue-enabled features that appear
        // in other browsers first.
        handler.setInDirectivePrologue(handler.asUnary(possibleDirective));

        if (directive == context->names().useStrict) {
            // Functions with non-simple parameter lists (destructuring,
            // default or rest parameters) must not contain a "use strict"
            // directive.
            if (pc->isFunctionBox()) {
                FunctionBox* funbox = pc->functionBox();
                if (!funbox->hasSimpleParameterList()) {
                    const char* parameterKind = funbox->hasDestructuringArgs
                                                ? "destructuring"
                                                : funbox->hasParameterExprs
                                                ? "default"
                                                : "rest";
                    errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind);
                    return false;
                }
            }

            // We're going to be in strict mode. Note that this scope explicitly
            // had "use strict";
            pc->sc()->setExplicitUseStrict();
            if (!pc->sc()->strict()) {
                // We keep track of the one possible strict violation that could
                // occur in the directive prologue -- octal escapes -- and
                // complain now.
                if (anyChars.sawOctalEscape()) {
                    error(JSMSG_DEPRECATED_OCTAL);
                    return false;
                }
                pc->sc()->strictScript = true;
            }
        } else if (directive == context->names().useAsm) {
            if (pc->isFunctionBox()) {
                return asmJS(list);
            }
            return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
        }
    }
    return true;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::statementList(YieldHandling yieldHandling)
{
    if (!CheckRecursionLimit(context)) {
        return null();
    }

    ListNodeType stmtList = handler.newStatementList(pos());
    if (!stmtList) {
        return null();
    }

    bool canHaveDirectives = pc->atBodyLevel();
    if (canHaveDirectives) {
        anyChars.clearSawOctalEscape();
    }
    bool afterReturn = false;
    bool warnedAboutStatementsAfterReturn = false;
    uint32_t statementBegin = 0;
    for (;;) {
        TokenKind tt = TokenKind::Eof;
        if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
            if (anyChars.isEOF()) {
                isUnexpectedEOF_ = true;
            }
            return null();
        }
        if (tt == TokenKind::Eof || tt == TokenKind::RightCurly) {
            TokenPos pos;
            if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) {
                return null();
            }
            handler.setListEndPosition(stmtList, pos);
            break;
        }
        if (afterReturn) {
            if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand)) {
                return null();
            }
        }
        Node next = statementListItem(yieldHandling, canHaveDirectives);
        if (!next) {
            if (anyChars.isEOF()) {
                isUnexpectedEOF_ = true;
            }
            return null();
        }
        if (!warnedAboutStatementsAfterReturn) {
            if (afterReturn) {
                if (!handler.isStatementPermittedAfterReturnStatement(next)) {
                    if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN)) {
                        return null();
                    }

                    warnedAboutStatementsAfterReturn = true;
                }
            } else if (handler.isReturnStatement(next)) {
                afterReturn = true;
            }
        }

        if (canHaveDirectives) {
            if (!maybeParseDirective(stmtList, next, &canHaveDirectives)) {
                return null();
            }
        }

        handler.addStatementToList(stmtList, next);
    }

    return stmtList;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::condition(InHandling inHandling, YieldHandling yieldHandling)
{
    MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_COND);

    Node pn = exprInParens(inHandling, yieldHandling, TripledotProhibited);
    if (!pn) {
        return null();
    }

    MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_COND);

    /* Check for (a = b) and warn about possible (a == b) mistype. */
    if (handler.isUnparenthesizedAssignment(pn)) {
        if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN)) {
            return null();
        }
    }
    return pn;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::matchLabel(YieldHandling yieldHandling,
                                              MutableHandle<PropertyName*> label)
{
    TokenKind tt = TokenKind::Eof;
    if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) {
        return false;
    }

    if (TokenKindIsPossibleIdentifier(tt)) {
        tokenStream.consumeKnownToken(tt, TokenStream::Operand);

        label.set(labelIdentifier(yieldHandling));
        if (!label) {
            return false;
        }
    } else {
        label.set(nullptr);
    }
    return true;
}

template <class ParseHandler, typename Unit>
GeneralParser<ParseHandler, Unit>::PossibleError::PossibleError(GeneralParser<ParseHandler, Unit>& parser)
  : parser_(parser)
{}

template <class ParseHandler, typename Unit>
typename GeneralParser<ParseHandler, Unit>::PossibleError::Error&
GeneralParser<ParseHandler, Unit>::PossibleError::error(ErrorKind kind)
{
    if (kind == ErrorKind::Expression) {
        return exprError_;
    }
    if (kind == ErrorKind::Destructuring) {
        return destructuringError_;
    }
    MOZ_ASSERT(kind == ErrorKind::DestructuringWarning);
    return destructuringWarning_;
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::setResolved(ErrorKind kind)
{
    error(kind).state_ = ErrorState::None;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::hasError(ErrorKind kind)
{
    return error(kind).state_ == ErrorState::Pending;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::hasPendingDestructuringError()
{
    return hasError(ErrorKind::Destructuring);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::setPending(ErrorKind kind, const TokenPos& pos,
                                                             unsigned errorNumber)
{
    // Don't overwrite a previously recorded error.
    if (hasError(kind)) {
        return;
    }

    // If we report an error later, we'll do it from the position where we set
    // the state to pending.
    Error& err = error(kind);
    err.offset_ = pos.begin;
    err.errorNumber_ = errorNumber;
    err.state_ = ErrorState::Pending;
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos,
                                                                                 unsigned errorNumber)
{
    setPending(ErrorKind::Destructuring, pos, errorNumber);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos,
                                                                                   unsigned errorNumber)
{
    setPending(ErrorKind::DestructuringWarning, pos, errorNumber);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
                                                                              unsigned errorNumber)
{
    setPending(ErrorKind::Expression, pos, errorNumber);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::checkForError(ErrorKind kind)
{
    if (!hasError(kind)) {
        return true;
    }

    Error& err = error(kind);
    parser_.errorAt(err.offset_, err.errorNumber_);
    return false;
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::checkForWarning(ErrorKind kind)
{
    if (!hasError(kind)) {
        return true;
    }

    Error& err = error(kind);
    return parser_.extraWarningAt(err.offset_, err.errorNumber_);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::checkForDestructuringErrorOrWarning()
{
    // Clear pending expression error, because we're definitely not in an
    // expression context.
    setResolved(ErrorKind::Expression);

    // Report any pending destructuring error or warning.
    return checkForError(ErrorKind::Destructuring) &&
           checkForWarning(ErrorKind::DestructuringWarning);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::PossibleError::checkForExpressionError()
{
    // Clear pending destructuring error or warning, because we're definitely
    // not in a destructuring context.
    setResolved(ErrorKind::Destructuring);
    setResolved(ErrorKind::DestructuringWarning);

    // Report any pending expression error.
    return checkForError(ErrorKind::Expression);
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorTo(ErrorKind kind,
                                                                  PossibleError* other)
{
    if (hasError(kind) && !other->hasError(kind)) {
        Error& err = error(kind);
        Error& otherErr = other->error(kind);
        otherErr.offset_ = err.offset_;
        otherErr.errorNumber_ = err.errorNumber_;
        otherErr.state_ = err.state_;
    }
}

template <class ParseHandler, typename Unit>
void
GeneralParser<ParseHandler, Unit>::PossibleError::transferErrorsTo(PossibleError* other)
{
    MOZ_ASSERT(other);
    MOZ_ASSERT(this != other);
    MOZ_ASSERT(&parser_ == &other->parser_,
               "Can't transfer fields to an instance which belongs to a different parser");

    transferErrorTo(ErrorKind::Destructuring, other);
    transferErrorTo(ErrorKind::Expression, other);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::bindingInitializer(Node lhs, DeclarationKind kind,
                                                      YieldHandling yieldHandling)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));

    if (kind == DeclarationKind::FormalParameter) {
        pc->functionBox()->hasParameterExprs = true;
    }

    Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
    if (!rhs) {
        return null();
    }

    BinaryNodeType assign = handler.newAssignment(ParseNodeKind::Assign, lhs, rhs);
    if (!assign) {
        return null();
    }

    if (foldConstants) {
        Node node = assign;
        if (!FoldConstants(context, &node, this)) {
            return null();
        }
        assign = handler.asBinary(node);
    }

    return assign;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::NameNodeType
GeneralParser<ParseHandler, Unit>::bindingIdentifier(DeclarationKind kind,
                                                     YieldHandling yieldHandling)
{
    RootedPropertyName name(context, bindingIdentifier(yieldHandling));
    if (!name) {
        return null();
    }

    NameNodeType binding = newName(name);
    if (!binding || !noteDeclaredName(name, kind, pos())) {
        return null();
    }

    return binding;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::bindingIdentifierOrPattern(DeclarationKind kind,
                                                              YieldHandling yieldHandling,
                                                              TokenKind tt)
{
    if (tt == TokenKind::LeftBracket) {
        return arrayBindingPattern(kind, yieldHandling);
    }

    if (tt == TokenKind::LeftCurly) {
        return objectBindingPattern(kind, yieldHandling);
    }

    if (!TokenKindIsPossibleIdentifierName(tt)) {
        error(JSMSG_NO_VARIABLE_NAME);
        return null();
    }

    return bindingIdentifier(kind, yieldHandling);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::objectBindingPattern(DeclarationKind kind,
                                                        YieldHandling yieldHandling)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));

    if (!CheckRecursionLimit(context)) {
        return null();
    }

    uint32_t begin = pos().begin;
    ListNodeType literal = handler.newObjectLiteral(begin);
    if (!literal) {
        return null();
    }

    Maybe<DeclarationKind> declKind = Some(kind);
    RootedAtom propAtom(context);
    for (;;) {
        TokenKind tt;
        if (!tokenStream.peekToken(&tt)) {
            return null();
        }
        if (tt == TokenKind::RightCurly) {
            anyChars.addModifierException(TokenStream::OperandIsNone);
            break;
        }

        if (tt == TokenKind::TripleDot) {
            tokenStream.consumeKnownToken(TokenKind::TripleDot);
            uint32_t begin = pos().begin;

            TokenKind tt;
            if (!tokenStream.getToken(&tt)) {
                return null();
            }

            if (!TokenKindIsPossibleIdentifierName(tt)) {
                error(JSMSG_NO_VARIABLE_NAME);
                return null();
            }

            NameNodeType inner = bindingIdentifier(kind, yieldHandling);
            if (!inner) {
                return null();
            }

            if (!handler.addSpreadProperty(literal, begin, inner)) {
                return null();
            }
        } else {
            TokenPos namePos = anyChars.nextToken().pos;

            PropertyType propType;
            Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
            if (!propName) {
                return null();
            }

            if (propType == PropertyType::Normal) {
                // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.

                if (!tokenStream.getToken(&tt, TokenStream::Operand)) {
                    return null();
                }

                Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
                if (!binding) {
                    return null();
                }

                bool hasInitializer;
                if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign, TokenStream::Operand)) {
                    return null();
                }

                Node bindingExpr = hasInitializer
                                   ? bindingInitializer(binding, kind, yieldHandling)
                                   : binding;
                if (!bindingExpr) {
                    return null();
                }

                if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) {
                    return null();
                }
            } else if (propType == PropertyType::Shorthand) {
                // Handle e.g., |var {x, y} = o| as destructuring shorthand
                // for |var {x: x, y: y} = o|.
                MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));

                NameNodeType binding = bindingIdentifier(kind, yieldHandling);
                if (!binding) {
                    return null();
                }

                if (!handler.addShorthand(literal, handler.asName(propName), binding)) {
                    return null();
                }
            } else if (propType == PropertyType::CoverInitializedName) {
                // Handle e.g., |var {x=1, y=2} = o| as destructuring
                // shorthand with default values.
                MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));

                NameNodeType binding = bindingIdentifier(kind, yieldHandling);
                if (!binding) {
                    return null();
                }

                tokenStream.consumeKnownToken(TokenKind::Assign);

                BinaryNodeType bindingExpr = bindingInitializer(binding, kind, yieldHandling);
                if (!bindingExpr) {
                    return null();
                }

                if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) {
                    return null();
                }
            } else {
                errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME);
                return null();
            }
        }

        bool matched;
        if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand)) {
            return null();
        }
        if (!matched) {
            break;
        }
        if (tt == TokenKind::TripleDot) {
            error(JSMSG_REST_WITH_COMMA);
            return null();
        }
    }

    MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
                                     reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
                                                          JSMSG_CURLY_OPENED, begin));

    handler.setEndPosition(literal, pos().end);
    return literal;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::arrayBindingPattern(DeclarationKind kind,
                                                       YieldHandling yieldHandling)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));

    if (!CheckRecursionLimit(context)) {
        return null();
    }

    uint32_t begin = pos().begin;
    ListNodeType literal = handler.newArrayLiteral(begin);
    if (!literal) {
        return null();
    }

     uint32_t index = 0;
     for (; ; index++) {
         if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
             error(JSMSG_ARRAY_INIT_TOO_BIG);
             return null();
         }

         TokenKind tt;
         if (!tokenStream.getToken(&tt)) {
             return null();
         }

         if (tt == TokenKind::RightBracket) {
             anyChars.ungetToken();
             anyChars.addModifierException(TokenStream::OperandIsNone);
             break;
         }

         if (tt == TokenKind::Comma) {
             if (!handler.addElision(literal, pos())) {
                 return null();
             }
         } else if (tt == TokenKind::TripleDot) {
             uint32_t begin = pos().begin;

             TokenKind tt;
             if (!tokenStream.getToken(&tt)) {
                 return null();
             }

             Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt);
             if (!inner) {
                 return null();
             }

             if (!handler.addSpreadElement(literal, begin, inner)) {
                 return null();
             }
         } else {
             Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
             if (!binding) {
                 return null();
             }

             bool hasInitializer;
             if (!tokenStream.matchToken(&hasInitializer, TokenKind::Assign, TokenStream::Operand)) {
                 return null();
             }

             Node element = hasInitializer
                            ? bindingInitializer(binding, kind, yieldHandling)
                            : binding;
             if (!element) {
                 return null();
             }

             handler.addArrayElement(literal, element);
         }

         if (tt != TokenKind::Comma) {
             // If we didn't already match TokenKind::Comma in above case.
             bool matched;
             if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand)) {
                 return null();
             }
             if (!matched) {
                 break;
             }

             if (tt == TokenKind::TripleDot) {
                 error(JSMSG_REST_WITH_COMMA);
                 return null();
             }
         }
     }

     MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightBracket, TokenStream::Operand,
                                      reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
                                                           JSMSG_BRACKET_OPENED, begin));

    handler.setEndPosition(literal, pos().end);
    return literal;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::destructuringDeclaration(DeclarationKind kind,
                                                            YieldHandling yieldHandling,
                                                            TokenKind tt)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
    MOZ_ASSERT(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly);

    return tt == TokenKind::LeftBracket
           ? arrayBindingPattern(kind, yieldHandling)
           : objectBindingPattern(kind, yieldHandling);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind,
                                                                               YieldHandling yieldHandling,
                                                                               TokenKind tt)
{
    uint32_t startYieldOffset = pc->lastYieldOffset;
    uint32_t startAwaitOffset = pc->lastAwaitOffset;
    Node res = destructuringDeclaration(kind, yieldHandling, tt);
    if (res) {
        if (pc->lastYieldOffset != startYieldOffset) {
            errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_PARAMETER);
            return null();
        }
        if (pc->lastAwaitOffset != startAwaitOffset) {
            errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_PARAMETER);
            return null();
        }
    }
    return res;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::LexicalScopeNodeType
GeneralParser<ParseHandler, Unit>::blockStatement(YieldHandling yieldHandling,
                                                  unsigned errorNumber)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
    uint32_t openedPos = pos().begin;

    ParseContext::Statement stmt(pc, StatementKind::Block);
    ParseContext::Scope scope(this);
    if (!scope.init(pc)) {
        return null();
    }

    ListNodeType list = statementList(yieldHandling);
    if (!list) {
        return null();
    }

    MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
                                     reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
                                                          openedPos));

    return finishLexicalScope(scope, list);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::expressionAfterForInOrOf(ParseNodeKind forHeadKind,
                                                            YieldHandling yieldHandling)
{
    MOZ_ASSERT(forHeadKind == ParseNodeKind::ForIn || forHeadKind == ParseNodeKind::ForOf);
    Node pn = forHeadKind == ParseNodeKind::ForOf
           ? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
           : expr(InAllowed, yieldHandling, TripledotProhibited);
    return pn;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::declarationPattern(DeclarationKind declKind, TokenKind tt,
                                                      bool initialDeclaration,
                                                      YieldHandling yieldHandling,
                                                      ParseNodeKind* forHeadKind,
                                                      Node* forInOrOfExpression)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket) ||
               anyChars.isCurrentTokenType(TokenKind::LeftCurly));

    Node pattern = destructuringDeclaration(declKind, yieldHandling, tt);
    if (!pattern) {
        return null();
    }

    if (initialDeclaration && forHeadKind) {
        bool isForIn, isForOf;
        if (!matchInOrOf(&isForIn, &isForOf)) {
            return null();
        }

        if (isForIn) {
            *forHeadKind = ParseNodeKind::ForIn;
        } else if (isForOf) {
            *forHeadKind = ParseNodeKind::ForOf;

            // Annex B.3.5 has different early errors for vars in for-of loops.
            if (declKind == DeclarationKind::Var) {
                declKind = DeclarationKind::ForOfVar;
            }
        } else {
            *forHeadKind = ParseNodeKind::ForHead;
        }

        if (*forHeadKind != ParseNodeKind::ForHead) {
            *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
            if (!*forInOrOfExpression) {
                return null();
            }

            return pattern;
        }
    }

    MUST_MATCH_TOKEN_MOD(TokenKind::Assign, TokenStream::Operand, JSMSG_BAD_DESTRUCT_DECL);

    Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
                           yieldHandling, TripledotProhibited);
    if (!init) {
        return null();
    }

    return handler.newAssignment(ParseNodeKind::Assign, pattern, init);
}

template <class ParseHandler, typename Unit>
bool
GeneralParser<ParseHandler, Unit>::initializerInNameDeclaration(NameNodeType binding,
                                                                DeclarationKind declKind,
                                                                bool initialDeclaration,
                                                                YieldHandling yieldHandling,
                                                                ParseNodeKind* forHeadKind,
                                                                Node* forInOrOfExpression)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Assign));

    uint32_t initializerOffset;
    if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand)) {
        return false;
    }

    Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
                                  yieldHandling, TripledotProhibited);
    if (!initializer) {
        return false;
    }

    if (forHeadKind && initialDeclaration) {
        bool isForIn, isForOf;
        if (!matchInOrOf(&isForIn, &isForOf)) {
            return false;
        }

        // An initialized declaration can't appear in a for-of:
        //
        //   for (var/let/const x = ... of ...); // BAD
        if (isForOf) {
            errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
            return false;
        }

        if (isForIn) {
            // Lexical declarations in for-in loops can't be initialized:
            //
            //   for (let/const x = ... in ...); // BAD
            if (DeclarationKindIsLexical(declKind)) {
                errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
                return false;
            }

            // This leaves only initialized for-in |var| declarations.  ES6
            // forbids these; later ES un-forbids in non-strict mode code.
            *forHeadKind = ParseNodeKind::ForIn;
            if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT)) {
                return false;
            }

            *forInOrOfExpression = expressionAfterForInOrOf(ParseNodeKind::ForIn, yieldHandling);
            if (!*forInOrOfExpression) {
                return false;
            }
        } else {
            *forHeadKind = ParseNodeKind::ForHead;
        }
    }

    return handler.finishInitializerAssignment(binding, initializer);
}

template <class ParseHandler, typename Unit>
typename ParseHandler::NameNodeType
GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind, TokenKind tt,
                                                   bool initialDeclaration,
                                                   YieldHandling yieldHandling,
                                                   ParseNodeKind* forHeadKind,
                                                   Node* forInOrOfExpression)
{
    // Anything other than possible identifier is an error.
    if (!TokenKindIsPossibleIdentifier(tt)) {
        error(JSMSG_NO_VARIABLE_NAME);
        return null();
    }

    RootedPropertyName name(context, bindingIdentifier(yieldHandling));
    if (!name) {
        return null();
    }

    NameNodeType binding = newName(name);
    if (!binding) {
        return null();
    }

    TokenPos namePos = pos();

    // The '=' context after a variable name in a declaration is an opportunity
    // for ASI, and thus for the next token to start an ExpressionStatement:
    //
    //  var foo   // VariableDeclaration
    //  /bar/g;   // ExpressionStatement
    //
    // Therefore get the token here as Operand.
    bool matched;
    if (!tokenStream.matchToken(&matched, TokenKind::Assign, TokenStream::Operand)) {
        return null();
    }

    if (matched) {
        if (!initializerInNameDeclaration(binding, declKind, initialDeclaration,
                                          yieldHandling, forHeadKind, forInOrOfExpression))
        {
            return null();
        }
    } else {
        if (initialDeclaration && forHeadKind) {
            bool isForIn, isForOf;
            if (!matchInOrOf(&isForIn, &isForOf)) {
                return null();
            }

            if (isForIn) {
                *forHeadKind = ParseNodeKind::ForIn;
            } else if (isForOf) {
                *forHeadKind = ParseNodeKind::ForOf;

                // Annex B.3.5 has different early errors for vars in for-of loops.
                if (declKind == DeclarationKind::Var) {
                    declKind = DeclarationKind::ForOfVar;
                }
            } else {
                *forHeadKind = ParseNodeKind::ForHead;
            }
        }

        if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
            *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
            if (!*forInOrOfExpression) {
                return null();
            }
        } else {
            // Normal const declarations, and const declarations in for(;;)
            // heads, must be initialized.
            if (declKind == DeclarationKind::Const) {
                errorAt(namePos.begin, JSMSG_BAD_CONST_DECL);
                return null();
            }
        }
    }

    // Note the declared name after knowing whether or not we are in a for-of
    // loop, due to special early error semantics in Annex B.3.5.
    if (!noteDeclaredName(name, declKind, namePos)) {
        return null();
    }

    return binding;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::declarationList(YieldHandling yieldHandling,
                                                   ParseNodeKind kind,
                                                   ParseNodeKind* forHeadKind /* = nullptr */,
                                                   Node* forInOrOfExpression /* = nullptr */)
{
    MOZ_ASSERT(kind == ParseNodeKind::Var ||
               kind == ParseNodeKind::Let ||
               kind == ParseNodeKind::Const);

    DeclarationKind declKind;
    switch (kind) {
      case ParseNodeKind::Var:
        declKind = DeclarationKind::Var;
        break;
      case ParseNodeKind::Const:
        declKind = DeclarationKind::Const;
        break;
      case ParseNodeKind::Let:
        declKind = DeclarationKind::Let;
        break;
      default:
        MOZ_CRASH("Unknown declaration kind");
    }

    ListNodeType decl = handler.newDeclarationList(kind, pos());
    if (!decl) {
        return null();
    }

    bool moreDeclarations;
    bool initialDeclaration = true;
    do {
        MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
                      *forHeadKind == ParseNodeKind::ForHead);

        TokenKind tt;
        if (!tokenStream.getToken(&tt)) {
            return null();
        }

        Node binding = (tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly)
                       ? declarationPattern(declKind, tt, initialDeclaration, yieldHandling,
                                            forHeadKind, forInOrOfExpression)
                       : declarationName(declKind, tt, initialDeclaration, yieldHandling,
                                         forHeadKind, forInOrOfExpression);
        if (!binding) {
            return null();
        }

        handler.addList(decl, binding);

        // If we have a for-in/of loop, the above call matches the entirety
        // of the loop head (up to the closing parenthesis).
        if (forHeadKind && *forHeadKind != ParseNodeKind::ForHead) {
            break;
        }

        initialDeclaration = false;

        if (!tokenStream.matchToken(&moreDeclarations, TokenKind::Comma, TokenStream::Operand)) {
            return null();
        }
    } while (moreDeclarations);

    return decl;
}

template <class ParseHandler, typename Unit>
typename ParseHandler::ListNodeType
GeneralParser<ParseHandler, Unit>::lexicalDeclaration(YieldHandling yieldHandling,
                                                      DeclarationKind kind)
{
    MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);

    /*
     * Parse body-level lets without a new block object. ES6 specs
     * that an execution environment's initial lexical environment
     * is the VariableEnvironment, i.e., body-level lets are in
     * the same environment record as vars.
     *
     * However, they cannot be parsed exactly as vars, as ES6
     * requires that uninitialized lets throw ReferenceError on use.
     *
     * See 8.1.1.1.6 and the note in 13.2.1.
     */
    ListNodeType decl = declarationList(yieldHandling,
                                        kind == DeclarationKind::Const
                                        ? ParseNodeKind::Const
                                        : ParseNodeKind::Let);
    if (!decl || !matchOrInsertSemicolon()) {
        return null();
    }

    return decl;
}

template <typename Unit>
bool
Parser<FullParseHandler, Unit>::namedImportsOrNamespaceImport(TokenKind tt,
                                                              ListNodeType importSpecSet)
{
    if (tt == TokenKind::LeftCurly) {
        while (true) {
            // Handle the forms |import {} from 'a'| and
            // |import { ..., } from 'a'| (where ... is non empty), by
            // escaping the loop early if the next token is }.
            if (!tokenStream.getToken(&tt)) {
                return false;
            }

            if (tt == TokenKind::RightCurly) {
                break;
            }

            if (!TokenKindIsPossibleIdentifierName(tt)) {
                error(JSMSG_NO_IMPORT_NAME);
                return false;
            }

            Rooted<PropertyName*> importName(context, anyChars.currentName());
            TokenPos importNamePos = pos();

            bool matched;
            if (!tokenStream.matchToken(&matched, TokenKind::As)) {
                return false;
            }

            if (matched) {
                TokenKind afterAs;
                if (!tokenStream.getToken(&afterAs)) {
                    return false;
                }

                if (!TokenKindIsPossibleIdentifierName(afterAs)) {
                    error(JSMSG_NO_BINDING_NAME);
                    return false;
                }
            } else {
                // Keywords cannot be bound to themselves, so an import name
                // that is a keyword is a syntax error if it is not followed
                // by the keyword 'as'.
                // See the ImportSpecifier production in ES6 section 15.2.2.
                if (IsKeyword(importName)) {
                    error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName));
                    return false;
                }
            }

            RootedPropertyName bindingAtom(context, importedBinding());
            if (!bindingAtom) {
                return false;
            }

            NameNodeType bindingName = newName(bindingAtom);
            if (!bindingName) {
                return false;
            }
            if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
                return false;
            }

            NameNodeType importNameNode = newName(importName, importNamePos);
            if (!importNameNode) {
                return false;
            }

            BinaryNodeType importSpec = handler.newImportSpec(importNameNode, bindingName);
            if (!importSpec) {
                return false;
            }

            handler.addList(importSpecSet, importSpec);

            TokenKind next;
            if (!tokenStream.getToken(&next)) {
                return false;
            }

            if (next == TokenKind::RightCurly) {
                break;
            }

            if (next != TokenKind::Comma) {
                error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
                return false;
            }
        }
    } else {
        MOZ_ASSERT(tt == TokenKind::Mul);

        MUST_MATCH_TOKEN_OR(TokenKind::As, JSMSG_AS_AFTER_IMPORT_STAR, false);

        MUST_MATCH_TOKEN_FUNC_OR(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME, false);

        NameNodeType importName = newName(context->names().star);
        if (!importName) {
            return false;
        }

        // Namespace imports are are not indirect bindings but lexical
        // definitions that hold a module namespace object. They are treated
        // as const variables which are initialized during the
        // ModuleInstantiate step.
        RootedPropertyName bindingName(context, importedBinding());
        if (!bindingName) {
            return false;
        }
        NameNodeType bindingNameNode = newName(bindingName);
        if (!bindingNameNode) {
            return false;
        }
        if (!noteDeclaredName(bindingName, DeclarationKind::Const, pos())) {
            return false;
        }

        // The namespace import name is currently required to live on the
        // environment.
        pc->varScope().lookupDeclaredName(bindingName)->value()->setClosedOver();

        BinaryNodeType importSpec = handler.newImportSpec(importName, bindingNameNode);
        if (!importSpec) {
            return false;
        }

        handler.addList(importSpecSet, importSpec);
    }

    return true;
}

template<typename Unit>
BinaryNode*
Parser<FullParseHandler, Unit>::importDeclaration()
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));

    if (!pc->atModuleLevel()) {
        error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
        return null();
    }

    uint32_t begin = pos().begin;
    TokenKind tt;
    if (!tokenStream.getToken(&tt)) {
        return null();
    }

    ListNodeType importSpecSet = handler.newList(ParseNodeKind::ImportSpecList, pos());
    if (!importSpecSet) {
        return null();
    }

    if (tt == TokenKind::String) {
        // Handle the form |import 'a'| by leaving the list empty. This is
        // equivalent to |import {} from 'a'|.
        importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
    } else {
        if (tt == TokenKind::LeftCurly || tt == TokenKind::Mul) {
            if (!namedImportsOrNamespaceImport(tt, importSpecSet)) {
                return null();
            }
        } else if (TokenKindIsPossibleIdentifierName(tt)) {
            // Handle the form |import a from 'b'|, by adding a single import
            // specifier to the list, with 'default' as the import name and
            // 'a' as the binding name. This is equivalent to
            // |import { default as a } from 'b'|.
            Node importName = newName(context->names().default_);
            if (!importName) {
                return null();
            }

            RootedPropertyName bindingAtom(context, importedBinding());
            if (!bindingAtom) {
                return null();
            }

            Node bindingName = newName(bindingAtom);
            if (!bindingName) {
                return null();
            }

            if (!noteDeclaredName(bindingAtom, DeclarationKind::Import, pos())) {
                return null();
            }

            BinaryNodeType importSpec = handler.newImportSpec(importName, bindingName);
            if (!importSpec) {
                return null();
            }

            handler.addList(importSpecSet, importSpec);

            if (!tokenStream.peekToken(&tt)) {
                return null();
            }

            if (tt == TokenKind::Comma) {
                tokenStream.consumeKnownToken(tt);
                if (!tokenStream.getToken(&tt)) {
                    return null();
                }

                if (tt != TokenKind::LeftCurly && tt != TokenKind::Mul) {
                    error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
                    return null();
                }

                if (!namedImportsOrNamespaceImport(tt, importSpecSet)) {
                    return null();
                }
            }
        } else {
            error(JSMSG_DECLARATION_AFTER_IMPORT);
            return null();
        }

        MUST_MATCH_TOKEN(TokenKind::From, JSMSG_FROM_AFTER_IMPORT_CLAUSE);

        MUST_MATCH_TOKEN(TokenKind::String, JSMSG_MODULE_SPEC_AFTER_FROM);
    }

    NameNodeType moduleSpec = stringLiteral();
    if (!moduleSpec) {
        return null();
    }

    if (!matchOrInsertSemicolon()) {
        return null();
    }

    BinaryNode* node =
        handler.newImportDeclaration(importSpecSet, moduleSpec, TokenPos(begin, pos().end));
    if (!node || !pc->sc()->asModuleContext()->builder.processImport(node)) {
        return null();
    }

    return node;
}

template<typename Unit>
inline SyntaxParseHandler::BinaryNodeType
Parser<SyntaxParseHandler, Unit>::importDeclaration()
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return SyntaxParseHandler::NodeFailure;
}

template <class ParseHandler, typename Unit>
inline typename ParseHandler::BinaryNodeType
GeneralParser<ParseHandler, Unit>::importDeclaration()
{
    return asFinalParser()->importDeclaration();
}

template <class ParseHandler, typename Unit>
inline typename ParseHandler::Node
GeneralParser<ParseHandler, Unit>::importDeclarationOrImportExpr(YieldHandling yieldHandling)
{
    MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));

    TokenKind tt;
    if (!tokenStream.peekToken(&tt)) {
        return null();
    }

    if (tt == TokenKind::Dot || tt == TokenKind::LeftParen) {
        return expressionStatement(yieldHandling);
    }

    return importDeclaration();
}

template<typename Unit>
bool
Parser<FullParseHandler, Unit>::checkExportedName(JSAtom* exportName)
{
    if (!pc->sc()->asModuleContext()->builder.hasExportedName(exportName)) {
        return true;
    }

    UniqueChars str = AtomToPrintableString(context, exportName);
    if (!str) {
        return false;
    }

    error(JSMSG_DUPLICATE_EXPORT_NAME, str.get());
    return false;
}

template<typename Unit>
inline bool
Parser<SyntaxParseHandler, Unit>::checkExportedName(JSAtom* exportName)
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return false;
}

template<class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedName(JSAtom* exportName)
{
    return asFinalParser()->checkExportedName(exportName);
}

template<typename Unit>
bool
Parser<FullParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNode* array)
{
    MOZ_ASSERT(array->isKind(ParseNodeKind::Array));

    for (ParseNode* node : array->contents()) {
        if (node->isKind(ParseNodeKind::Elision)) {
            continue;
        }

        ParseNode* binding;
        if (node->isKind(ParseNodeKind::Spread)) {
            binding = node->as<UnaryNode>().kid();
        } else if (node->isKind(ParseNodeKind::Assign)) {
            binding = node->as<AssignmentNode>().left();
        } else {
            binding = node;
        }

        if (!checkExportedNamesForDeclaration(binding)) {
            return false;
        }
    }

    return true;
}

template<typename Unit>
inline bool
Parser<SyntaxParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNodeType array)
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return false;
}

template<class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedNamesForArrayBinding(ListNodeType array)
{
    return asFinalParser()->checkExportedNamesForArrayBinding(array);
}

template<typename Unit>
bool
Parser<FullParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNode* obj)
{
    MOZ_ASSERT(obj->isKind(ParseNodeKind::Object));

    for (ParseNode* node : obj->contents()) {
        MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
                   node->isKind(ParseNodeKind::Colon) ||
                   node->isKind(ParseNodeKind::Shorthand) ||
                   node->isKind(ParseNodeKind::Spread));

        ParseNode* target;
        if (node->isKind(ParseNodeKind::Spread)) {
            target = node->as<UnaryNode>().kid();
        } else {
            if (node->isKind(ParseNodeKind::MutateProto)) {
                target = node->as<UnaryNode>().kid();
            } else {
                target = node->as<BinaryNode>().right();
            }

            if (target->isKind(ParseNodeKind::Assign)) {
                target = target->as<AssignmentNode>().left();
            }
        }

        if (!checkExportedNamesForDeclaration(target)) {
            return false;
        }
    }

    return true;
}

template<typename Unit>
inline bool
Parser<SyntaxParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNodeType obj)
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return false;
}

template<class ParseHandler, typename Unit>
inline bool
GeneralParser<ParseHandler, Unit>::checkExportedNamesForObjectBinding(ListNodeType obj)
{
    return asFinalParser()->checkExportedNamesForObjectBinding(obj);
}

template<typename Unit>
bool
Parser<FullParseHandler, Unit>::checkExportedNamesForDeclaration(ParseNode* node)
{
    if (node->isKind(ParseNodeKind::Name)) {
        if (!checkExportedName(node->as<NameNode>().atom())) {
            return false;
        }
    } else if (node->isKind(ParseNodeKind::Array)) {
        if (!checkExportedNamesForArrayBinding(&node->as<ListNode>())) {
            return false;
        }
    } else {
        MOZ_ASSERT(node->isKind(ParseNodeKind::Object));
        if (!checkExportedNamesForObjectBinding(&node->as<ListNode>())) {
            return false;
        }
    }

    return true;
}

template<typename Unit>
inline bool
Parser<SyntaxParseHandler, Unit>::checkExportedNamesForDeclaration(Node node)
{
    MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
    return false;
}