js/src/frontend/BinSource-auto.cpp
author Tooru Fujisawa <arai_a@mac.com>
Tue, 30 Oct 2018 09:49:41 +0900
changeset 502591 a4fb56d2819e636de6c7ae756028e537efae48d0
parent 501790 c22d2d5b7af664565e888b039badd8157d80264c
permissions -rw-r--r--
Bug 1497784 - Drop support for lexical declaration in BinAST for now. r=Yoric

// This file was autogenerated by binjs_generate_spidermonkey,
// please DO NOT EDIT BY HAND.
/* -*- 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/. */

// To generate this file, see the documentation in
// js/src/frontend/binsource/README.md.

#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Vector.h"

#include "frontend/BinSource-macros.h"
#include "frontend/BinSource.h"
#include "frontend/BinTokenReaderTester.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "frontend/SharedContext.h"

#include "vm/RegExpObject.h"

#include "frontend/ParseContext-inl.h"

namespace js {
namespace frontend {

// Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
// a string literal (and ONLY a string literal).
template<typename Tok, size_t N>
bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
    return Tok::equals(left, right);
}


// ----- Sums of interfaces (autogenerated, by lexicographical order)
// Sums of sums are flattened.
/*
AssertedMaybePositionalParameterName ::= AssertedParameterName
    AssertedPositionalParameterName
    AssertedRestParameterName
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedMaybePositionalParameterName(
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumAssertedMaybePositionalParameterName(start, kind, fields,
        scopeKind, positionalParams));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseSumAssertedMaybePositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    Ok result;
    switch (kind) {
      case BinKind::AssertedParameterName:
        return raiseError("FIXME: Not implemented yet in this preview release (AssertedParameterName)");
      case BinKind::AssertedPositionalParameterName:
        MOZ_TRY_VAR(result, parseInterfaceAssertedPositionalParameterName(start, kind, fields,
            scopeKind, positionalParams));
        break;
      case BinKind::AssertedRestParameterName:
        return raiseError("FIXME: Not implemented yet in this preview release (AssertedRestParameterName)");
      default:
        return raiseInvalidKind("AssertedMaybePositionalParameterName", kind);
    }
    return result;
}

/*
AssignmentTarget ::= ArrayAssignmentTarget
    AssignmentTargetIdentifier
    ComputedMemberAssignmentTarget
    ObjectAssignmentTarget
    StaticMemberAssignmentTarget
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTarget()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTarget(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
        break;
      case BinKind::AssignmentTargetIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
        break;
      case BinKind::ComputedMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
        break;
      case BinKind::ObjectAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
        break;
      case BinKind::StaticMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("AssignmentTarget", kind);
    }
    return result;
}

/*
Binding ::= ArrayBinding
    BindingIdentifier
    ObjectBinding
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBinding()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayBinding:
        MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
        break;
      case BinKind::BindingIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
        break;
      case BinKind::ObjectBinding:
        MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Binding", kind);
    }
    return result;
}

/*
Expression ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpressionWithExpression
    EagerArrowExpressionWithFunctionBody
    EagerFunctionExpression
    IdentifierExpression
    LazyArrowExpressionWithExpression
    LazyArrowExpressionWithFunctionBody
    LazyFunctionExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    StaticMemberExpression
    TemplateExpression
    ThisExpression
    UnaryExpression
    UpdateExpression
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayExpression:
        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
        break;
      case BinKind::AssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
        break;
      case BinKind::AwaitExpression:
        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
        break;
      case BinKind::BinaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
        break;
      case BinKind::CallExpression:
        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
        break;
      case BinKind::ClassExpression:
        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
        break;
      case BinKind::CompoundAssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
        break;
      case BinKind::ComputedMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
        break;
      case BinKind::ConditionalExpression:
        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::IdentifierExpression:
        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::LazyFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
        break;
      case BinKind::LiteralBooleanExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
        break;
      case BinKind::LiteralInfinityExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
        break;
      case BinKind::LiteralNullExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
        break;
      case BinKind::LiteralNumericExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
        break;
      case BinKind::LiteralRegExpExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
        break;
      case BinKind::LiteralStringExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
        break;
      case BinKind::NewExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
        break;
      case BinKind::NewTargetExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
        break;
      case BinKind::ObjectExpression:
        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
        break;
      case BinKind::StaticMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
        break;
      case BinKind::TemplateExpression:
        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
        break;
      case BinKind::ThisExpression:
        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
        break;
      case BinKind::UnaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
        break;
      case BinKind::UpdateExpression:
        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
        break;
      case BinKind::YieldExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
        break;
      case BinKind::YieldStarExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Expression", kind);
    }
    return result;
}

/*
ExpressionOrSuper ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpressionWithExpression
    EagerArrowExpressionWithFunctionBody
    EagerFunctionExpression
    IdentifierExpression
    LazyArrowExpressionWithExpression
    LazyArrowExpressionWithFunctionBody
    LazyFunctionExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    StaticMemberExpression
    Super
    TemplateExpression
    ThisExpression
    UnaryExpression
    UpdateExpression
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExpressionOrSuper()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumExpressionOrSuper(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayExpression:
        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
        break;
      case BinKind::AssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
        break;
      case BinKind::AwaitExpression:
        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
        break;
      case BinKind::BinaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
        break;
      case BinKind::CallExpression:
        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
        break;
      case BinKind::ClassExpression:
        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
        break;
      case BinKind::CompoundAssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
        break;
      case BinKind::ComputedMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
        break;
      case BinKind::ConditionalExpression:
        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::IdentifierExpression:
        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::LazyFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
        break;
      case BinKind::LiteralBooleanExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
        break;
      case BinKind::LiteralInfinityExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
        break;
      case BinKind::LiteralNullExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
        break;
      case BinKind::LiteralNumericExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
        break;
      case BinKind::LiteralRegExpExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
        break;
      case BinKind::LiteralStringExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
        break;
      case BinKind::NewExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
        break;
      case BinKind::NewTargetExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
        break;
      case BinKind::ObjectExpression:
        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
        break;
      case BinKind::StaticMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
        break;
      case BinKind::Super:
        MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields));
        break;
      case BinKind::TemplateExpression:
        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
        break;
      case BinKind::ThisExpression:
        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
        break;
      case BinKind::UnaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
        break;
      case BinKind::UpdateExpression:
        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
        break;
      case BinKind::YieldExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
        break;
      case BinKind::YieldStarExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ExpressionOrSuper", kind);
    }
    return result;
}

/*
ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget
    AssignmentTargetIdentifier
    ComputedMemberAssignmentTarget
    ForInOfBinding
    ObjectAssignmentTarget
    StaticMemberAssignmentTarget
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumForInOfBindingOrAssignmentTarget(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
        break;
      case BinKind::AssignmentTargetIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
        break;
      case BinKind::ComputedMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
        break;
      case BinKind::ForInOfBinding:
        MOZ_TRY_VAR(result, parseInterfaceForInOfBinding(start, kind, fields));
        break;
      case BinKind::ObjectAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
        break;
      case BinKind::StaticMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
    }
    return result;
}

/*
ObjectProperty ::= DataProperty
    EagerGetter
    EagerMethod
    EagerSetter
    LazyGetter
    LazyMethod
    LazySetter
    ShorthandProperty
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseObjectProperty()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumObjectProperty(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::DataProperty:
        MOZ_TRY_VAR(result, parseInterfaceDataProperty(start, kind, fields));
        break;
      case BinKind::EagerGetter:
        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
        break;
      case BinKind::EagerMethod:
        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
        break;
      case BinKind::EagerSetter:
        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
        break;
      case BinKind::LazyGetter:
        MOZ_TRY_VAR(result, parseInterfaceLazyGetter(start, kind, fields));
        break;
      case BinKind::LazyMethod:
        MOZ_TRY_VAR(result, parseInterfaceLazyMethod(start, kind, fields));
        break;
      case BinKind::LazySetter:
        MOZ_TRY_VAR(result, parseInterfaceLazySetter(start, kind, fields));
        break;
      case BinKind::ShorthandProperty:
        MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ObjectProperty", kind);
    }
    return result;
}

/*
Parameter ::= ArrayBinding
    BindingIdentifier
    BindingWithInitializer
    ObjectBinding
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseParameter()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayBinding:
        MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
        break;
      case BinKind::BindingIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
        if (!parseContext_->positionalFormalParameterNames().append(result->template as<NameNode>().atom())) {
            return raiseOOM();
        }
        if (parseContext_->isFunctionBox()) {
            parseContext_->functionBox()->length++;
        }
        break;
      case BinKind::BindingWithInitializer:
        MOZ_TRY_VAR(result, parseInterfaceBindingWithInitializer(start, kind, fields));
        break;
      case BinKind::ObjectBinding:
        MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Parameter", kind);
    }
    return result;
}

/*
Program ::= Module
    Script
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseProgram()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::Module:
        MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields));
        break;
      case BinKind::Script:
        MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Program", kind);
    }
    return result;
}

/*
PropertyName ::= ComputedPropertyName
    LiteralPropertyName
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parsePropertyName()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumPropertyName(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ComputedPropertyName:
        MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind, fields));
        break;
      case BinKind::LiteralPropertyName:
        MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("PropertyName", kind);
    }
    return result;
}

/*
SimpleAssignmentTarget ::= AssignmentTargetIdentifier
    ComputedMemberAssignmentTarget
    StaticMemberAssignmentTarget
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSimpleAssignmentTarget()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumSimpleAssignmentTarget(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::AssignmentTargetIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
        break;
      case BinKind::ComputedMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
        break;
      case BinKind::StaticMemberAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("SimpleAssignmentTarget", kind);
    }
    return result;
}

/*
SpreadElementOrExpression ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpressionWithExpression
    EagerArrowExpressionWithFunctionBody
    EagerFunctionExpression
    IdentifierExpression
    LazyArrowExpressionWithExpression
    LazyArrowExpressionWithFunctionBody
    LazyFunctionExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SpreadElement
    StaticMemberExpression
    TemplateExpression
    ThisExpression
    UnaryExpression
    UpdateExpression
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSpreadElementOrExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumSpreadElementOrExpression(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayExpression:
        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
        break;
      case BinKind::AssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
        break;
      case BinKind::AwaitExpression:
        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
        break;
      case BinKind::BinaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
        break;
      case BinKind::CallExpression:
        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
        break;
      case BinKind::ClassExpression:
        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
        break;
      case BinKind::CompoundAssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
        break;
      case BinKind::ComputedMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
        break;
      case BinKind::ConditionalExpression:
        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::IdentifierExpression:
        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::LazyFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
        break;
      case BinKind::LiteralBooleanExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
        break;
      case BinKind::LiteralInfinityExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
        break;
      case BinKind::LiteralNullExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
        break;
      case BinKind::LiteralNumericExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
        break;
      case BinKind::LiteralRegExpExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
        break;
      case BinKind::LiteralStringExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
        break;
      case BinKind::NewExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
        break;
      case BinKind::NewTargetExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
        break;
      case BinKind::ObjectExpression:
        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
        break;
      case BinKind::SpreadElement:
        MOZ_TRY_VAR(result, parseInterfaceSpreadElement(start, kind, fields));
        break;
      case BinKind::StaticMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
        break;
      case BinKind::TemplateExpression:
        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
        break;
      case BinKind::ThisExpression:
        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
        break;
      case BinKind::UnaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
        break;
      case BinKind::UpdateExpression:
        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
        break;
      case BinKind::YieldExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
        break;
      case BinKind::YieldStarExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("SpreadElementOrExpression", kind);
    }
    return result;
}

/*
Statement ::= Block
    BreakStatement
    ClassDeclaration
    ContinueStatement
    DebuggerStatement
    DoWhileStatement
    EagerFunctionDeclaration
    EmptyStatement
    ExpressionStatement
    ForInStatement
    ForOfStatement
    ForStatement
    IfStatement
    LabelledStatement
    LazyFunctionDeclaration
    ReturnStatement
    SwitchStatement
    SwitchStatementWithDefault
    ThrowStatement
    TryCatchStatement
    TryFinallyStatement
    VariableDeclaration
    WhileStatement
    WithStatement
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);
    const auto start = tokenizer_->offset();

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));

    BINJS_MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields));

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::Block:
        MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
        break;
      case BinKind::BreakStatement:
        MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
        break;
      case BinKind::ClassDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
        break;
      case BinKind::ContinueStatement:
        MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
        break;
      case BinKind::DebuggerStatement:
        MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
        break;
      case BinKind::DoWhileStatement:
        MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
        break;
      case BinKind::EagerFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::EmptyStatement:
        MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
        break;
      case BinKind::ExpressionStatement:
        MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields));
        break;
      case BinKind::ForInStatement:
        MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
        break;
      case BinKind::ForOfStatement:
        MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields));
        break;
      case BinKind::ForStatement:
        MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields));
        break;
      case BinKind::IfStatement:
        MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields));
        break;
      case BinKind::LabelledStatement:
        MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields));
        break;
      case BinKind::LazyFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::ReturnStatement:
        MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
        break;
      case BinKind::SwitchStatement:
        MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
        break;
      case BinKind::SwitchStatementWithDefault:
        MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields));
        break;
      case BinKind::ThrowStatement:
        MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
        break;
      case BinKind::TryCatchStatement:
        MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields));
        break;
      case BinKind::TryFinallyStatement:
        MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields));
        break;
      case BinKind::VariableDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
        break;
      case BinKind::WhileStatement:
        MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields));
        break;
      case BinKind::WithStatement:
        MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Statement", kind);
    }
    return result;
}


template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ArrayExpression:
        MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
        break;
      case BinKind::AssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields));
        break;
      case BinKind::AwaitExpression:
        MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
        break;
      case BinKind::BinaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
        break;
      case BinKind::CallExpression:
        MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
        break;
      case BinKind::ClassExpression:
        MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
        break;
      case BinKind::CompoundAssignmentExpression:
        MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
        break;
      case BinKind::ComputedMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
        break;
      case BinKind::ConditionalExpression:
        MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::EagerArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::IdentifierExpression:
        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      case BinKind::LazyFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
        break;
      case BinKind::LiteralBooleanExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
        break;
      case BinKind::LiteralInfinityExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
        break;
      case BinKind::LiteralNullExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields));
        break;
      case BinKind::LiteralNumericExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
        break;
      case BinKind::LiteralRegExpExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
        break;
      case BinKind::LiteralStringExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
        break;
      case BinKind::NewExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
        break;
      case BinKind::NewTargetExpression:
        MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
        break;
      case BinKind::ObjectExpression:
        MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
        break;
      case BinKind::StaticMemberExpression:
        MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
        break;
      case BinKind::TemplateExpression:
        MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
        break;
      case BinKind::ThisExpression:
        MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
        break;
      case BinKind::UnaryExpression:
        MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
        break;
      case BinKind::UpdateExpression:
        MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
        break;
      case BinKind::VariableDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
        break;
      case BinKind::YieldExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
        break;
      case BinKind::YieldStarExpression:
        MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("VariableDeclarationOrExpression", kind);
    }
    return result;
}



// ----- Interfaces (autogenerated, by lexicographical order)
// When fields have a non-trivial type, implementation is deanonymized and delegated to another parser.
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ArrayAssignmentTarget)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ArrayBinding)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ArrayExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Elements };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());

    if (elements->empty()) {
        elements->setHasNonConstInitializer();
    }
    auto result = elements;
    return result;
}


/*
 interface AssertedBlockScope : Node {
    FrozenArray<AssertedDeclaredName> declaredNames;
    bool hasDirectEval;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedBlockScope()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedBlockScope) {
        return raiseInvalidKind("AssertedBlockScope", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBlockScope(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssertedBlockScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::DeclaredNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto scopeKind = AssertedScopeKind::Block;

    MOZ_TRY(parseListOfAssertedDeclaredName(
        scopeKind));

    BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
    if (hasDirectEval) {
        parseContext_->sc()->setHasDirectEval();
        parseContext_->sc()->setBindingsAccessedDynamically();
    }
    if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
        // In non-strict mode code, direct calls to eval can
        // add variables to the call object.
        parseContext_->functionBox()->setHasExtensibleScope();
    }
    auto result = Ok();
    return result;
}


/*
 interface AssertedBoundName : Node {
    [IdentifierName] string name;
    bool isCaptured;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedBoundName(
        AssertedScopeKind scopeKind)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedBoundName) {
        return raiseInvalidKind("AssertedBoundName", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundName(start, kind, fields,
        scopeKind));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedBoundName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind)
{
    MOZ_ASSERT(kind == BinKind::AssertedBoundName);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Name, BinField::IsCaptured };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const bool allowDuplicateName = false;

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());

    BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
    ParseContext::Scope* scope;
    DeclarationKind declKind;
    MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
    MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured, allowDuplicateName));
    auto result = Ok();
    return result;
}


/*
 interface AssertedBoundNamesScope : Node {
    FrozenArray<AssertedBoundName> boundNames;
    bool hasDirectEval;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedBoundNamesScope()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedBoundNamesScope) {
        return raiseInvalidKind("AssertedBoundNamesScope", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundNamesScope(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedBoundNamesScope(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssertedBoundNamesScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::BoundNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto scopeKind = AssertedScopeKind::Catch;

    MOZ_TRY(parseListOfAssertedBoundName(
        scopeKind));

    BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
    if (hasDirectEval) {
        parseContext_->sc()->setHasDirectEval();
        parseContext_->sc()->setBindingsAccessedDynamically();
    }
    if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
        // In non-strict mode code, direct calls to eval can
        // add variables to the call object.
        parseContext_->functionBox()->setHasExtensibleScope();
    }
    auto result = Ok();
    return result;
}


/*
 interface AssertedDeclaredName : Node {
    [IdentifierName] string name;
    AssertedDeclaredKind kind;
    bool isCaptured;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedDeclaredName(
        AssertedScopeKind scopeKind)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedDeclaredName) {
        return raiseInvalidKind("AssertedDeclaredName", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedDeclaredName(start, kind, fields,
        scopeKind));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedDeclaredName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind)
{
    MOZ_ASSERT(kind == BinKind::AssertedDeclaredName);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Name, BinField::Kind, BinField::IsCaptured };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const bool allowDuplicateName = false;

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());

    BINJS_MOZ_TRY_DECL(kind_, parseAssertedDeclaredKind());

    BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
    ParseContext::Scope* scope;
    DeclarationKind declKind;
    MOZ_TRY(getDeclaredScope(scopeKind, kind_, scope, declKind));
    MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured, allowDuplicateName));
    auto result = Ok();
    return result;
}


/*
 interface AssertedParameterScope : Node {
    FrozenArray<AssertedMaybePositionalParameterName> paramNames;
    bool hasDirectEval;
    bool isSimpleParameterList;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedParameterScope(
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedParameterScope) {
        return raiseInvalidKind("AssertedParameterScope", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedParameterScope(start, kind, fields,
        positionalParams));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    MOZ_ASSERT(kind == BinKind::AssertedParameterScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::ParamNames, BinField::HasDirectEval, BinField::IsSimpleParameterList };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto scopeKind = AssertedScopeKind::Parameter;

    MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(
        scopeKind, positionalParams));

    BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
    if (hasDirectEval) {
        parseContext_->sc()->setHasDirectEval();
        parseContext_->sc()->setBindingsAccessedDynamically();
    }
    BINJS_MOZ_TRY_DECL(isSimpleParameterList, tokenizer_->readBool());
    (void) isSimpleParameterList;
    if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
        // In non-strict mode code, direct calls to eval can
        // add variables to the call object.
        parseContext_->functionBox()->setHasExtensibleScope();
    }
    auto result = Ok();
    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedPositionalParameterName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    MOZ_ASSERT(kind == BinKind::AssertedPositionalParameterName);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Index, BinField::Name, BinField::IsCaptured };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    bool allowDuplicateName = !parseContext_->sc()->strict();

    BINJS_MOZ_TRY_DECL(index, tokenizer_->readUnsignedLong());

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
    // `positionalParams` vector can be shorter than the actual
    // parameter length. Resize on demand.
    // (see also ListOfAssertedMaybePositionalParameterName)
    size_t prevLength = positionalParams.get().length();
    if (index >= prevLength) {
        // This is implementation limit, which is not in the spec.
        if (index >= ARGNO_LIMIT - 1) {
            return raiseError("AssertedPositionalParameterName.index is too big");
        }
        size_t newLength = index + 1;
        BINJS_TRY(positionalParams.get().resize(newLength));
        for (uint32_t i = prevLength; i < newLength; i++) {
            positionalParams.get()[i] = nullptr;
        }
    }

    if (positionalParams.get()[index]) {
        return raiseError("AssertedPositionalParameterName has duplicate entry for the same index");
    }
    positionalParams.get()[index] = name;
    BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
    ParseContext::Scope* scope;
    DeclarationKind declKind;
    MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
    MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured, allowDuplicateName));
    auto result = Ok();
    return result;
}


/*
 interface AssertedScriptGlobalScope : Node {
    FrozenArray<AssertedDeclaredName> declaredNames;
    bool hasDirectEval;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedScriptGlobalScope()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedScriptGlobalScope) {
        return raiseInvalidKind("AssertedScriptGlobalScope", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedScriptGlobalScope(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedScriptGlobalScope(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssertedScriptGlobalScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::DeclaredNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto scopeKind = AssertedScopeKind::Global;

    MOZ_TRY(parseListOfAssertedDeclaredName(
        scopeKind));

    BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
    if (hasDirectEval) {
        parseContext_->sc()->setHasDirectEval();
        parseContext_->sc()->setBindingsAccessedDynamically();
    }
    if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
        // In non-strict mode code, direct calls to eval can
        // add variables to the call object.
        parseContext_->functionBox()->setHasExtensibleScope();
    }
    auto result = Ok();
    return result;
}


/*
 interface AssertedVarScope : Node {
    FrozenArray<AssertedDeclaredName> declaredNames;
    bool hasDirectEval;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedVarScope()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::AssertedVarScope) {
        return raiseInvalidKind("AssertedVarScope", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedVarScope(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssertedVarScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::DeclaredNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto scopeKind = AssertedScopeKind::Var;

    MOZ_TRY(parseListOfAssertedDeclaredName(
        scopeKind));

    BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
    if (hasDirectEval) {
        parseContext_->sc()->setHasDirectEval();
        parseContext_->sc()->setBindingsAccessedDynamically();
    }
    if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
        // In non-strict mode code, direct calls to eval can
        // add variables to the call object.
        parseContext_->functionBox()->setHasExtensibleScope();
    }
    auto result = Ok();
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssignmentExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Binding, BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget());

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    BINJS_TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Name };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());

    if (!IsIdentifier(name)) {
        return raiseError("Invalid identifier");
    }
    BINJS_TRY(usedNames_.noteUse(cx_, name, parseContext_->scriptId(), parseContext_->innermostScope()->id()));
    BINJS_TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (AwaitExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::BinaryExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Operator, BinField::Left, BinField::Right };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(operator_, parseBinaryOperator());

    BINJS_MOZ_TRY_DECL(left, parseExpression());

    BINJS_MOZ_TRY_DECL(right, parseExpression());

    ParseNodeKind pnk;
    switch (operator_) {
      case BinaryOperator::Comma:
        pnk = ParseNodeKind::Comma;
        break;
      case BinaryOperator::LogicalOr:
        pnk = ParseNodeKind::Or;
        break;
      case BinaryOperator::LogicalAnd:
        pnk = ParseNodeKind::And;
        break;
      case BinaryOperator::BitOr:
        pnk = ParseNodeKind::BitOr;
        break;
      case BinaryOperator::BitXor:
        pnk = ParseNodeKind::BitXor;
        break;
      case BinaryOperator::BitAnd:
        pnk = ParseNodeKind::BitAnd;
        break;
      case BinaryOperator::Eq:
        pnk = ParseNodeKind::Eq;
        break;
      case BinaryOperator::Neq:
        pnk = ParseNodeKind::Ne;
        break;
      case BinaryOperator::StrictEq:
        pnk = ParseNodeKind::StrictEq;
        break;
      case BinaryOperator::StrictNeq:
        pnk = ParseNodeKind::StrictNe;
        break;
      case BinaryOperator::LessThan:
        pnk = ParseNodeKind::Lt;
        break;
      case BinaryOperator::LeqThan:
        pnk = ParseNodeKind::Le;
        break;
      case BinaryOperator::GreaterThan:
        pnk = ParseNodeKind::Gt;
        break;
      case BinaryOperator::GeqThan:
        pnk = ParseNodeKind::Ge;
        break;
      case BinaryOperator::In:
        pnk = ParseNodeKind::In;
        break;
      case BinaryOperator::Instanceof:
        pnk = ParseNodeKind::InstanceOf;
        break;
      case BinaryOperator::Lsh:
        pnk = ParseNodeKind::Lsh;
        break;
      case BinaryOperator::Rsh:
        pnk = ParseNodeKind::Rsh;
        break;
      case BinaryOperator::Ursh:
        pnk = ParseNodeKind::Ursh;
        break;
      case BinaryOperator::Plus:
        pnk = ParseNodeKind::Add;
        break;
      case BinaryOperator::Minus:
        pnk = ParseNodeKind::Sub;
        break;
      case BinaryOperator::Mul:
        pnk = ParseNodeKind::Star;
        break;
      case BinaryOperator::Div:
        pnk = ParseNodeKind::Div;
        break;
      case BinaryOperator::Mod:
        pnk = ParseNodeKind::Mod;
        break;
      case BinaryOperator::Pow:
        pnk = ParseNodeKind::Pow;
        break;
    }

    ParseNode* result;
    if (left->isKind(pnk) &&
        pnk != ParseNodeKind::Pow /* ParseNodeKind::Pow is not left-associative */)
    {
        // Regroup left-associative operations into lists.
        left->template as<ListNode>().appendWithoutOrderAssumption(right);
        result = left;
    } else {
        BINJS_TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start)));

        list->appendWithoutOrderAssumption(left);
        list->appendWithoutOrderAssumption(right);
        result = list;
    }
    return result;
}


/*
 interface BindingIdentifier : Node {
    [IdentifierName] string name;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBindingIdentifier()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::BindingIdentifier) {
        return raiseInvalidKind("BindingIdentifier", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceBindingIdentifier(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::BindingIdentifier);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Name };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());

    if (!IsIdentifier(name)) {
        return raiseError("Invalid identifier");
    }
    BINJS_TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (BindingWithInitializer)");
}


/*
 interface Block : Node {
    AssertedBlockScope scope;
    FrozenArray<Statement> statements;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBlock()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::Block) {
        return raiseInvalidKind("Block", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::Block);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Scope, BinField::Statements };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::Block);
    ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(currentScope.init(parseContext_));

    MOZ_TRY(parseAssertedBlockScope());

    BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());

    MOZ_TRY(checkClosedVars(currentScope));
    BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
    BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, statements));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::BreakStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Label };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    RootedAtom label(cx_);
    MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());

    if (label) {
        if (!IsIdentifier(label)) {
            return raiseError("Invalid identifier");
        }

        auto validity = parseContext_->checkBreakStatement(label->asPropertyName());

        if (validity.isErr()) {
            switch (validity.unwrapErr()) {
            case ParseContext::BreakStatementError::ToughBreak:
                return raiseError(kind, "Not in a loop");
            case ParseContext::BreakStatementError::LabelNotFound:
                return raiseError(kind, "Label not found");
            }
        }
    }
    BINJS_TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::CallExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Callee, BinField::Arguments };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper());

    BINJS_MOZ_TRY_DECL(arguments, parseArguments());

    auto op = JSOP_CALL;

    // Try to optimize funcall and funapply at the bytecode level
    if (PropertyName* prop = factory_.maybeDottedProperty(callee)) {
        if (prop == cx_->names().apply) {
            op = JSOP_FUNAPPLY;
            if (parseContext_->isFunctionBox())
                parseContext_->functionBox()->usesApply = true;
        } else if (prop == cx_->names().call) {
            op = JSOP_FUNCALL;
        }
    }

    // Check for direct calls to `eval`.
    if (factory_.isEvalName(callee, cx_)) {
        if (!parseContext_->varScope().lookupDeclaredNameForAdd(cx_->names().eval)
         && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(cx_->names().eval))
        {
            // This is a direct call to `eval`.
            if (!parseContext_->sc()->hasDirectEval()) {
                return raiseMissingDirectEvalInAssertedScope();
            }

            op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
        }
    }

    BINJS_TRY_DECL(result, factory_.newCall(callee, arguments));
    result->setOp(op);
    return result;
}


/*
 interface CatchClause : Node {
    AssertedBoundNamesScope bindingScope;
    Binding binding;
    Block body;
 }
*/
template<typename Tok> JS::Result<LexicalScopeNode*>
BinASTParser<Tok>::parseCatchClause()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::CatchClause) {
        return raiseInvalidKind("CatchClause", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceCatchClause(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<LexicalScopeNode*>
BinASTParser<Tok>::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::CatchClause);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::BindingScope, BinField::Binding, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
    ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(currentScope.init(parseContext_));

    MOZ_TRY(parseAssertedBoundNamesScope());

    BINJS_MOZ_TRY_DECL(binding, parseBinding());

    BINJS_MOZ_TRY_DECL(body, parseBlock());

    MOZ_TRY(checkClosedVars(currentScope));
    BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
    BINJS_TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
    BINJS_TRY(factory_.setupCatchScope(result, binding, body));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ClassDeclaration)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ClassExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::CompoundAssignmentExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Operator, BinField::Binding, BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());

    BINJS_MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget());

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    ParseNodeKind pnk;
    switch (operator_){
      case CompoundAssignmentOperator::PlusAssign:
        pnk = ParseNodeKind::AddAssign;
        break;
      case CompoundAssignmentOperator::MinusAssign:
        pnk = ParseNodeKind::SubAssign;
        break;
      case CompoundAssignmentOperator::MulAssign:
        pnk = ParseNodeKind::MulAssign;
        break;
      case CompoundAssignmentOperator::DivAssign:
        pnk = ParseNodeKind::DivAssign;
        break;
      case CompoundAssignmentOperator::ModAssign:
        pnk = ParseNodeKind::ModAssign;
        break;
      case CompoundAssignmentOperator::PowAssign:
        pnk = ParseNodeKind::PowAssign;
        break;
      case CompoundAssignmentOperator::LshAssign:
        pnk = ParseNodeKind::LshAssign;
        break;
      case CompoundAssignmentOperator::RshAssign:
        pnk = ParseNodeKind::RshAssign;
        break;
      case CompoundAssignmentOperator::UrshAssign:
        pnk = ParseNodeKind::UrshAssign;
        break;
      case CompoundAssignmentOperator::BitOrAssign:
        pnk = ParseNodeKind::BitOrAssign;
        break;
      case CompoundAssignmentOperator::BitXorAssign:
        pnk = ParseNodeKind::BitXorAssign;
        break;
      case CompoundAssignmentOperator::BitAndAssign:
        pnk = ParseNodeKind::BitAndAssign;
        break;
    }
    BINJS_TRY_DECL(result, factory_.newAssignment(pnk, binding, expression));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ComputedMemberAssignmentTarget);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Object, BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ComputedMemberExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Object, BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ComputedPropertyName)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ConditionalExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Test, BinField::Consequent, BinField::Alternate };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(consequent, parseExpression());

    BINJS_MOZ_TRY_DECL(alternate, parseExpression());

    BINJS_TRY_DECL(result, factory_.newConditional(test, consequent, alternate));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ContinueStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Label };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    RootedAtom label(cx_);
    MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());

    if (label) {
        if (!IsIdentifier(label)) {
            return raiseError("ContinueStatement - Label MUST be an identifier");
        }

        auto validity = parseContext_->checkContinueStatement(label ? label->asPropertyName() : nullptr);
        if (validity.isErr()) {
            switch (validity.unwrapErr()) {
              case ParseContext::ContinueStatementError::NotInALoop:
                return raiseError(kind, "Not in a loop");
              case ParseContext::ContinueStatementError::LabelNotFound:
                return raiseError(kind, "Label not found");
            }
        }
    }

    BINJS_TRY_DECL(result, factory_.newContinueStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::DataProperty);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Name, BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    if (!factory_.isUsableAsObjectPropertyName(name)) {
        return raiseError("DataProperty key kind");
    }

    ParseNode* result;
    if (name->template is<NameNode>() && name->template as<NameNode>().atom() == cx_->names().proto) {
        BINJS_TRY_VAR(result, factory_.newUnary(ParseNodeKind::MutateProto, start, expression));
    } else {
        BINJS_TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));
    }
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (DebuggerStatement)");
}


/*
 interface Directive : Node {
    string rawValue;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseDirective()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::Directive) {
        return raiseInvalidKind("Directive", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceDirective(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::Directive);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::RawValue };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom rawValue(cx_);
    MOZ_TRY_VAR(rawValue, tokenizer_->readAtom());

    TokenPos pos = tokenizer_->pos(start);
    BINJS_TRY_DECL(result, factory_.newStringLiteral(rawValue, pos));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::DoWhileStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Test, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop);

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(body, parseStatement());

    BINJS_TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (EagerArrowExpressionWithExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (EagerArrowExpressionWithFunctionBody)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EagerFunctionDeclaration);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[6] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Statement;

    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
    if (isAsync) {
        return raiseError("Async function is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
    if (isGenerator) {
        return raiseError("Generator is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax,
        (syntax != FunctionSyntaxKind::Setter &&
         syntax != FunctionSyntaxKind::Getter) ? name : nullptr));

    forceStrictIfNecessary(funbox, directives);

    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
    BINJS_TRY(funpc.init());
    parseContext_->functionScope().useAsVarScope(parseContext_);
    MOZ_ASSERT(parseContext_->isFunctionBox());

    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(lexicalScope.init(parseContext_));
    ListNode* params;
    ListNode* body;
    MOZ_TRY(parseFunctionOrMethodContents(
        length, &params, &body));
    MOZ_TRY(prependDirectivesToBody(body, directives));
    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
    BINJS_TRY_DECL(bodyScope, factory_.newLexicalScope(*lexicalScopeData, body));
    BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, bodyScope, funbox));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EagerFunctionExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[6] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Expression;

    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
    if (isAsync) {
        return raiseError("Async function is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
    if (isGenerator) {
        return raiseError("Generator is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax,
        (syntax != FunctionSyntaxKind::Setter &&
         syntax != FunctionSyntaxKind::Getter) ? name : nullptr));

    forceStrictIfNecessary(funbox, directives);

    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
    BINJS_TRY(funpc.init());
    parseContext_->functionScope().useAsVarScope(parseContext_);
    MOZ_ASSERT(parseContext_->isFunctionBox());

    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(lexicalScope.init(parseContext_));
    ListNode* params;
    ListNode* body;
    MOZ_TRY(parseFunctionExpressionContents(
        length, &params, &body));
    MOZ_TRY(prependDirectivesToBody(body, directives));
    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
    BINJS_TRY_DECL(bodyScope, factory_.newLexicalScope(*lexicalScopeData, body));
    BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, bodyScope, funbox));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerGetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EagerGetter);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Name, BinField::Directives, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Setter;
    const bool isGenerator = false;
    const bool isAsync = false;
    const auto accessorType = AccessorType::Getter;
    const uint32_t length = 0;

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax,
        (syntax != FunctionSyntaxKind::Setter &&
         syntax != FunctionSyntaxKind::Getter) ? name : nullptr));

    forceStrictIfNecessary(funbox, directives);

    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
    BINJS_TRY(funpc.init());
    parseContext_->functionScope().useAsVarScope(parseContext_);
    MOZ_ASSERT(parseContext_->isFunctionBox());

    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(lexicalScope.init(parseContext_));
    ListNode* params;
    ListNode* body;
    MOZ_TRY(parseGetterContents(
        length, &params, &body));
    MOZ_TRY(prependDirectivesToBody(body, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerMethod(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EagerMethod);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[6] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Method;
    const auto accessorType = AccessorType::None;

    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
    if (isAsync) {
        return raiseError("Async function is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
    if (isGenerator) {
        return raiseError("Generator is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(name, parsePropertyName());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax,
        (syntax != FunctionSyntaxKind::Setter &&
         syntax != FunctionSyntaxKind::Getter) ? name : nullptr));

    forceStrictIfNecessary(funbox, directives);

    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
    BINJS_TRY(funpc.init());
    parseContext_->functionScope().useAsVarScope(parseContext_);
    MOZ_ASSERT(parseContext_->isFunctionBox());

    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(lexicalScope.init(parseContext_));
    ListNode* params;
    ListNode* body;
    MOZ_TRY(parseFunctionOrMethodContents(
        length, &params, &body));
    MOZ_TRY(prependDirectivesToBody(body, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerSetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EagerSetter);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[4] = { BinField::Name, BinField::Length, BinField::Directives, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Setter;
    const bool isGenerator = false;
    const bool isAsync = false;
    const auto accessorType = AccessorType::Setter;

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax,
        (syntax != FunctionSyntaxKind::Setter &&
         syntax != FunctionSyntaxKind::Getter) ? name : nullptr));

    forceStrictIfNecessary(funbox, directives);

    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
    BINJS_TRY(funpc.init());
    parseContext_->functionScope().useAsVarScope(parseContext_);
    MOZ_ASSERT(parseContext_->isFunctionBox());

    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
    BINJS_TRY(lexicalScope.init(parseContext_));
    ListNode* params;
    ListNode* body;
    MOZ_TRY(parseSetterContents(
        length, &params, &body));
    MOZ_TRY(prependDirectivesToBody(body, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::EmptyStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));

    BINJS_TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ExpressionStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    BINJS_TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset()));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ForInOfBinding);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Kind, BinField::Binding };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    AutoVariableDeclarationKind kindGuard(this);

    BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());

    BINJS_MOZ_TRY_DECL(binding, parseBinding());

    // Restored by `kindGuard`.
    variableDeclarationKind_ = kind_;
    MOZ_TRY(checkBinding(binding->template as<NameNode>().atom()->asPropertyName()));
    ParseNodeKind pnk;
    switch (kind_) {
      case VariableDeclarationKind::Var:
        pnk = ParseNodeKind::Var;
        break;
      case VariableDeclarationKind::Let:
        return raiseError("Let is not supported in this preview release");
      case VariableDeclarationKind::Const:
        return raiseError("Const is not supported in this preview release");
    }
    BINJS_TRY_DECL(result, factory_.newDeclarationList(pnk, tokenizer_->pos(start)));
    factory_.addList(result, binding);
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ForInStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Left, BinField::Right, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::ForInLoop);

    // Implicit scope around the `for`, used to store `for (let x in  ...)`
    // or `for (const x in ...)`-style declarations. Detail on the
    // declaration is stored as part of `scope`.
    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
    BINJS_TRY(scope.init(parseContext_));

    BINJS_MOZ_TRY_DECL(left, parseForInOfBindingOrAssignmentTarget());

    BINJS_MOZ_TRY_DECL(right, parseExpression());

    BINJS_MOZ_TRY_DECL(body, parseStatement());

    BINJS_TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right, tokenizer_->pos(start)));
    ParseNode* result;
    BINJS_TRY_VAR(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0));

    if (!scope.isEmpty()) {
        BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
        BINJS_TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
    }
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ForOfStatement)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ForStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[4] = { BinField::Init, BinField::Test, BinField::Update, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::ForLoop);

    // Implicit scope around the `for`, used to store `for (let x; ...; ...)`
    // or `for (const x; ...; ...)`-style declarations. Detail on the
    // declaration is stored as part of `BINJS_Scope`.
    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
    BINJS_TRY(scope.init(parseContext_));

    BINJS_MOZ_TRY_DECL(init, parseOptionalVariableDeclarationOrExpression());

    BINJS_MOZ_TRY_DECL(test, parseOptionalExpression());

    BINJS_MOZ_TRY_DECL(update, parseOptionalExpression());

    BINJS_MOZ_TRY_DECL(body, parseStatement());

    BINJS_TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start)));
    ParseNode* result;
    BINJS_TRY_VAR(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0));

    if (!scope.isEmpty()) {
        BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
        BINJS_TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
    }
    return result;
}


/*
 interface FormalParameters : Node {
    FrozenArray<Parameter> items;
    Binding? rest;
 }
*/
template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseFormalParameters()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::FormalParameters) {
        return raiseInvalidKind("FormalParameters", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceFormalParameters(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::FormalParameters);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Items, BinField::Rest };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(items, parseListOfParameter());

    BINJS_MOZ_TRY_DECL(rest, parseOptionalBinding());

    auto result = items;
    if (rest) {
        return raiseError("Rest parameter is not supported in this preview release");
    }
    return result;
}


/*
 interface FunctionExpressionContents : Node {
    bool isFunctionNameCaptured;
    bool isThisCaptured;
    AssertedParameterScope parameterScope;
    FormalParameters params;
    AssertedVarScope bodyScope;
    FunctionBody body;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseFunctionExpressionContents(
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::FunctionExpressionContents) {
        return raiseInvalidKind("FunctionExpressionContents", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceFunctionExpressionContents(start, kind, fields,
        funLength, paramsOut, bodyOut));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceFunctionExpressionContents(const size_t start, const BinKind kind, const BinFields& fields,
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    MOZ_ASSERT(kind == BinKind::FunctionExpressionContents);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[6] = { BinField::IsFunctionNameCaptured, BinField::IsThisCaptured, BinField::ParameterScope, BinField::Params, BinField::BodyScope, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(isFunctionNameCaptured, tokenizer_->readBool());
    // Per spec, isFunctionNameCaptured can be true for anonymous
    // function.  Check isFunctionNameCaptured only for named
    // function.
    if (parseContext_->functionBox()->function()->isNamedLambda() &&
        isFunctionNameCaptured)
    {
        captureFunctionName();
    }
    BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
    // TODO: Use this in BinASTParser::buildFunction.
    (void) isThisCaptured;
    Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
    MOZ_TRY(parseAssertedParameterScope(
        &positionalParams));

    BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
    MOZ_TRY(checkFunctionLength(funLength));
    MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
    MOZ_TRY(parseAssertedVarScope());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    *paramsOut = params;
    *bodyOut = body;
    auto result = Ok();
    return result;
}


/*
 interface FunctionOrMethodContents : Node {
    bool isThisCaptured;
    AssertedParameterScope parameterScope;
    FormalParameters params;
    AssertedVarScope bodyScope;
    FunctionBody body;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseFunctionOrMethodContents(
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::FunctionOrMethodContents) {
        return raiseInvalidKind("FunctionOrMethodContents", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceFunctionOrMethodContents(start, kind, fields,
        funLength, paramsOut, bodyOut));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceFunctionOrMethodContents(const size_t start, const BinKind kind, const BinFields& fields,
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    MOZ_ASSERT(kind == BinKind::FunctionOrMethodContents);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[5] = { BinField::IsThisCaptured, BinField::ParameterScope, BinField::Params, BinField::BodyScope, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
    // TODO: Use this in BinASTParser::buildFunction.
    (void) isThisCaptured;
    Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
    MOZ_TRY(parseAssertedParameterScope(
        &positionalParams));

    BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
    MOZ_TRY(checkFunctionLength(funLength));
    MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
    MOZ_TRY(parseAssertedVarScope());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    *paramsOut = params;
    *bodyOut = body;
    auto result = Ok();
    return result;
}


/*
 interface GetterContents : Node {
    bool isThisCaptured;
    AssertedVarScope bodyScope;
    FunctionBody body;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseGetterContents(
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::GetterContents) {
        return raiseInvalidKind("GetterContents", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceGetterContents(start, kind, fields,
        funLength, paramsOut, bodyOut));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceGetterContents(const size_t start, const BinKind kind, const BinFields& fields,
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    MOZ_ASSERT(kind == BinKind::GetterContents);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::IsThisCaptured, BinField::BodyScope, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
    // TODO: Use this in BinASTParser::buildFunction.
    (void) isThisCaptured;
    MOZ_TRY(parseAssertedVarScope());

    BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    *paramsOut = params;
    *bodyOut = body;
    auto result = Ok();
    return result;
}


/*
 interface IdentifierExpression : Node {
    [IdentifierName] string name;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseIdentifierExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::IdentifierExpression) {
        return raiseInvalidKind("IdentifierExpression", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceIdentifierExpression(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::IdentifierExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Name };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());

    if (!IsIdentifier(name)) {
        return raiseError("Invalid identifier");
    }
    BINJS_TRY(usedNames_.noteUse(cx_, name, parseContext_->scriptId(), parseContext_->innermostScope()->id()));
    BINJS_TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::IfStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Test, BinField::Consequent, BinField::Alternate };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(consequent, parseStatement());

    BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement());

    BINJS_TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LabelledStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Label, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom label(cx_);
    MOZ_TRY_VAR(label, tokenizer_->readAtom());
    if (!IsIdentifier(label)) {
        return raiseError("Invalid identifier");
    }
    ParseContext::LabelStatement stmt(parseContext_, label);
    BINJS_MOZ_TRY_DECL(body, parseStatement());

    BINJS_TRY_DECL(result, factory_.newLabeledStatement(label->asPropertyName(), body, start));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LazyArrowExpressionWithExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LazyArrowExpressionWithFunctionBody)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LazyFunctionDeclaration);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Statement;

    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
    if (isAsync) {
        return raiseError("Async function is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
    if (isGenerator) {
        return raiseError("Generator is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
    // Don't parse the contents until we delazify.

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax, name));

    forceStrictIfNecessary(funbox, directives);

    RootedFunction fun(cx_, funbox->function());

    // TODO: This will become incorrect in the face of ES6 features.
    fun->setArgCount(length);

    auto skipStart = contentsSkip.startOffset();
    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
                                            skipStart, skipStart + contentsSkip.length(),
                                            skipStart, 0, skipStart, ParseGoal::Script));

    if (funbox->strict()) {
        lazy->setStrict();
    }
    lazy->setIsBinAST();
    funbox->function()->initLazyScript(lazy);

    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LazyFunctionExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::Length, BinField::Directives, BinField::ContentsSkip, BinField::Contents };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Expression;

    BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
    if (isAsync) {
        return raiseError("Async function is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
    if (isGenerator) {
        return raiseError("Generator is not supported in this preview release");
    }
    BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());

    BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
    // Don't parse the contents until we delazify.

    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax, name));

    forceStrictIfNecessary(funbox, directives);

    RootedFunction fun(cx_, funbox->function());

    // TODO: This will become incorrect in the face of ES6 features.
    fun->setArgCount(length);

    auto skipStart = contentsSkip.startOffset();
    BINJS_TRY_DECL(lazy, LazyScript::Create(cx_, fun, sourceObject_, parseContext_->closedOverBindingsForLazy(), parseContext_->innerFunctionsForLazy,
                                            skipStart, skipStart + contentsSkip.length(),
                                            skipStart, 0, skipStart, ParseGoal::Script));

    if (funbox->strict()) {
        lazy->setStrict();
    }
    lazy->setIsBinAST();
    funbox->function()->initLazyScript(lazy);

    BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyGetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LazyGetter)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyMethod(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LazyMethod)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazySetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LazySetter)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralBooleanExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Value };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(value, tokenizer_->readBool());

    BINJS_TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (LiteralInfinityExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralNullExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));

    BINJS_TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralNumericExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Value };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(value, tokenizer_->readDouble());

    BINJS_TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralPropertyName);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Value };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom value(cx_);
    MOZ_TRY_VAR(value, tokenizer_->readAtom());

    ParseNode* result;
    uint32_t index;
    if (value->isIndex(&index)) {
        BINJS_TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset())));
    } else {
        BINJS_TRY_VAR(result, factory_.newObjectLiteralPropertyName(value, tokenizer_->pos(start)));
    }
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralRegExpExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Pattern, BinField::Flags };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom pattern(cx_);
    MOZ_TRY_VAR(pattern, tokenizer_->readAtom());
    Chars flags(cx_);
    MOZ_TRY(tokenizer_->readChars(flags));

    RegExpFlag reflags = NoFlags;
    for (auto c : flags) {
        if (c == 'g' && !(reflags & GlobalFlag)) {
            reflags = RegExpFlag(reflags | GlobalFlag);
        } else if (c == 'i' && !(reflags & IgnoreCaseFlag)) {
            reflags = RegExpFlag(reflags | IgnoreCaseFlag);
        } else if (c == 'm' && !(reflags & MultilineFlag)) {
            reflags = RegExpFlag(reflags | MultilineFlag);
        } else if (c == 'y' && !(reflags & StickyFlag)) {
            reflags = RegExpFlag(reflags | StickyFlag);
        } else if (c == 'u' && !(reflags & UnicodeFlag)) {
            reflags = RegExpFlag(reflags | UnicodeFlag);
        } else {
            return raiseError("Invalid regexp flags");
        }
    }


    Rooted<RegExpObject*> reobj(cx_);
    BINJS_TRY_VAR(reobj, RegExpObject::create(cx_,
        pattern,
        reflags,
        TenuredObject));

    BINJS_TRY_DECL(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::LiteralStringExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Value };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    RootedAtom value(cx_);
    MOZ_TRY_VAR(value, tokenizer_->readAtom());

    BINJS_TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (Module)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::NewExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Callee, BinField::Arguments };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(callee, parseExpression());

    BINJS_MOZ_TRY_DECL(arguments, parseArguments());

    BINJS_TRY_DECL(result, factory_.newNewExpression(tokenizer_->pos(start).begin, callee, arguments));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (NewTargetExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ObjectAssignmentTarget)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (ObjectBinding)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ObjectExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Properties };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(properties, parseListOfObjectProperty());

    auto result = properties;
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ReturnStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    if (!parseContext_->isFunctionBox()) {
        // Return statements are permitted only inside functions.
        return raiseInvalidKind("Toplevel Statement", kind);
    }

    parseContext_->functionBox()->usesReturn = true;

    BINJS_MOZ_TRY_DECL(expression, parseOptionalExpression());

    BINJS_TRY_DECL(result, factory_.newReturnStatement(expression, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::Script);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Scope, BinField::Directives, BinField::Statements };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    MOZ_TRY(parseAssertedScriptGlobalScope());

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
    forceStrictIfNecessary(parseContext_->sc(), directives);
    BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());

    MOZ_TRY(checkClosedVars(parseContext_->varScope())); MOZ_TRY(prependDirectivesToBody(/* body = */ statements, directives)); auto result = statements;
    return result;
}


/*
 interface SetterContents : Node {
    bool isThisCaptured;
    AssertedParameterScope parameterScope;
    Parameter param;
    AssertedVarScope bodyScope;
    FunctionBody body;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseSetterContents(
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::SetterContents) {
        return raiseInvalidKind("SetterContents", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceSetterContents(start, kind, fields,
        funLength, paramsOut, bodyOut));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceSetterContents(const size_t start, const BinKind kind, const BinFields& fields,
        uint32_t funLength,
        ListNode** paramsOut,
        ListNode** bodyOut)
{
    MOZ_ASSERT(kind == BinKind::SetterContents);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[5] = { BinField::IsThisCaptured, BinField::ParameterScope, BinField::Param, BinField::BodyScope, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
    // TODO: Use this in BinASTParser::buildFunction.
    (void) isThisCaptured;
    Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
    MOZ_TRY(parseAssertedParameterScope(
        &positionalParams));

    BINJS_MOZ_TRY_DECL(param, parseParameter());
    BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
    factory_.addList(params, param);
    MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
    MOZ_TRY(parseAssertedVarScope());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    *paramsOut = params;
    *bodyOut = body;
    auto result = Ok();
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ShorthandProperty);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Name };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(name, parseIdentifierExpression());

    MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
    MOZ_ASSERT(!factory_.isUsableAsObjectPropertyName(name));
    BINJS_TRY_DECL(propName, factory_.newObjectLiteralPropertyName(name->template as<NameNode>().name(), tokenizer_->pos(start)));

    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(propName, name, AccessorType::None));
    result->setKind(ParseNodeKind::Shorthand);
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (SpreadElement)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Object, BinField::Property };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    size_t nameStart;

    BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
    RootedAtom property(cx_);
    {
        nameStart = tokenizer_->offset();
        MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());

    }

    BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Object, BinField::Property };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    size_t nameStart;

    BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
    RootedAtom property(cx_);
    {
        nameStart = tokenizer_->offset();
        MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());

    }

    BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (Super)");
}


/*
 interface SwitchCase : Node {
    Expression test;
    FrozenArray<Statement> consequent;
 }
*/
template<typename Tok> JS::Result<CaseClause*>
BinASTParser<Tok>::parseSwitchCase()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::SwitchCase) {
        return raiseInvalidKind("SwitchCase", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchCase(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<CaseClause*>
BinASTParser<Tok>::parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::SwitchCase);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Test, BinField::Consequent };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());

    BINJS_TRY_DECL(result, factory_.newCaseOrDefault(start, test, consequent));
    return result;
}


/*
 interface SwitchDefault : Node {
    FrozenArray<Statement> consequent;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSwitchDefault()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::SwitchDefault) {
        return raiseInvalidKind("SwitchDefault", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchDefault(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::SwitchDefault);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Consequent };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());

    BINJS_TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::SwitchStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Discriminant, BinField::Cases };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(discriminant, parseExpression());

    BINJS_MOZ_TRY_DECL(cases, parseListOfSwitchCase());

    BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
    BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope, false));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::SwitchStatementWithDefault);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[4] = { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(discriminant, parseExpression());

    BINJS_MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase());

    BINJS_MOZ_TRY_DECL(defaultCase, parseSwitchDefault());

    BINJS_MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase());

    // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase`
    auto cases = preDefaultCases;
    factory_.addList(cases, defaultCase);
    ParseNode* iter = postDefaultCases->head();
    while (iter) {
        ParseNode* next = iter->pn_next;
        factory_.addList(cases, iter);
        iter = next;
    }
    BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
    BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope, true));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (TemplateExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ThisExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));

    if (parseContext_->isFunctionBox()) {
        parseContext_->functionBox()->usesThis = true;
    }

    TokenPos pos = tokenizer_->pos(start);
    ParseNode* thisName(nullptr);
    if (parseContext_->sc()->thisBinding() == ThisBinding::Function) {
        HandlePropertyName dotThis = cx_->names().dotThis;
        BINJS_TRY(usedNames_.noteUse(cx_, dotThis, parseContext_->scriptId(), parseContext_->innermostScope()->id()));
        BINJS_TRY_VAR(thisName, factory_.newName(dotThis, pos, cx_));
    }

    BINJS_TRY_DECL(result, factory_.newThisLiteral(pos, thisName));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::ThrowStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[1] = { BinField::Expression };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(expression, parseExpression());

    BINJS_TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::TryCatchStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Body, BinField::CatchClause };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseNode* body;
    {
        ParseContext::Statement stmt(parseContext_, StatementKind::Try);
        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
        BINJS_TRY(scope.init(parseContext_));
        MOZ_TRY_VAR(body, parseBlock());

    }

    BINJS_MOZ_TRY_DECL(catchClause, parseCatchClause());

    BINJS_TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, /* finallyBlock = */ nullptr));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::TryFinallyStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::Body, BinField::CatchClause, BinField::Finalizer };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseNode* body;
    {
        ParseContext::Statement stmt(parseContext_, StatementKind::Try);
        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
        BINJS_TRY(scope.init(parseContext_));
        MOZ_TRY_VAR(body, parseBlock());

    }

    BINJS_MOZ_TRY_DECL(catchClause, parseOptionalCatchClause());
    ParseNode* finalizer;
    {
        ParseContext::Statement stmt(parseContext_, StatementKind::Finally);
        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
        BINJS_TRY(scope.init(parseContext_));
        MOZ_TRY_VAR(finalizer, parseBlock());

    }

    BINJS_TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, finalizer));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::UnaryExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Operator, BinField::Operand };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(operator_, parseUnaryOperator());

    BINJS_MOZ_TRY_DECL(operand, parseExpression());

    ParseNodeKind pnk;
    switch (operator_) {
      case UnaryOperator::Minus:
        pnk = ParseNodeKind::Neg;
        break;
      case UnaryOperator::Plus:
        pnk = ParseNodeKind::Pos;
        break;
      case UnaryOperator::Not:
        pnk = ParseNodeKind::Not;
        break;
      case UnaryOperator::BitNot:
        pnk = ParseNodeKind::BitNot;
        break;
      case UnaryOperator::Typeof: {
        if (operand->isKind(ParseNodeKind::Name)) {
            pnk = ParseNodeKind::TypeOfName;
        } else {
            pnk = ParseNodeKind::TypeOfExpr;
        }
        break;
      }
      case UnaryOperator::Void:
        pnk = ParseNodeKind::Void;
        break;
      case UnaryOperator::Delete: {
        switch (operand->getKind()) {
          case ParseNodeKind::Name:
            operand->setOp(JSOP_DELNAME);
            pnk = ParseNodeKind::DeleteName;
            break;
          case ParseNodeKind::Dot:
            pnk = ParseNodeKind::DeleteProp;
            break;
          case ParseNodeKind::Elem:
            pnk = ParseNodeKind::DeleteElem;
            break;
          default:
            pnk = ParseNodeKind::DeleteExpr;
        }
        break;
      }
    }
    BINJS_TRY_DECL(result, factory_.newUnary(pnk, start, operand));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::UpdateExpression);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::IsPrefix, BinField::Operator, BinField::Operand };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(isPrefix, tokenizer_->readBool());

    BINJS_MOZ_TRY_DECL(operator_, parseUpdateOperator());

    BINJS_MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget());

    ParseNodeKind pnk;
    switch (operator_) {
      case UpdateOperator::Incr:
        pnk = isPrefix ? ParseNodeKind::PreIncrement
                       : ParseNodeKind::PostIncrement;
        break;
      case UpdateOperator::Decr:
        pnk = isPrefix ? ParseNodeKind::PreDecrement
                       : ParseNodeKind::PostDecrement;
        break;
    }
    BINJS_TRY_DECL(result, factory_.newUnary(pnk, start, operand));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::VariableDeclaration);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Kind, BinField::Declarators };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    AutoVariableDeclarationKind kindGuard(this);

    BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
    // Restored by `kindGuard`.
    variableDeclarationKind_ = kind_;
    BINJS_MOZ_TRY_DECL(declarators, parseListOfVariableDeclarator());

    // By specification, the list may not be empty.
    if (declarators->empty()) {
        return raiseEmpty("VariableDeclaration");
    }

    ParseNodeKind pnk;
    switch (kind_) {
      case VariableDeclarationKind::Var:
        pnk = ParseNodeKind::Var;
        break;
      case VariableDeclarationKind::Let:
        return raiseError("Let is not supported in this preview release");
      case VariableDeclarationKind::Const:
        return raiseError("Const is not supported in this preview release");
    }
    declarators->setKind(pnk);
    auto result = declarators;
    return result;
}


/*
 interface VariableDeclarator : Node {
    Binding binding;
    Expression? init;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseVariableDeclarator()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    if (kind != BinKind::VariableDeclarator) {
        return raiseInvalidKind("VariableDeclarator", kind);
    }
    const auto start = tokenizer_->offset();
    BINJS_MOZ_TRY_DECL(result, parseInterfaceVariableDeclarator(start, kind, fields));
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::VariableDeclarator);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Binding, BinField::Init };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(binding, parseBinding());

    BINJS_MOZ_TRY_DECL(init, parseOptionalExpression());

    ParseNode* result;
    if (binding->isKind(ParseNodeKind::Name)) {
        // `var foo [= bar]``
        NameNode* bindingNameNode = &binding->template as<NameNode>();
        MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
        result = bindingNameNode;
        if (init) {
            BINJS_TRY(factory_.finishInitializerAssignment(bindingNameNode, init));
        }
    } else {
        // `var pattern = bar`
        if (!init) {
            // Here, `init` is required.
            return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init);
        }

        MOZ_CRASH("Unimplemented: AssertedScope check for BindingPattern variable declaration");
        BINJS_TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, binding, init));
    }
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::WhileStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Test, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop);

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(body, parseStatement());

    BINJS_TRY_DECL(result, factory_.newWhileStatement(start, test, body));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    MOZ_ASSERT(kind == BinKind::WithStatement);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[2] = { BinField::Object, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(object, parseExpression());

    ParseContext::Statement stmt(parseContext_, StatementKind::With);
    BINJS_MOZ_TRY_DECL(body, parseStatement());

    parseContext_->sc()->setBindingsAccessedDynamically();
    BINJS_TRY_DECL(result, factory_.newWithStatement(start, object, body));
    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (YieldExpression)");
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    return raiseError("FIXME: Not implemented yet in this preview release (YieldStarExpression)");
}



// ----- String enums (autogenerated, by lexicographical order)
/*
enum AssertedDeclaredKind {
    "var",
    "non-const lexical",
    "const lexical"
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
BinASTParser<Tok>::parseAssertedDeclaredKind()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
        return AssertedDeclaredKind::Var;
    case BinVariant::AssertedDeclaredKindNonConstLexical:
        return AssertedDeclaredKind::NonConstLexical;
    case BinVariant::AssertedDeclaredKindConstLexical:
        return AssertedDeclaredKind::ConstLexical;
      default:
        return raiseInvalidVariant("AssertedDeclaredKind", variant);
    }
}

/*
enum BinaryOperator {
    ",",
    "||",
    "&&",
    "|",
    "^",
    "&",
    "==",
    "!=",
    "===",
    "!==",
    "<",
    "<=",
    ">",
    ">=",
    "in",
    "instanceof",
    "<<",
    ">>",
    ">>>",
    "+",
    "-",
    "*",
    "/",
    "%",
    "**"
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::BinaryOperator>
BinASTParser<Tok>::parseBinaryOperator()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::BinaryOperatorComma:
        return BinaryOperator::Comma;
    case BinVariant::BinaryOperatorLogicalOr:
        return BinaryOperator::LogicalOr;
    case BinVariant::BinaryOperatorLogicalAnd:
        return BinaryOperator::LogicalAnd;
    case BinVariant::BinaryOperatorBitOr:
        return BinaryOperator::BitOr;
    case BinVariant::BinaryOperatorBitXor:
        return BinaryOperator::BitXor;
    case BinVariant::BinaryOperatorBitAnd:
        return BinaryOperator::BitAnd;
    case BinVariant::BinaryOperatorEq:
        return BinaryOperator::Eq;
    case BinVariant::BinaryOperatorNeq:
        return BinaryOperator::Neq;
    case BinVariant::BinaryOperatorStrictEq:
        return BinaryOperator::StrictEq;
    case BinVariant::BinaryOperatorStrictNeq:
        return BinaryOperator::StrictNeq;
    case BinVariant::BinaryOperatorLessThan:
        return BinaryOperator::LessThan;
    case BinVariant::BinaryOperatorLeqThan:
        return BinaryOperator::LeqThan;
    case BinVariant::BinaryOperatorGreaterThan:
        return BinaryOperator::GreaterThan;
    case BinVariant::BinaryOperatorGeqThan:
        return BinaryOperator::GeqThan;
    case BinVariant::BinaryOperatorIn:
        return BinaryOperator::In;
    case BinVariant::BinaryOperatorInstanceof:
        return BinaryOperator::Instanceof;
    case BinVariant::BinaryOperatorLsh:
        return BinaryOperator::Lsh;
    case BinVariant::BinaryOperatorRsh:
        return BinaryOperator::Rsh;
    case BinVariant::BinaryOperatorUrsh:
        return BinaryOperator::Ursh;
    case BinVariant::BinaryOperatorOrUnaryOperatorPlus:
        return BinaryOperator::Plus;
    case BinVariant::BinaryOperatorOrUnaryOperatorMinus:
        return BinaryOperator::Minus;
    case BinVariant::BinaryOperatorMul:
        return BinaryOperator::Mul;
    case BinVariant::BinaryOperatorDiv:
        return BinaryOperator::Div;
    case BinVariant::BinaryOperatorMod:
        return BinaryOperator::Mod;
    case BinVariant::BinaryOperatorPow:
        return BinaryOperator::Pow;
      default:
        return raiseInvalidVariant("BinaryOperator", variant);
    }
}

/*
enum CompoundAssignmentOperator {
    "+=",
    "-=",
    "*=",
    "/=",
    "%=",
    "**=",
    "<<=",
    ">>=",
    ">>>=",
    "|=",
    "^=",
    "&="
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
BinASTParser<Tok>::parseCompoundAssignmentOperator()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::CompoundAssignmentOperatorPlusAssign:
        return CompoundAssignmentOperator::PlusAssign;
    case BinVariant::CompoundAssignmentOperatorMinusAssign:
        return CompoundAssignmentOperator::MinusAssign;
    case BinVariant::CompoundAssignmentOperatorMulAssign:
        return CompoundAssignmentOperator::MulAssign;
    case BinVariant::CompoundAssignmentOperatorDivAssign:
        return CompoundAssignmentOperator::DivAssign;
    case BinVariant::CompoundAssignmentOperatorModAssign:
        return CompoundAssignmentOperator::ModAssign;
    case BinVariant::CompoundAssignmentOperatorPowAssign:
        return CompoundAssignmentOperator::PowAssign;
    case BinVariant::CompoundAssignmentOperatorLshAssign:
        return CompoundAssignmentOperator::LshAssign;
    case BinVariant::CompoundAssignmentOperatorRshAssign:
        return CompoundAssignmentOperator::RshAssign;
    case BinVariant::CompoundAssignmentOperatorUrshAssign:
        return CompoundAssignmentOperator::UrshAssign;
    case BinVariant::CompoundAssignmentOperatorBitOrAssign:
        return CompoundAssignmentOperator::BitOrAssign;
    case BinVariant::CompoundAssignmentOperatorBitXorAssign:
        return CompoundAssignmentOperator::BitXorAssign;
    case BinVariant::CompoundAssignmentOperatorBitAndAssign:
        return CompoundAssignmentOperator::BitAndAssign;
      default:
        return raiseInvalidVariant("CompoundAssignmentOperator", variant);
    }
}

/*
enum UnaryOperator {
    "+",
    "-",
    "!",
    "~",
    "typeof",
    "void",
    "delete"
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::UnaryOperator>
BinASTParser<Tok>::parseUnaryOperator()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::BinaryOperatorOrUnaryOperatorPlus:
        return UnaryOperator::Plus;
    case BinVariant::BinaryOperatorOrUnaryOperatorMinus:
        return UnaryOperator::Minus;
    case BinVariant::UnaryOperatorNot:
        return UnaryOperator::Not;
    case BinVariant::UnaryOperatorBitNot:
        return UnaryOperator::BitNot;
    case BinVariant::UnaryOperatorTypeof:
        return UnaryOperator::Typeof;
    case BinVariant::UnaryOperatorVoid:
        return UnaryOperator::Void;
    case BinVariant::UnaryOperatorDelete:
        return UnaryOperator::Delete;
      default:
        return raiseInvalidVariant("UnaryOperator", variant);
    }
}

/*
enum UpdateOperator {
    "++",
    "--"
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::UpdateOperator>
BinASTParser<Tok>::parseUpdateOperator()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::UpdateOperatorIncr:
        return UpdateOperator::Incr;
    case BinVariant::UpdateOperatorDecr:
        return UpdateOperator::Decr;
      default:
        return raiseInvalidVariant("UpdateOperator", variant);
    }
}

/*
enum VariableDeclarationKind {
    "var",
    "let",
    "const"
};
*/
template<typename Tok> JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
BinASTParser<Tok>::parseVariableDeclarationKind()
{
    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());

    switch (variant) {
    case BinVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
        return VariableDeclarationKind::Var;
    case BinVariant::VariableDeclarationKindLet:
        return VariableDeclarationKind::Let;
    case BinVariant::VariableDeclarationKindConst:
        return VariableDeclarationKind::Const;
      default:
        return raiseInvalidVariant("VariableDeclarationKind", variant);
    }
}



// ----- Lists (autogenerated, by lexicographical order)

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArguments()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::Arguments, tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
        factory_.addList(/* list = */ result, /* kid = */ item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseFunctionBody()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseStatement());
        factory_.addStatementToList(result, item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseListOfAssertedBoundName(
        AssertedScopeKind scopeKind)
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    (void) start;
    auto result = Ok();

    for (uint32_t i = 0; i < length; ++i) {
        MOZ_TRY(parseAssertedBoundName(
            scopeKind));
        // Nothing to do here.
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseListOfAssertedDeclaredName(
        AssertedScopeKind scopeKind)
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    (void) start;
    auto result = Ok();

    for (uint32_t i = 0; i < length; ++i) {
        MOZ_TRY(parseAssertedDeclaredName(
            scopeKind));
        // Nothing to do here.
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseListOfAssertedMaybePositionalParameterName(
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    (void) start;
    auto result = Ok();
    // This list contains also destructuring parameters, and the number of
    // list items can be greater than the actual parameters, or more than
    // ARGNO_LIMIT even if the number of parameters fits into ARGNO_LIMIT.
    // Also, the number of parameters can be greater than this list's length
    // if one of destructuring parameter is empty.
    //
    // We resize `positionalParams` vector on demand, to keep the vector
    // length match to the known maximum positional parameter index + 1.

    for (uint32_t i = 0; i < length; ++i) {
        MOZ_TRY(parseAssertedMaybePositionalParameterName(
            scopeKind, positionalParams));
        // Nothing to do here.
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfDirective()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseDirective());
        factory_.addStatementToList(result, item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfObjectProperty()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newObjectLiteral(start));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseObjectProperty());
        if (!item->isConstant())
            result->setHasNonConstInitializer();
        result->appendWithoutOrderAssumption(item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newArrayLiteral(start));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseOptionalSpreadElementOrExpression());
        if (item) {
            factory_.addArrayElement(result, item); // Infallible.
        } else {
            BINJS_TRY(factory_.addElision(result, tokenizer_->pos(start)));
        }
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfParameter()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseParameter());
        factory_.addList(/* list = */ result, /* kid = */ item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfStatement()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseStatement());
        factory_.addStatementToList(result, item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfSwitchCase()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseSwitchCase());
        factory_.addCaseStatementToList(result, item);
    }

    MOZ_TRY(guard.done());
    return result;
}

template<typename Tok> JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfVariableDeclarator()
{
    uint32_t length;
    AutoList guard(*tokenizer_);

    const auto start = tokenizer_->offset();
    MOZ_TRY(tokenizer_->enterList(length, guard));
    BINJS_TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/,
        tokenizer_->pos(start)));

    for (uint32_t i = 0; i < length; ++i) {
        BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator());
        result->appendWithoutOrderAssumption(item);
    }

    MOZ_TRY(guard.done());
    return result;
}


    // ----- Default values (by lexicographical order)
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalBinding()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalBindingIdentifier()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else if (kind == BinKind::BindingIdentifier) {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
    } else {
        return raiseInvalidKind("BindingIdentifier", kind);
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<LexicalScopeNode*>
BinASTParser<Tok>::parseOptionalCatchClause()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    LexicalScopeNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else if (kind == BinKind::CatchClause) {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields));
    } else {
        return raiseInvalidKind("CatchClause", kind);
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalSpreadElementOrExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
    }
    MOZ_TRY(guard.done());

    return result;
}

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
    ParseNode* result;
    if (kind == BinKind::_Null) {
        result = nullptr;
    } else {
        const auto start = tokenizer_->offset();
        MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(start, kind, fields));
    }
    MOZ_TRY(guard.done());

    return result;
}



// Force class instantiation.
// This ensures that the symbols are built, without having to export all our
// code (and its baggage of #include and macros) in the header.
template class BinASTParser<BinTokenReaderMultipart>;
template class BinASTParser<BinTokenReaderTester>;

} // namespace frontend
} // namespace js