js/src/frontend/BinSource-auto.cpp
author Eric Faust <efaustbmo@gmail.com>
Mon, 01 Oct 2018 20:41:48 -0700
changeset 494879 b3dbe062fb3dcdbb33067352cc80ab85fd0249a6
parent 494874 275f7949148be2d20a45653e44a0bf4b4ae09a44
child 494881 63ea63571271f031dc457f1b1b7519ec8bf3e3de
permissions -rw-r--r--
Bug 1459067 - Part 2: Implement LazyFunctionExpression and LazyFunctionDeclaration for BinAST. (r=arai)

// 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/Parser.h"
#include "frontend/SharedContext.h"

#include "vm/RegExpObject.h"

#include "frontend/ParseContext-inl.h"
#include "frontend/ParseNode-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.
/*
ArrowExpression ::= EagerArrowExpressionWithExpression
    EagerArrowExpressionWithFunctionBody
    LazyArrowExpressionWithExpression
    LazyArrowExpressionWithFunctionBody
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrowExpression()
{
    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, parseSumArrowExpression(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      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::LazyArrowExpressionWithExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(start, kind, fields));
        break;
      case BinKind::LazyArrowExpressionWithFunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ArrowExpression", kind);
    }
    return result;
}

/*
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:
        MOZ_TRY_VAR(result, parseInterfaceAssertedParameterName(start, kind, fields,
            scopeKind, positionalParams));
        break;
      case BinKind::AssertedPositionalParameterName:
        MOZ_TRY_VAR(result, parseInterfaceAssertedPositionalParameterName(start, kind, fields,
            scopeKind, positionalParams));
        break;
      case BinKind::AssertedRestParameterName:
        MOZ_TRY_VAR(result, parseInterfaceAssertedRestParameterName(start, kind, fields,
            scopeKind, positionalParams));
        break;
      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;
}

/*
AssignmentTargetOrAssignmentTargetWithInitializer ::= ArrayAssignmentTarget
    AssignmentTargetIdentifier
    AssignmentTargetWithInitializer
    ComputedMemberAssignmentTarget
    ObjectAssignmentTarget
    StaticMemberAssignmentTarget
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTargetOrAssignmentTargetWithInitializer()
{
    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, parseSumAssignmentTargetOrAssignmentTargetWithInitializer(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumAssignmentTargetOrAssignmentTargetWithInitializer(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::AssignmentTargetWithInitializer:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetWithInitializer(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("AssignmentTargetOrAssignmentTargetWithInitializer", kind);
    }
    return result;
}

/*
AssignmentTargetPattern ::= ArrayAssignmentTarget
    ObjectAssignmentTarget
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTargetPattern()
{
    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, parseSumAssignmentTargetPattern(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumAssignmentTargetPattern(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::ObjectAssignmentTarget:
        MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("AssignmentTargetPattern", kind);
    }
    return result;
}

/*
AssignmentTargetProperty ::= AssignmentTargetPropertyIdentifier
    AssignmentTargetPropertyProperty
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTargetProperty()
{
    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, parseSumAssignmentTargetProperty(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::AssignmentTargetPropertyIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields));
        break;
      case BinKind::AssignmentTargetPropertyProperty:
        MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("AssignmentTargetProperty", 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;
}

/*
BindingOrBindingWithInitializer ::= ArrayBinding
    BindingIdentifier
    BindingWithInitializer
    ObjectBinding
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBindingOrBindingWithInitializer()
{
    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, parseSumBindingOrBindingWithInitializer(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumBindingOrBindingWithInitializer(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::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("BindingOrBindingWithInitializer", kind);
    }
    return result;
}

/*
BindingPattern ::= ArrayBinding
    ObjectBinding
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBindingPattern()
{
    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, parseSumBindingPattern(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumBindingPattern(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::ObjectBinding:
        MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("BindingPattern", kind);
    }
    return result;
}

/*
BindingProperty ::= BindingPropertyIdentifier
    BindingPropertyProperty
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBindingProperty()
{
    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, parseSumBindingProperty(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::BindingPropertyIdentifier:
        MOZ_TRY_VAR(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields));
        break;
      case BinKind::BindingPropertyProperty:
        MOZ_TRY_VAR(result, parseInterfaceBindingPropertyProperty(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("BindingProperty", kind);
    }
    return result;
}

/*
ExportDeclaration ::= Export
    ExportAllFrom
    ExportDefault
    ExportFrom
    ExportLocals
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportDeclaration()
{
    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, parseSumExportDeclaration(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::Export:
        MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields));
        break;
      case BinKind::ExportAllFrom:
        MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields));
        break;
      case BinKind::ExportDefault:
        MOZ_TRY_VAR(result, parseInterfaceExportDefault(start, kind, fields));
        break;
      case BinKind::ExportFrom:
        MOZ_TRY_VAR(result, parseInterfaceExportFrom(start, kind, fields));
        break;
      case BinKind::ExportLocals:
        MOZ_TRY_VAR(result, parseInterfaceExportLocals(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ExportDeclaration", 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;
}

/*
ExpressionOrTemplateElement ::= 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
    TemplateElement
    TemplateExpression
    ThisExpression
    UnaryExpression
    UpdateExpression
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExpressionOrTemplateElement()
{
    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, parseSumExpressionOrTemplateElement(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumExpressionOrTemplateElement(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::TemplateElement:
        MOZ_TRY_VAR(result, parseInterfaceTemplateElement(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("ExpressionOrTemplateElement", 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;
}

/*
FunctionDeclaration ::= EagerFunctionDeclaration
    LazyFunctionDeclaration
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseFunctionDeclaration()
{
    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, parseSumFunctionDeclaration(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::EagerFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::LazyFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("FunctionDeclaration", kind);
    }
    return result;
}

/*
FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassDeclaration
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpressionWithExpression
    EagerArrowExpressionWithFunctionBody
    EagerFunctionDeclaration
    EagerFunctionExpression
    IdentifierExpression
    LazyArrowExpressionWithExpression
    LazyArrowExpressionWithFunctionBody
    LazyFunctionDeclaration
    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>::parseFunctionDeclarationOrClassDeclarationOrExpression()
{
    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, parseSumFunctionDeclarationOrClassDeclarationOrExpression(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrExpression(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::ClassDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(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::EagerFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(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::LazyFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(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("FunctionDeclarationOrClassDeclarationOrExpression", kind);
    }
    return result;
}

/*
FunctionDeclarationOrClassDeclarationOrVariableDeclaration ::= ClassDeclaration
    EagerFunctionDeclaration
    LazyFunctionDeclaration
    VariableDeclaration
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration()
{
    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, parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::ClassDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
        break;
      case BinKind::EagerFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::LazyFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::VariableDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrVariableDeclaration", kind);
    }
    return result;
}

/*
FunctionExpression ::= EagerFunctionExpression
    LazyFunctionExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseFunctionExpression()
{
    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, parseSumFunctionExpression(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::LazyFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("FunctionExpression", kind);
    }
    return result;
}

/*
Getter ::= EagerGetter
    LazyGetter
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseGetter()
{
    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, parseSumGetter(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumGetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::EagerGetter:
        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
        break;
      case BinKind::LazyGetter:
        MOZ_TRY_VAR(result, parseInterfaceLazyGetter(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Getter", kind);
    }
    return result;
}

/*
ImportDeclaration ::= Import
    ImportNamespace
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseImportDeclaration()
{
    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, parseSumImportDeclaration(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::Import:
        MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields));
        break;
      case BinKind::ImportNamespace:
        MOZ_TRY_VAR(result, parseInterfaceImportNamespace(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ImportDeclaration", kind);
    }
    return result;
}

/*
ImportDeclarationOrExportDeclarationOrStatement ::= Block
    BreakStatement
    ClassDeclaration
    ContinueStatement
    DebuggerStatement
    DoWhileStatement
    EagerFunctionDeclaration
    EmptyStatement
    Export
    ExportAllFrom
    ExportDefault
    ExportFrom
    ExportLocals
    ExpressionStatement
    ForInStatement
    ForOfStatement
    ForStatement
    IfStatement
    Import
    ImportNamespace
    LabelledStatement
    LazyFunctionDeclaration
    ReturnStatement
    SwitchStatement
    SwitchStatementWithDefault
    ThrowStatement
    TryCatchStatement
    TryFinallyStatement
    VariableDeclaration
    WhileStatement
    WithStatement
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseImportDeclarationOrExportDeclarationOrStatement()
{
    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, parseSumImportDeclarationOrExportDeclarationOrStatement(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumImportDeclarationOrExportDeclarationOrStatement(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::Export:
        MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields));
        break;
      case BinKind::ExportAllFrom:
        MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields));
        break;
      case BinKind::ExportDefault:
        MOZ_TRY_VAR(result, parseInterfaceExportDefault(start, kind, fields));
        break;
      case BinKind::ExportFrom:
        MOZ_TRY_VAR(result, parseInterfaceExportFrom(start, kind, fields));
        break;
      case BinKind::ExportLocals:
        MOZ_TRY_VAR(result, parseInterfaceExportLocals(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::Import:
        MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields));
        break;
      case BinKind::ImportNamespace:
        MOZ_TRY_VAR(result, parseInterfaceImportNamespace(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("ImportDeclarationOrExportDeclarationOrStatement", kind);
    }
    return result;
}

/*
IterationStatement ::= DoWhileStatement
    ForInStatement
    ForOfStatement
    ForStatement
    WhileStatement
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseIterationStatement()
{
    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, parseSumIterationStatement(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::DoWhileStatement:
        MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(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::WhileStatement:
        MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("IterationStatement", kind);
    }
    return result;
}

/*
Literal ::= LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralStringExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseLiteral()
{
    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, parseSumLiteral(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      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::LiteralStringExpression:
        MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Literal", kind);
    }
    return result;
}

/*
Method ::= EagerMethod
    LazyMethod
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseMethod()
{
    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, parseSumMethod(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumMethod(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::EagerMethod:
        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
        break;
      case BinKind::LazyMethod:
        MOZ_TRY_VAR(result, parseInterfaceLazyMethod(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Method", kind);
    }
    return result;
}

/*
MethodDefinition ::= EagerGetter
    EagerMethod
    EagerSetter
    LazyGetter
    LazyMethod
    LazySetter
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseMethodDefinition()
{
    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, parseSumMethodDefinition(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      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;
      default:
        return raiseInvalidKind("MethodDefinition", 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;
}

/*
Setter ::= EagerSetter
    LazySetter
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSetter()
{
    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, parseSumSetter(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumSetter(const size_t start, const BinKind kind, const BinFields& fields)
{
    ParseNode* result;
    switch (kind) {
      case BinKind::EagerSetter:
        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
        break;
      case BinKind::LazySetter:
        MOZ_TRY_VAR(result, parseInterfaceLazySetter(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Setter", 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;
}

/*
VariableDeclarationOrExpression ::= 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
    VariableDeclaration
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseVariableDeclarationOrExpression()
{
    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, parseSumVariableDeclarationOrExpression(start, kind, fields));

    MOZ_TRY(guard.done());
    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.

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

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

    return result;
}

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


/*
 interface ArrayAssignmentTarget : Node {
    FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer)> elements;
    AssignmentTarget? rest;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrayAssignmentTarget()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 (ArrayAssignmentTarget)");
}


/*
 interface ArrayBinding : Node {
    FrozenArray<(Binding or BindingWithInitializer)?> elements;
    Binding? rest;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrayBinding()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 (ArrayBinding)");
}


/*
 interface ArrayExpression : Node {
    FrozenArray<(SpreadElement or Expression)?> elements;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrayExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 ArrowExpressionContentsWithExpression : Node {
    AssertedParameterScope parameterScope;
    FormalParameters params;
    AssertedVarScope bodyScope;
    Expression body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrowExpressionContentsWithExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ArrowExpressionContentsWithFunctionBody : Node {
    AssertedParameterScope parameterScope;
    FormalParameters params;
    AssertedVarScope bodyScope;
    FunctionBody body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseArrowExpressionContentsWithFunctionBody()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 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 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)

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

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

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

    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));
    auto result = Ok();
    return result;
}


/*
 interface AssertedParameterName : Node {
    IdentifierName name;
    bool isCaptured;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedParameterName(
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedParameterName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    MOZ_ASSERT(kind == BinKind::AssertedParameterName);
    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)

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

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


/*
 interface AssertedPositionalParameterName : Node {
    unsigned long index;
    IdentifierName name;
    bool isCaptured;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedPositionalParameterName(
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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)

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

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->readAtom());
    // FIXME: The following checks should be performed inside
    // checkPositionalParameterIndices to match the spec's order
    // (bug 1490976).
    if (index >= positionalParams.get().length()) {
        return raiseError("AssertedPositionalParameterName.length out of range");
    }
    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));
    auto result = Ok();
    return result;
}


/*
 interface AssertedRestParameterName : Node {
    IdentifierName name;
    bool isCaptured;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedRestParameterName(
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseInterfaceAssertedRestParameterName(const size_t start, const BinKind kind, const BinFields& fields,
        AssertedScopeKind scopeKind,
        MutableHandle<GCVector<JSAtom*>> positionalParams)
{
    MOZ_ASSERT(kind == BinKind::AssertedRestParameterName);
    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)

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

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


/*
 interface AssignmentExpression : Node {
    AssignmentTarget binding;
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface AssignmentTargetIdentifier : Node {
    Identifier name;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTargetIdentifier()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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_->readAtom());

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


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

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

    return result;
}

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


/*
 interface AssignmentTargetPropertyProperty : Node {
    PropertyName name;
    (AssignmentTarget or AssignmentTargetWithInitializer) binding;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAssignmentTargetPropertyProperty()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


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

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

    return result;
}

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


/*
 interface AwaitExpression : Node {
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseAwaitExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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 (AwaitExpression)");
}


/*
 interface BinaryExpression : Node {
    BinaryOperator operator;
    Expression left;
    Expression right;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBinaryExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 {
    Identifier 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_->readAtom());

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


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

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

    return result;
}

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


/*
 interface BindingPropertyProperty : Node {
    PropertyName name;
    (Binding or BindingWithInitializer) binding;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBindingPropertyProperty()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


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

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

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


/*
 interface BreakStatement : Node {
    Label? label;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseBreakStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface CallExpression : Node {
    (Expression or Super) callee;
    Arguments arguments;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseCallExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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(callee->name())
         && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
            // 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;
}


/*
 interface ClassDeclaration : Node {
    BindingIdentifier name;
    Expression? super;
    FrozenArray<ClassElement> elements;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseClassDeclaration()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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 (ClassDeclaration)");
}


/*
 interface ClassElement : Node {
    bool isStatic;
    MethodDefinition method;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseClassElement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ClassExpression : Node {
    BindingIdentifier? name;
    Expression? super;
    FrozenArray<ClassElement> elements;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseClassExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 (ClassExpression)");
}


/*
 interface CompoundAssignmentExpression : Node {
    CompoundAssignmentOperator operator;
    SimpleAssignmentTarget binding;
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseCompoundAssignmentExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ComputedMemberAssignmentTarget : Node {
    (Expression or Super) object;
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseComputedMemberAssignmentTarget()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface ComputedMemberExpression : Node {
    (Expression or Super) object;
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseComputedMemberExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface ComputedPropertyName : Node {
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseComputedPropertyName()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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 (ComputedPropertyName)");
}


/*
 interface ConditionalExpression : Node {
    Expression test;
    Expression consequent;
    Expression alternate;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseConditionalExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ContinueStatement : Node {
    Label? label;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseContinueStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface DataProperty : Node {
    PropertyName name;
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseDataProperty()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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

    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));
    return result;
}


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

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

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


/*
 interface DoWhileStatement : Node {
    Expression test;
    Statement body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseDoWhileStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface EagerArrowExpressionWithExpression : Node {
    bool isAsync;
    unsigned long length;
    ArrowExpressionContentsWithExpression contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerArrowExpressionWithExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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 (EagerArrowExpressionWithExpression)");
}


/*
 interface EagerArrowExpressionWithFunctionBody : Node {
    bool isAsync;
    unsigned long length;
    FrozenArray<Directive> directives;
    ArrowExpressionContentsWithFunctionBody contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerArrowExpressionWithFunctionBody()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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 (EagerArrowExpressionWithFunctionBody)");
}


/*
 interface EagerFunctionDeclaration : Node {
    bool isAsync;
    bool isGenerator;
    BindingIdentifier name;
    unsigned long length;
    FrozenArray<Directive> directives;
    FunctionOrMethodContents contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerFunctionDeclaration()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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

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

    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* tmpBody;
    MOZ_TRY(parseFunctionOrMethodContents(
        length, &params, &tmpBody));
    BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
    BINJS_TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
    BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));
    return result;
}


/*
 interface EagerFunctionExpression : Node {
    bool isAsync;
    bool isGenerator;
    BindingIdentifier? name;
    unsigned long length;
    FrozenArray<Directive> directives;
    FunctionExpressionContents contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerFunctionExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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

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

    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* tmpBody;
    MOZ_TRY(parseFunctionExpressionContents(
        length, &params, &tmpBody));
    BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
    BINJS_TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
    BINJS_TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
    BINJS_MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));
    return result;
}


/*
 interface EagerGetter : Node {
    PropertyName name;
    FrozenArray<Directive> directives;
    GetterContents contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerGetter()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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* tmpBody;
    MOZ_TRY(parseGetterContents(
        length, &params, &tmpBody));
    BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}


/*
 interface EagerMethod : Node {
    bool isAsync;
    bool isGenerator;
    PropertyName name;
    unsigned long length;
    FrozenArray<Directive> directives;
    FunctionOrMethodContents contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerMethod()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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

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

    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* tmpBody;
    MOZ_TRY(parseFunctionOrMethodContents(
        length, &params, &tmpBody));
    BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}


/*
 interface EagerSetter : Node {
    PropertyName name;
    unsigned long length;
    FrozenArray<Directive> directives;
    SetterContents contents;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerSetter()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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* tmpBody;
    MOZ_TRY(parseSetterContents(
        length, &params, &tmpBody));
    BINJS_MOZ_TRY_DECL(body, appendDirectivesToBody(tmpBody, directives));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, accessorType));
    return result;
}


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

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

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


/*
 interface Export : Node {
    (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExport()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


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

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

    return result;
}

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


/*
 interface ExportDefault : Node {
    (FunctionDeclaration or ClassDeclaration or Expression) body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportDefault()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ExportFrom : Node {
    FrozenArray<ExportFromSpecifier> namedExports;
    string moduleSpecifier;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportFrom()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ExportFromSpecifier : Node {
    IdentifierName name;
    IdentifierName? exportedName;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportFromSpecifier()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ExportLocalSpecifier : Node {
    IdentifierExpression name;
    IdentifierName? exportedName;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportLocalSpecifier()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ExportLocals : Node {
    FrozenArray<ExportLocalSpecifier> namedExports;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExportLocals()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ExpressionStatement : Node {
    Expression expression;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseExpressionStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface ForInOfBinding : Node {
    VariableDeclarationKind kind;
    Binding binding;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseForInOfBinding()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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()));
    auto pnk =
        kind_ == VariableDeclarationKind::Let
            ? ParseNodeKind::Let
            : ParseNodeKind::Var;
    BINJS_TRY_DECL(result, factory_.newDeclarationList(pnk, tokenizer_->pos(start)));
    factory_.addList(result, binding);
    return result;
}


/*
 interface ForInStatement : Node {
    (ForInOfBinding or AssignmentTarget) left;
    Expression right;
    Statement body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseForInStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

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


/*
 interface ForOfStatement : Node {
    (ForInOfBinding or AssignmentTarget) left;
    Expression right;
    Statement body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseForOfStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    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 (ForOfStatement)");
}


/*
 interface ForStatement : Node {
    (VariableDeclaration or Expression)? init;
    Expression? test;
    Expression? update;
    Statement body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseForStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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) {
        BINJS_TRY_DECL(spread, factory_.newSpread(start, rest));
        factory_.addList(result, spread);
    }
    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<</