js/src/frontend/BinSource-auto.cpp
author Stars <starsmarsjupitersaturn@protonmail.com>
Fri, 06 Jul 2018 08:40:50 -0600
changeset 427720 795f30107e2a31c04163a53397c4ed693b235e25
parent 424606 fb57020766137aa6f654fdc38fd2f96b9181dd01
child 428841 b14186c3f8952a345541bec532f2d2233b854cbc
permissions -rw-r--r--
Bug 1466428 - BinSource-auto.cpp: argument name 'YYY' in comment does not match parameter name 'XXX'. Auto generated by rust generator and the yaml file, these comments were pointing to old parameters which have now been updated to have the correct generated source file. r=arai MozReview-Commit-ID: CjNIY85s5K9

// 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 ::= EagerArrowExpression
    SkippableArrowExpression
*/
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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("ArrowExpression", 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
    EagerArrowExpression
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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
    EagerArrowExpression
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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
    EagerArrowExpression
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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;
}

/*
FunctionBodyOrExpression ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpression
    EagerFunctionExpression
    FunctionBody
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    StaticMemberExpression
    TemplateExpression
    ThisExpression
    UnaryExpression
    UpdateExpression
    YieldExpression
    YieldStarExpression
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseFunctionBodyOrExpression()
{
    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, parseSumFunctionBodyOrExpression(start, kind, fields));

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

template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumFunctionBodyOrExpression(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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
        break;
      case BinKind::EagerFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
        break;
      case BinKind::FunctionBody:
        MOZ_TRY_VAR(result, parseInterfaceFunctionBody(start, kind, fields));
        break;
      case BinKind::IdentifierExpression:
        MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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("FunctionBodyOrExpression", kind);
    }
    return result;
}

/*
FunctionDeclaration ::= EagerFunctionDeclaration
    SkippableFunctionDeclaration
*/
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::SkippableFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("FunctionDeclaration", kind);
    }
    return result;
}

/*
FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression
    AssignmentExpression
    AwaitExpression
    BinaryExpression
    CallExpression
    ClassDeclaration
    ClassExpression
    CompoundAssignmentExpression
    ComputedMemberExpression
    ConditionalExpression
    EagerArrowExpression
    EagerFunctionDeclaration
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionDeclaration
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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
    SkippableFunctionDeclaration
    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::SkippableFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(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
    SkippableFunctionExpression
*/
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::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("FunctionExpression", kind);
    }
    return result;
}

/*
Getter ::= EagerGetter
    SkippableGetter
*/
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::SkippableGetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(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
    ReturnStatement
    SkippableFunctionDeclaration
    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::ReturnStatement:
        MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
        break;
      case BinKind::SkippableFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(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
    SkippableMethod
*/
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::SkippableMethod:
        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("Method", kind);
    }
    return result;
}

/*
MethodDefinition ::= EagerGetter
    EagerMethod
    EagerSetter
    SkippableGetter
    SkippableMethod
    SkippableSetter
*/
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::SkippableGetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(start, kind, fields));
        break;
      case BinKind::SkippableMethod:
        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
        break;
      case BinKind::SkippableSetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(start, kind, fields));
        break;
      default:
        return raiseInvalidKind("MethodDefinition", kind);
    }
    return result;
}

/*
ObjectProperty ::= DataProperty
    EagerGetter
    EagerMethod
    EagerSetter
    ShorthandProperty
    SkippableGetter
    SkippableMethod
    SkippableSetter
*/
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::ShorthandProperty:
        MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
        break;
      case BinKind::SkippableGetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(start, kind, fields));
        break;
      case BinKind::SkippableMethod:
        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
        break;
      case BinKind::SkippableSetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(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->pn_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
    SkippableSetter
*/
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::SkippableSetter:
        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(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
    EagerArrowExpression
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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
    ReturnStatement
    SkippableFunctionDeclaration
    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::ReturnStatement:
        MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
        break;
      case BinKind::SkippableFunctionDeclaration:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(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
    EagerArrowExpression
    EagerFunctionExpression
    IdentifierExpression
    LiteralBooleanExpression
    LiteralInfinityExpression
    LiteralNullExpression
    LiteralNumericExpression
    LiteralRegExpExpression
    LiteralStringExpression
    NewExpression
    NewTargetExpression
    ObjectExpression
    SkippableArrowExpression
    SkippableFunctionExpression
    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::EagerArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(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::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::SkippableArrowExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
        break;
      case BinKind::SkippableFunctionExpression:
        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(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());

    auto result = elements;
    return result;
}


/*
 interface AssertedBlockScope : Node {
    FrozenArray<IdentifierName> lexicallyDeclaredNames;
    FrozenArray<IdentifierName> capturedNames;
    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[3] = { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
    MOZ_TRY(parseAndUpdateCapturedNames(kind));

    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 AssertedParameterScope : Node {
    FrozenArray<IdentifierName> parameterNames;
    FrozenArray<IdentifierName> capturedNames;
    bool hasDirectEval;
 }
*/
template<typename Tok> JS::Result<Ok>
BinASTParser<Tok>::parseAssertedParameterScope()
{
    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));
    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)
{
    MOZ_ASSERT(kind == BinKind::AssertedParameterScope);
    BINJS_TRY(CheckRecursionLimit(cx_));

#if defined(DEBUG)
    const BinField expected_fields[3] = { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    ParseContext::Statement* inStatement = parseContext_->innermostStatement();

    // If we are in a `CatchClause`, the binding is a implicit CatchParameter
    // and it goes into the innermost scope. Otherwise, we're in a function,
    // so it goes in the function scope.
    if (inStatement && inStatement->kind() == StatementKind::Catch)
        MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::CatchParameter));
    else
        MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind::PositionalFormalParameter));
    MOZ_TRY(parseAndUpdateCapturedNames(kind));

    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<IdentifierName> lexicallyDeclaredNames;
    FrozenArray<IdentifierName> varDeclaredNames;
    FrozenArray<IdentifierName> capturedNames;
    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[4] = { BinField::LexicallyDeclaredNames, BinField::VarDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
    MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var));
    MOZ_TRY(parseAndUpdateCapturedNames(kind));

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

    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;
    // 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;
        }
    }
    auto result = arguments;
    result->setKind(ParseNodeKind::Call);
    result->prepend(callee);
    result->setOp(op);
    return result;
}


/*
 interface CatchClause : Node {
    AssertedParameterScope? bindingScope;
    Binding binding;
    Block body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
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<ParseNode*>
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(parseOptionalAssertedParameterScope());

    BINJS_MOZ_TRY_DECL(binding, parseBinding());

    BINJS_MOZ_TRY_DECL(body, parseBlock());

    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, start));
    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, start));
    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 EagerArrowExpression : Node {
    bool isAsync;
    AssertedParameterScope? parameterScope;
    AssertedVarScope? bodyScope;
    FormalParameters params;
    (FunctionBody or Expression) body;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseEagerArrowExpression()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface EagerFunctionDeclaration : Node {
    bool isAsync;
    bool isGenerator;
    BindingIdentifier name;
    AssertedParameterScope? parameterScope;
    AssertedVarScope? bodyScope;
    FormalParameters params;
    FunctionBody body;
 }
*/
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[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::ParameterScope, BinField::BodyScope, BinField::Params, BinField::Body };
    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(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax, name));

    // 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_));
    MOZ_TRY(parseOptionalAssertedParameterScope());

    MOZ_TRY(parseOptionalAssertedVarScope());

    BINJS_MOZ_TRY_DECL(params, parseFormalParameters());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    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;
    AssertedParameterScope? parameterScope;
    AssertedVarScope? bodyScope;
    FormalParameters params;
    FunctionBody body;
 }
*/
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[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::ParameterScope, BinField::BodyScope, BinField::Params, BinField::Body };
    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(funbox, buildFunctionBox(
        isGenerator ? GeneratorKind::Generator
                    : GeneratorKind::NotGenerator,
        isAsync ? FunctionAsyncKind::AsyncFunction
                : FunctionAsyncKind::SyncFunction,
        syntax, name));

    // 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_));
    MOZ_TRY(parseOptionalAssertedParameterScope());

    MOZ_TRY(parseOptionalAssertedVarScope());

    BINJS_MOZ_TRY_DECL(params, parseFormalParameters());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    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;
    AssertedVarScope? bodyScope;
    FunctionBody body;
 }
*/
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::BodyScope, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());
    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        GeneratorKind::NotGenerator,
        FunctionAsyncKind::SyncFunction,
        FunctionSyntaxKind::Getter, /* name = */ nullptr));

    // 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_));
    MOZ_TRY(parseOptionalAssertedVarScope());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::Getter));
    return result;
}


/*
 interface EagerMethod : Node {
    bool isAsync;
    bool isGenerator;
    PropertyName name;
    AssertedParameterScope? parameterScope;
    AssertedVarScope? bodyScope;
    FormalParameters params;
    FunctionBody body;
 }
*/
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[7] = { BinField::IsAsync, BinField::IsGenerator, BinField::Name, BinField::ParameterScope, BinField::BodyScope, BinField::Params, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
    const auto syntax = FunctionSyntaxKind::Method;

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

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

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());

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

    // 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_));
    MOZ_TRY(parseOptionalAssertedParameterScope());

    MOZ_TRY(parseOptionalAssertedVarScope());

    BINJS_MOZ_TRY_DECL(params, parseFormalParameters());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None));
    return result;
}


/*
 interface EagerSetter : Node {
    PropertyName name;
    AssertedParameterScope? parameterScope;
    AssertedVarScope? bodyScope;
    Parameter param;
    FunctionBody body;
 }
*/
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[5] = { BinField::Name, BinField::ParameterScope, BinField::BodyScope, BinField::Param, BinField::Body };
    MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)

    BINJS_MOZ_TRY_DECL(name, parsePropertyName());
    BINJS_MOZ_TRY_DECL(funbox, buildFunctionBox(
        GeneratorKind::NotGenerator,
        FunctionAsyncKind::SyncFunction,
        FunctionSyntaxKind::Setter, /* name = */ nullptr));

    // 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_));
    MOZ_TRY(parseOptionalAssertedParameterScope());

    MOZ_TRY(parseOptionalAssertedVarScope());

    BINJS_MOZ_TRY_DECL(param, parseParameter());

    BINJS_MOZ_TRY_DECL(body, parseFunctionBody());

    BINJS_TRY_DECL(params, new_<ListNode>(ParseNodeKind::ParamsBody, param->pn_pos));
    factory_.addList(params, param);
    BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
    BINJS_TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::Setter));
    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->pn_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)));
    BINJS_TRY_DECL(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)));
    BINJS_TRY_DECL(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<ParseNode*>
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<ParseNode*>
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 FunctionBody : Node {
    FrozenArray<Directive> directives;
    FrozenArray<Statement> statements;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseFunctionBody()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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

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

    BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());

    BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());

    BINJS_MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));
    return result;
}


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

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

    return result;
}

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

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

    RootedAtom name(cx_);
    MOZ_TRY_VAR(name, tokenizer_->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 IfStatement : Node {
    Expression test;
    Statement consequent;
    Statement? alternate;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseIfStatement()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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

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

    BINJS_MOZ_TRY_DECL(test, parseExpression());

    BINJS_MOZ_TRY_DECL(consequent, parseStatement());

    BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement());

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


/*
 interface Import : Node {
    string moduleSpecifier;
    BindingIdentifier? defaultBinding;
    FrozenArray<ImportSpecifier> namedImports;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseImport()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


/*
 interface ImportNamespace : Node {
    string moduleSpecifier;
    BindingIdentifier? defaultBinding;
    BindingIdentifier namespaceBinding;
 }
*/
template<typename Tok> JS::Result<ParseNode*>
BinASTParser<Tok>::parseImportNamespace()
{
    BinKind kind;
    BinFields fields(cx_);
    AutoTaggedTuple guard(*tokenizer_);

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

    return result;
}

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


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

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

    return result;
}

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


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

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

    return result;
}

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

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

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

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


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

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

    return result;
}

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

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

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

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


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

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

    return result;
}

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


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

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

    return result;
}

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

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


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

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

    return result;
}

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

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

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

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


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

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

    return result;
}

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

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

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

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


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

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

    return result;
}

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

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

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

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