Bug 1437004 - Porting BinAST to AST v3;r=arai,jorendorff
authorDavid Teller <dteller@mozilla.com>
Wed, 21 Feb 2018 17:07:03 +0100
changeset 412117 26162086b394fc0eb45c46258f6e148063f5f031
parent 412116 8e3a57a21b26909851d97fbb0300066950d8e95c
child 412118 d220f806c19772c769272fb81555d1d5a21d0a64
push id101850
push usernerli@mozilla.com
push dateFri, 06 Apr 2018 22:04:41 +0000
treeherdermozilla-inbound@e8f1530940a5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai, jorendorff
bugs1437004
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1437004 - Porting BinAST to AST v3;r=arai,jorendorff This patch is a nearly complete reimplementation of BinASTReader, with the following changes: - Files BinToken.h, BinSource-auto.h (new), BinSource-auto.cpp (new) are now autogenerated by the generator in js/src/frontend/binsouce from the webidl specifications of BinAST and a small configuration file. - Optional fields have been removed. Rather, some specific fields may, if so marked in the specifications, contain a Null constant. - `hasDirectEval` is now checked for consistency (NOT completeness). - `varDeclaredNames` is now checked for consistency (NOT completeness). - `lexicallyDeclaredNames` is now checked for consistency (NOT completeness). - `parameterNames` is now checked for consistency (NOT completeness). - `capturedNames` is NOT checked. - Atoms read are now properly expected to be UTF8. This patch does not implement the entire specifications, but should implement most of ES5. In particular, it is sufficient to parse the source code of: - Facebook; - jQuery; - mootools; - Underscore; - Backbone; - Angular. MozReview-Commit-ID: HwkVB5dliZv
config/check_spidermonkey_style.py
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource-auto.h
js/src/frontend/BinSource.cpp
js/src/frontend/BinSource.h
js/src/frontend/BinSource.webidl_
js/src/frontend/BinSource.yaml
js/src/frontend/BinToken.h
js/src/moz.build
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -108,16 +108,17 @@ included_inclnames_to_ignore = set([
     'unicode/utypes.h',         # ICU
     'vtune/VTuneWrapper.h'      # VTune
 ])
 
 # These files have additional constraints on where they are #included, so we
 # ignore #includes of them when checking #include ordering.
 oddly_ordered_inclnames = set([
     'ctypes/typedefs.h',        # Included multiple times in the body of ctypes/CTypes.h
+    'frontend/BinSource-auto.h', # Included in the body of frontend/BinSource.h
     'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h
     'gc/StatsPhasesGenerated.h',         # Included in the body of gc/Statistics.h
     'gc/StatsPhasesGenerated.cpp',       # Included in the body of gc/Statistics.cpp
     'psapi.h',                  # Must be included after "util/Windows.h" on Windows
     'machine/endian.h',         # Must be included after <sys/types.h> on BSD
     'winbase.h',                # Must precede other system headers(?)
     'windef.h'                  # Must precede other system headers(?)
 ])
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -0,0 +1,7326 @@
+// 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.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 {
+
+using AutoList = BinTokenReaderTester::AutoList;
+using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple;
+using AutoTuple = BinTokenReaderTester::AutoTuple;
+using BinFields = BinTokenReaderTester::BinFields;
+using Chars = BinTokenReaderTester::Chars;
+using NameBag = GCHashSet<JSString*>;
+using Names = GCVector<JSString*, 8>;
+using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
+
+// Evaluate an expression EXPR, checking that the result is not falsy.
+//
+// Throw `cx->alreadyReportedError()` if it returns 0/nullptr.
+#define TRY(EXPR) \
+    do { \
+        if (!EXPR) \
+            return cx_->alreadyReportedError(); \
+    } while(false)
+
+
+// Evaluate an expression EXPR, checking that the result is not falsy.
+// In case of success, assign the result to VAR.
+//
+// Throw `cx->alreadyReportedError()` if it returns 0/nullptr.
+#define TRY_VAR(VAR, EXPR) \
+    do { \
+        VAR = EXPR; \
+        if (!VAR) \
+            return cx_->alreadyReportedError(); \
+    } while (false)
+
+// Evaluate an expression EXPR, checking that the result is not falsy.
+// In case of success, assign the result to a new variable VAR.
+//
+// Throw `cx->alreadyReportedError()` if it returns 0/nullptr.
+#define TRY_DECL(VAR, EXPR) \
+    auto VAR = EXPR; \
+    if (!VAR) \
+        return cx_->alreadyReportedError();
+
+// Evaluate an expression EXPR, checking that the result is a success.
+// In case of success, unwrap and assign the result to a new variable VAR.
+//
+// In case of error, propagate the error.
+#define MOZ_TRY_DECL(VAR, EXPR) \
+    auto _##VAR = EXPR; \
+    if (_##VAR.isErr()) \
+        return ::mozilla::Err(_##VAR.unwrapErr()); \
+    auto VAR = _##VAR.unwrap();
+
+// Ensure that we are visiting the right fields.
+template<size_t N>
+JS::Result<Ok, JS::Error&>
+BinASTParser::checkFields(const BinKind kind, const BinFields& actual, const BinField (&expected)[N])
+{
+    if (actual.length() != N)
+        return raiseInvalidNumberOfFields(kind, N, actual.length());
+
+    for (size_t i = 0; i < N; ++i) {
+        if (actual[i] != expected[i])
+            return raiseInvalidField(describeBinKind(kind), actual[i]);
+    }
+
+    return Ok();
+}
+
+// Special case for N=0, as empty arrays are not permitted in C++
+JS::Result<Ok, JS::Error&>
+BinASTParser::checkFields0(const BinKind kind, const BinFields& actual)
+{
+    if (actual.length() != 0)
+        return raiseInvalidNumberOfFields(kind, 0, actual.length());
+
+    return Ok();
+}
+
+// Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
+// a string literal (and ONLY a string literal).
+template<size_t N>
+bool operator==(const Chars& left, const char (&right)[N]) {
+    return BinTokenReaderTester::equals(left, right);
+}
+
+// Helper class: Restore field `variableDeclarationKind_` upon leaving a scope.
+class MOZ_RAII AutoVariableDeclarationKind {
+  public:
+    explicit AutoVariableDeclarationKind(BinASTParser* parser
+                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
+      parser_(parser),
+      kind(parser->variableDeclarationKind_)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    ~AutoVariableDeclarationKind() {
+        parser_->variableDeclarationKind_ = kind;
+    }
+  private:
+    BinASTParser* parser_;
+    BinASTParser::VariableDeclarationKind kind;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+
+// ----- Sums of interfaces (autogenerated, by lexicographical order)
+// Sums of sums are flattened.
+/*
+AssignmentTarget ::= ArrayAssignmentTarget
+    AssignmentTargetIdentifier
+    ComputedMemberAssignmentTarget
+    ObjectAssignmentTarget
+    StaticMemberAssignmentTarget
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumAssignmentTarget(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetOrAssignmentTargetWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumAssignmentTargetOrAssignmentTargetWithInitializer(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetPattern()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumAssignmentTargetPattern(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumAssignmentTargetProperty(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingOrBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumBindingOrBindingWithInitializer(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingPattern()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumBindingPattern(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumBindingProperty(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumExportDeclaration(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    Super
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExpressionOrSuper()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumExpressionOrSuper(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    TemplateElement
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExpressionOrTemplateElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumExpressionOrTemplateElement(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseForInOfBindingOrAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumForInOfBindingOrAssignmentTarget(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionBody
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionBodyOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumFunctionBodyOrExpression(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionBody:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionBody(start, kind, fields));
+        break;
+      case BinKind::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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;
+}
+
+/*
+FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassDeclaration
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionDeclaration
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionDeclarationOrClassDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrExpression(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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
+    FunctionDeclaration
+    VariableDeclaration
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::FunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::VariableDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrVariableDeclaration", kind);
+    }
+    return result;
+}
+
+/*
+ImportDeclaration ::= Import
+    ImportNamespace
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseImportDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumImportDeclaration(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+    EmptyStatement
+    Export
+    ExportAllFrom
+    ExportDefault
+    ExportFrom
+    ExportLocals
+    ExpressionStatement
+    ForInStatement
+    ForOfStatement
+    ForStatement
+    FunctionDeclaration
+    IfStatement
+    Import
+    ImportNamespace
+    LabelledStatement
+    ReturnStatement
+    SwitchStatement
+    SwitchStatementWithDefault
+    ThrowStatement
+    TryCatchStatement
+    TryFinallyStatement
+    VariableDeclaration
+    WhileStatement
+    WithStatement
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseImportDeclarationOrExportDeclarationOrStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumImportDeclarationOrExportDeclarationOrStatement(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::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::FunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(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::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseIterationStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumIterationStatement(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteral()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumLiteral(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+}
+
+/*
+MethodDefinition ::= Getter
+    Method
+    Setter
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseMethodDefinition()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumMethodDefinition(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::Getter:
+        MOZ_TRY_VAR(result, parseInterfaceGetter(start, kind, fields));
+        break;
+      case BinKind::Method:
+        MOZ_TRY_VAR(result, parseInterfaceMethod(start, kind, fields));
+        break;
+      case BinKind::Setter:
+        MOZ_TRY_VAR(result, parseInterfaceSetter(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("MethodDefinition", kind);
+    }
+    return result;
+}
+
+/*
+ObjectProperty ::= DataProperty
+    Getter
+    Method
+    Setter
+    ShorthandProperty
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseObjectProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumObjectProperty(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::Getter:
+        MOZ_TRY_VAR(result, parseInterfaceGetter(start, kind, fields));
+        break;
+      case BinKind::Method:
+        MOZ_TRY_VAR(result, parseInterfaceMethod(start, kind, fields));
+        break;
+      case BinKind::Setter:
+        MOZ_TRY_VAR(result, parseInterfaceSetter(start, kind, fields));
+        break;
+      case BinKind::ShorthandProperty:
+        MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("ObjectProperty", kind);
+    }
+    return result;
+}
+
+/*
+Parameter ::= ArrayBinding
+    BindingIdentifier
+    BindingWithInitializer
+    ObjectBinding
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseParameter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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));
+        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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseProgram()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+*/
+JS::Result<ParseNode*>
+BinASTParser::parsePropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumPropertyName(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::ComputedPropertyName:
+        MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind, fields));
+        break;
+      case BinKind::LiteralPropertyName:
+        MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("PropertyName", kind);
+    }
+    return result;
+}
+
+/*
+SimpleAssignmentTarget ::= AssignmentTargetIdentifier
+    ComputedMemberAssignmentTarget
+    StaticMemberAssignmentTarget
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSimpleAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumSimpleAssignmentTarget(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    SpreadElement
+    StaticMemberExpression
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSpreadElementOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumSpreadElementOrExpression(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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
+    EmptyStatement
+    ExpressionStatement
+    ForInStatement
+    ForOfStatement
+    ForStatement
+    FunctionDeclaration
+    IfStatement
+    LabelledStatement
+    ReturnStatement
+    SwitchStatement
+    SwitchStatementWithDefault
+    ThrowStatement
+    TryCatchStatement
+    TryFinallyStatement
+    VariableDeclaration
+    WhileStatement
+    WithStatement
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::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::FunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(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::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
+    ArrowExpression
+    AssignmentExpression
+    AwaitExpression
+    BinaryExpression
+    CallExpression
+    ClassExpression
+    CompoundAssignmentExpression
+    ComputedMemberExpression
+    ConditionalExpression
+    FunctionExpression
+    IdentifierExpression
+    LiteralBooleanExpression
+    LiteralInfinityExpression
+    LiteralNullExpression
+    LiteralNumericExpression
+    LiteralRegExpExpression
+    LiteralStringExpression
+    NewExpression
+    NewTargetExpression
+    ObjectExpression
+    StaticMemberExpression
+    TemplateExpression
+    ThisExpression
+    UnaryExpression
+    UpdateExpression
+    VariableDeclaration
+    YieldExpression
+    YieldStarExpression
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseVariableDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumVariableDeclarationOrExpression(start, kind, fields));
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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::ArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceArrowExpression(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::FunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(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::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 ArrayAssignmentTarget : Node {
+    FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer)> elements;
+    AssignmentTarget? rest;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseArrayAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseArrayBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceArrayBinding(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseArrayExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceArrayExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ArrayExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Elements }));
+
+
+
+    MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
+
+
+    auto result = elements;return result;
+}
+
+
+/*
+ interface ArrowExpression : Node {
+    bool isAsync;
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    FormalParameters params;
+    (FunctionBody or Expression) body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseArrowExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceArrowExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ArrowExpression)");
+}
+
+
+/*
+ interface AssertedBlockScope : Node {
+    FrozenArray<IdentifierName> lexicallyDeclaredNames;
+    FrozenArray<IdentifierName> capturedNames;
+    bool hasDirectEval;
+ }
+*/
+JS::Result<Ok>
+BinASTParser::parseAssertedBlockScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssertedBlockScope(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::AssertedBlockScope);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
+    MOZ_TRY(parseAndUpdateCapturedNames());
+
+
+
+    MOZ_TRY_DECL(hasDirectEval, 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;
+ }
+*/
+JS::Result<Ok>
+BinASTParser::parseAssertedParameterScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssertedParameterScope(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::AssertedParameterScope);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter));
+    MOZ_TRY(parseAndUpdateCapturedNames());
+
+
+
+    MOZ_TRY_DECL(hasDirectEval, 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;
+ }
+*/
+JS::Result<Ok>
+BinASTParser::parseAssertedVarScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssertedVarScope(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::AssertedVarScope);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::VarDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
+    MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var));
+    MOZ_TRY(parseAndUpdateCapturedNames());
+
+
+
+    MOZ_TRY_DECL(hasDirectEval, 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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssignmentExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::AssignmentExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(binding, parseAssignmentTarget());
+
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression));return result;
+}
+
+
+/*
+ interface AssignmentTargetIdentifier : Node {
+    Identifier name;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+
+
+    RootedAtom name(cx_);
+    MOZ_TRY(readString(&name));
+
+
+    if (!IsIdentifier(name))
+        return raiseError("Invalid identifier");
+    TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result;
+}
+
+
+/*
+ interface AssignmentTargetPropertyIdentifier : Node {
+    AssignmentTargetIdentifier binding;
+    Expression? init;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetPropertyIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetPropertyProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAssignmentTargetWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetWithInitializer(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (AssignmentTargetWithInitializer)");
+}
+
+
+/*
+ interface AwaitExpression : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseAwaitExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceAwaitExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBinaryExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBinaryExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::BinaryExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Left, BinField::Right }));
+
+
+
+    MOZ_TRY_DECL(operator_, parseBinaryOperator());
+
+
+
+
+    MOZ_TRY_DECL(left, parseExpression());
+
+
+
+
+    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 {
+        TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start)));
+
+        list->appendWithoutOrderAssumption(left);
+        list->appendWithoutOrderAssumption(right);
+        result = list;
+    }return result;
+}
+
+
+/*
+ interface BindingIdentifier : Node {
+    Identifier name;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBindingIdentifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::BindingIdentifier);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+
+
+    RootedAtom name(cx_);
+    MOZ_TRY(readString(&name));
+
+
+    if (!IsIdentifier(name))
+        return raiseError("Invalid identifier");
+    TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result;
+}
+
+
+/*
+ interface BindingPropertyIdentifier : Node {
+    BindingIdentifier binding;
+    Expression? init;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingPropertyIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingPropertyProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBindingPropertyProperty(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBindingWithInitializer(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBlock()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::Block);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Statements }));
+    fprintf(stderr, "Block: PUSH parse context\n");
+    ParseContext::Statement stmt(parseContext_, StatementKind::Block);
+    ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
+    TRY(currentScope.init(parseContext_));
+
+
+    MOZ_TRY(parseOptionalAssertedBlockScope());
+
+
+
+
+    MOZ_TRY_DECL(statements, parseListOfStatement());
+
+
+    TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
+    TRY_DECL(result, factory_.newLexicalScope(*bindings, statements));
+    fprintf(stderr, "Block: POP parse context\n");return result;
+}
+
+
+/*
+ interface BreakStatement : Node {
+    Label? label;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseBreakStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceBreakStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::BreakStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Label }));
+    RootedAtom label(cx_);
+    MOZ_TRY(readMaybeString(&label));
+
+    if (label && !IsIdentifier(label))
+        return raiseError("Invalid identifier");
+
+    if (label) {
+        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");
+            }
+        }
+    }
+    TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface CallExpression : Node {
+    (Expression or Super) callee;
+    Arguments arguments;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseCallExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceCallExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::CallExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
+
+
+
+    MOZ_TRY_DECL(callee, parseExpressionOrSuper());
+
+
+
+
+    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 {
+    Binding binding;
+    Block body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseCatchClause()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceCatchClause(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::CatchClause);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Body }));
+    ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
+    ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
+    TRY(currentScope.init(parseContext_));
+
+
+    MOZ_TRY_DECL(binding, parseBinding());
+
+
+
+
+    MOZ_TRY_DECL(body, parseBlock());
+
+
+    // Export implicit variables to the scope.
+    // FIXME: Handle cases other than Name.
+    MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
+    auto ptr = currentScope.lookupDeclaredNameForAdd(binding->name());
+    TRY(currentScope.addDeclaredName(parseContext_, ptr, binding->name(), DeclarationKind::Let, start));
+
+    TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
+    TRY_DECL(result, factory_.newLexicalScope(*bindings, body));
+    TRY(factory_.setupCatchScope(result, binding, body));return result;
+}
+
+
+/*
+ interface ClassDeclaration : Node {
+    BindingIdentifier name;
+    Expression? super;
+    FrozenArray<ClassElement> elements;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseClassDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceClassDeclaration(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseClassElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceClassElement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseClassExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceClassExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseCompoundAssignmentExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::CompoundAssignmentExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Binding, BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());
+
+
+
+
+    MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget());
+
+
+
+
+    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;
+    }
+    TRY_DECL(result, factory_.newAssignment(pnk, binding, expression));return result;
+}
+
+
+/*
+ interface ComputedMemberAssignmentTarget : Node {
+    (Expression or Super) object;
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseComputedMemberAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ComputedMemberAssignmentTarget);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(object, parseExpressionOrSuper());
+
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));return result;
+}
+
+
+/*
+ interface ComputedMemberExpression : Node {
+    (Expression or Super) object;
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseComputedMemberExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceComputedMemberExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ComputedMemberExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(object, parseExpressionOrSuper());
+
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));return result;
+}
+
+
+/*
+ interface ComputedPropertyName : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseComputedPropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceComputedPropertyName(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseConditionalExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceConditionalExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ConditionalExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate }));
+
+
+
+    MOZ_TRY_DECL(test, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(consequent, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(alternate, parseExpression());
+
+
+    TRY_DECL(result, factory_.newConditional(test, consequent, alternate));return result;
+}
+
+
+/*
+ interface ContinueStatement : Node {
+    Label? label;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseContinueStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceContinueStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ContinueStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Label }));
+    RootedAtom label(cx_);
+    MOZ_TRY(readMaybeString(&label));
+
+    if (label && !IsIdentifier(label))
+        return raiseError("ContinueStatement - Label MUST be an identifier");
+
+    if (label) {
+        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");
+            }
+        }
+    }
+
+    TRY_DECL(result, factory_.newContinueStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface DataProperty : Node {
+    PropertyName name;
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseDataProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceDataProperty(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::DataProperty);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Name, BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(name, parsePropertyName());
+
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    if (!factory_.isUsableAsObjectPropertyName(name))
+        return raiseError("DataProperty key kind");
+
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));return result;
+}
+
+
+/*
+ interface DebuggerStatement : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseDebuggerStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceDebuggerStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (DebuggerStatement)");
+}
+
+
+/*
+ interface Directive : Node {
+    string rawValue;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseDirective()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceDirective(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::Directive);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::RawValue }));
+
+
+    RootedAtom rawValue(cx_);
+    MOZ_TRY(readString(&rawValue));
+
+
+    TokenPos pos = tokenizer_->pos(start);
+    TRY_DECL(result, factory_.newStringLiteral(rawValue, pos));return result;
+}
+
+
+/*
+ interface DoWhileStatement : Node {
+    Expression test;
+    Statement body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseDoWhileStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceDoWhileStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::DoWhileStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body }));
+    ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop);
+
+
+    MOZ_TRY_DECL(test, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface EmptyStatement : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseEmptyStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEmptyStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::EmptyStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields0(kind, fields));
+
+    TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface Export : Node {
+    (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExport()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExport(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Export)");
+}
+
+
+/*
+ interface ExportAllFrom : Node {
+    string moduleSpecifier;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportAllFrom()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportAllFrom(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportDefault(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportFrom()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportFrom(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportFromSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportFromSpecifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportLocalSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportLocalSpecifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportLocalSpecifier)");
+}
+
+
+/*
+ interface ExportLocals : Node {
+    FrozenArray<ExportLocalSpecifier> namedExports;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExportLocals()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportLocals(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportLocals)");
+}
+
+
+/*
+ interface ExpressionStatement : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseExpressionStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExpressionStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ExpressionStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset()));return result;
+}
+
+
+/*
+ interface ForInOfBinding : Node {
+    VariableDeclarationKind kind;
+    Binding binding;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseForInOfBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForInOfBinding(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForInOfBinding);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Kind, BinField::Binding }));
+    AutoVariableDeclarationKind kindGuard(this);
+
+
+    MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
+
+
+
+
+    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;
+    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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseForInStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForInStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForInStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Left, BinField::Right, BinField::Body }));
+    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_);
+    TRY(scope.init(parseContext_));
+
+
+    MOZ_TRY_DECL(left, parseForInOfBindingOrAssignmentTarget());
+
+
+
+
+    MOZ_TRY_DECL(right, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right, tokenizer_->pos(start)));
+    TRY_DECL(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0));
+
+    if (!scope.isEmpty()) {
+        TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
+        TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
+    }return result;
+}
+
+
+/*
+ interface ForOfStatement : Node {
+    (ForInOfBinding or AssignmentTarget) left;
+    Expression right;
+    Statement body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseForOfStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForOfStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseForStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Init, BinField::Test, BinField::Update, BinField::Body }));
+    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_);
+    TRY(scope.init(parseContext_));
+
+
+    MOZ_TRY_DECL(init, parseOptionalVariableDeclarationOrExpression());
+
+
+
+
+    MOZ_TRY_DECL(test, parseOptionalExpression());
+
+
+
+
+    MOZ_TRY_DECL(update, parseOptionalExpression());
+
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start)));
+    TRY_DECL(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0));
+
+    if (!scope.isEmpty()) {
+        TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
+        TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
+    }return result;
+}
+
+
+/*
+ interface FormalParameters : Node {
+    FrozenArray<Parameter> items;
+    Binding? rest;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFormalParameters()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFormalParameters(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FormalParameters);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Items, BinField::Rest }));
+
+
+
+    MOZ_TRY_DECL(items, parseListOfParameter());
+
+
+
+
+    MOZ_TRY_DECL(rest, parseOptionalBinding());
+
+
+    auto result = items;
+    if (rest) {
+        TRY_DECL(spread, factory_.newSpread(start, rest));
+        factory_.addList(result, spread);
+    }return result;
+}
+
+
+/*
+ interface FunctionBody : Node {
+    FrozenArray<Directive> directives;
+    FrozenArray<Statement> statements;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionBody()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFunctionBody(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FunctionBody);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Directives, BinField::Statements }));
+
+
+
+    MOZ_TRY_DECL(directives, parseListOfDirective());
+
+
+
+
+    MOZ_TRY_DECL(statements, parseListOfStatement());
+
+
+    MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));return result;
+}
+
+
+/*
+ interface FunctionDeclaration : Node {
+    bool isAsync;
+    bool isGenerator;
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    BindingIdentifier name;
+    FormalParameters params;
+    FunctionBody body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFunctionDeclaration(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FunctionDeclaration);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(isAsync, readBool());
+
+
+
+
+    MOZ_TRY_DECL(isGenerator, readBool());
+
+
+    MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction));
+
+    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
+    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
+    TRY(funpc.init());
+    parseContext_->functionScope().useAsVarScope(parseContext_);
+    MOZ_ASSERT(parseContext_->isFunctionBox());
+
+    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
+    TRY(lexicalScope.init(parseContext_));
+
+    MOZ_TRY(parseOptionalAssertedParameterScope());
+
+
+
+
+    MOZ_TRY(parseOptionalAssertedVarScope());
+
+
+
+
+    MOZ_TRY_DECL(name, parseBindingIdentifier());
+
+
+
+
+    MOZ_TRY_DECL(params, parseFormalParameters());
+
+
+
+
+    MOZ_TRY_DECL(body, parseFunctionBody());
+
+
+    TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
+    TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
+    MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));return result;
+}
+
+
+/*
+ interface FunctionExpression : Node {
+    bool isAsync;
+    bool isGenerator;
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    BindingIdentifier? name;
+    FormalParameters params;
+    FunctionBody body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseFunctionExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFunctionExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FunctionExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(isAsync, readBool());
+
+
+
+
+    MOZ_TRY_DECL(isGenerator, readBool());
+
+
+    MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction));
+
+    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
+    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
+    TRY(funpc.init());
+    parseContext_->functionScope().useAsVarScope(parseContext_);
+    MOZ_ASSERT(parseContext_->isFunctionBox());
+
+    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
+    TRY(lexicalScope.init(parseContext_));
+
+    MOZ_TRY(parseOptionalAssertedParameterScope());
+
+
+
+
+    MOZ_TRY(parseOptionalAssertedVarScope());
+
+
+
+
+    MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
+
+
+
+
+    MOZ_TRY_DECL(params, parseFormalParameters());
+
+
+
+
+    MOZ_TRY_DECL(body, parseFunctionBody());
+
+
+    TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_));
+    TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body));
+    MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));return result;
+}
+
+
+/*
+ interface Getter : Node {
+    AssertedVarScope? bodyScope;
+    PropertyName name;
+    FunctionBody body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseGetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceGetter(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceGetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Getter)");
+}
+
+
+/*
+ interface IdentifierExpression : Node {
+    Identifier name;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseIdentifierExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceIdentifierExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::IdentifierExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+
+
+    RootedAtom name(cx_);
+    MOZ_TRY(readString(&name));
+
+
+    if (!IsIdentifier(name))
+        return raiseError("Invalid identifier");
+    TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result;
+}
+
+
+/*
+ interface IfStatement : Node {
+    Expression test;
+    Statement consequent;
+    Statement? alternate;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseIfStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceIfStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::IfStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate }));
+
+
+
+    MOZ_TRY_DECL(test, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(consequent, parseStatement());
+
+
+
+
+    MOZ_TRY_DECL(alternate, parseOptionalStatement());
+
+
+    TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate));return result;
+}
+
+
+/*
+ interface Import : Node {
+    string moduleSpecifier;
+    BindingIdentifier? defaultBinding;
+    FrozenArray<ImportSpecifier> namedImports;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseImport()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImport(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseImportNamespace()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImportNamespace(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseImportSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImportSpecifier(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::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;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLabelledStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLabelledStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LabelledStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Label, BinField::Body }));
+
+
+    RootedAtom label(cx_);
+    MOZ_TRY(readString(&label));
+    if (!IsIdentifier(label))
+        return raiseError("Invalid identifier");
+    ParseContext::LabelStatement stmt(parseContext_, label);
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(result, factory_.newLabeledStatement(label->asPropertyName(), body, start));return result;
+}
+
+
+/*
+ interface LiteralBooleanExpression : Node {
+    bool value;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralBooleanExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralBooleanExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Value }));
+
+
+
+    MOZ_TRY_DECL(value, readBool());
+
+
+    TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface LiteralInfinityExpression : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralInfinityExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (LiteralInfinityExpression)");
+}
+
+
+/*
+ interface LiteralNullExpression : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralNullExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralNullExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralNullExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields0(kind, fields));
+
+    TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface LiteralNumericExpression : Node {
+    number value;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralNumericExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralNumericExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Value }));
+
+
+
+    MOZ_TRY_DECL(value, readNumber());
+
+
+    TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface LiteralPropertyName : Node {
+    string value;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralPropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralPropertyName(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralPropertyName);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Value }));
+
+
+    RootedAtom value(cx_);
+    MOZ_TRY(readString(&value));
+
+
+    ParseNode* result;
+    uint32_t index;
+    if (value->isIndex(&index))
+        TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset())));
+    else
+        TRY_VAR(result, factory_.newObjectLiteralPropertyName(value, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface LiteralRegExpExpression : Node {
+    string pattern;
+    string flags;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralRegExpExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralRegExpExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Pattern, BinField::Flags }));
+
+
+    RootedAtom pattern(cx_);
+    MOZ_TRY(readString(&pattern));
+
+    Chars flags(cx_); MOZ_TRY(readString(flags));
+
+    RegExpFlag reflags = NoFlags;
+    for (auto c : flags) {
+        if (c == 'g' && !(reflags & GlobalFlag))
+            reflags = RegExpFlag(reflags | GlobalFlag);
+        else if (c == 'i' && !(reflags & IgnoreCaseFlag))
+            reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+        else if (c == 'm' && !(reflags & MultilineFlag))
+            reflags = RegExpFlag(reflags | MultilineFlag);
+        else if (c == 'y' && !(reflags & StickyFlag))
+            reflags = RegExpFlag(reflags | StickyFlag);
+        else if (c == 'u' && !(reflags & UnicodeFlag))
+            reflags = RegExpFlag(reflags | UnicodeFlag);
+        else
+            return raiseInvalidEnum("RegExpLiteral", flags);
+    }
+
+
+    Rooted<RegExpObject*> reobj(cx_);
+    TRY_VAR(reobj, RegExpObject::create(cx_,
+        pattern,
+        reflags,
+        alloc_,
+        TenuredObject));
+
+    TRY_DECL(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this));return result;
+}
+
+
+/*
+ interface LiteralStringExpression : Node {
+    string value;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseLiteralStringExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralStringExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralStringExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Value }));
+
+
+    RootedAtom value(cx_);
+    MOZ_TRY(readString(&value));
+
+
+    TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface Method : Node {
+    bool isAsync;
+    bool isGenerator;
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    PropertyName name;
+    FormalParameters params;
+    FunctionBody body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseMethod()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceMethod(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::Method);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(isAsync, readBool());
+
+
+
+
+    MOZ_TRY_DECL(isGenerator, readBool());
+
+
+    MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction));
+
+    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
+    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
+    TRY(funpc.init());
+    parseContext_->functionScope().useAsVarScope(parseContext_);
+    MOZ_ASSERT(parseContext_->isFunctionBox());
+
+    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
+    TRY(lexicalScope.init(parseContext_));
+
+    MOZ_TRY(parseOptionalAssertedParameterScope());
+
+
+
+
+    MOZ_TRY(parseOptionalAssertedVarScope());
+
+
+
+
+    MOZ_TRY_DECL(name, parsePropertyName());
+
+
+
+
+    MOZ_TRY_DECL(params, parseFormalParameters());
+
+
+
+
+    MOZ_TRY_DECL(body, parseFunctionBody());
+
+
+    MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None));return result;
+}
+
+
+/*
+ interface Module : Node {
+    AssertedVarScope? scope;
+    FrozenArray<Directive> directives;
+    FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseModule()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceModule(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Module)");
+}
+
+
+/*
+ interface NewExpression : Node {
+    Expression callee;
+    Arguments arguments;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseNewExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceNewExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::NewExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
+
+
+
+    MOZ_TRY_DECL(callee, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(arguments, parseArguments());
+
+
+    auto result = arguments;
+    result->setKind(ParseNodeKind::New);
+    result->prepend(callee);return result;
+}
+
+
+/*
+ interface NewTargetExpression : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseNewTargetExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceNewTargetExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (NewTargetExpression)");
+}
+
+
+/*
+ interface ObjectAssignmentTarget : Node {
+    FrozenArray<AssignmentTargetProperty> properties;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseObjectAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ObjectAssignmentTarget)");
+}
+
+
+/*
+ interface ObjectBinding : Node {
+    FrozenArray<BindingProperty> properties;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseObjectBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceObjectBinding(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ObjectBinding)");
+}
+
+
+/*
+ interface ObjectExpression : Node {
+    FrozenArray<ObjectProperty> properties;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseObjectExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceObjectExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ObjectExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Properties }));
+
+
+
+    MOZ_TRY_DECL(properties, parseListOfObjectProperty());
+
+
+    auto result = properties;return result;
+}
+
+
+/*
+ interface ReturnStatement : Node {
+    Expression? expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseReturnStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceReturnStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ReturnStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Expression }));
+    if (!parseContext_->isFunctionBox()) {
+        // Return statements are permitted only inside functions.
+        return raiseInvalidKind("Toplevel Statement", kind);
+    }
+
+    parseContext_->functionBox()->usesReturn = true;
+
+
+    MOZ_TRY_DECL(expression, parseOptionalExpression());
+
+
+    TRY_DECL(result, factory_.newReturnStatement(expression, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface Script : Node {
+    AssertedVarScope? scope;
+    FrozenArray<Directive> directives;
+    FrozenArray<Statement> statements;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseScript()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceScript(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::Script);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Directives, BinField::Statements }));
+
+
+
+    MOZ_TRY(parseOptionalAssertedVarScope());
+
+
+
+
+    MOZ_TRY_DECL(directives, parseListOfDirective());
+
+
+
+
+    MOZ_TRY_DECL(statements, parseListOfStatement());
+
+
+    MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));return result;
+}
+
+
+/*
+ interface Setter : Node {
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    PropertyName name;
+    Parameter param;
+    FunctionBody body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSetter(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::Setter);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Param, BinField::Body }));
+    const auto isAsync = false;
+    const auto isGenerator = false;
+    MOZ_TRY_DECL(funbox, buildFunctionBox(
+        isGenerator ? GeneratorKind::Generator
+                    : GeneratorKind::NotGenerator,
+        isAsync ? FunctionAsyncKind::AsyncFunction
+                : FunctionAsyncKind::SyncFunction));
+
+    // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function.
+    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
+    TRY(funpc.init());
+    parseContext_->functionScope().useAsVarScope(parseContext_);
+    MOZ_ASSERT(parseContext_->isFunctionBox());
+
+    ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_);
+    TRY(lexicalScope.init(parseContext_));
+
+    MOZ_TRY(parseOptionalAssertedParameterScope());
+
+
+
+
+    MOZ_TRY(parseOptionalAssertedVarScope());
+
+
+
+
+    MOZ_TRY_DECL(name, parsePropertyName());
+
+
+
+
+    MOZ_TRY_DECL(param, parseParameter());
+
+
+
+
+    MOZ_TRY_DECL(body, parseFunctionBody());
+
+
+    TRY_DECL(params, factory_.newList(ParseNodeKind::ParamsBody, param));
+    MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::Setter));return result;
+}
+
+
+/*
+ interface ShorthandProperty : Node {
+    IdentifierExpression name;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseShorthandProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceShorthandProperty(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ShorthandProperty);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+
+
+
+    MOZ_TRY_DECL(name, parseIdentifierExpression());
+
+
+    if (!factory_.isUsableAsObjectPropertyName(name))
+        TRY_VAR(name, factory_.newObjectLiteralPropertyName(name->name(), tokenizer_->pos(start)));
+
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, name, AccessorType::None));return result;
+}
+
+
+/*
+ interface SpreadElement : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSpreadElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSpreadElement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SpreadElement)");
+}
+
+
+/*
+ interface StaticMemberAssignmentTarget : Node {
+    (Expression or Super) object;
+    IdentifierName property;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseStaticMemberAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Property }));
+
+
+
+    MOZ_TRY_DECL(object, parseExpressionOrSuper());
+
+
+
+    RootedAtom property(cx_);
+    MOZ_TRY(readString(&property));
+
+
+    TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));return result;
+}
+
+
+/*
+ interface StaticMemberExpression : Node {
+    (Expression or Super) object;
+    IdentifierName property;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseStaticMemberExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceStaticMemberExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Property }));
+
+
+
+    MOZ_TRY_DECL(object, parseExpressionOrSuper());
+
+
+
+    RootedAtom property(cx_);
+    MOZ_TRY(readString(&property));
+
+
+    TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));return result;
+}
+
+
+/*
+ interface Super : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSuper()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSuper(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Super)");
+}
+
+
+/*
+ interface SwitchCase : Node {
+    Expression test;
+    FrozenArray<Statement> consequent;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSwitchCase()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSwitchCase(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::SwitchCase);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent }));
+
+
+
+    MOZ_TRY_DECL(test, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(consequent, parseListOfStatement());
+
+
+    TRY_DECL(result, factory_.newCaseOrDefault(start, test, consequent));return result;
+}
+
+
+/*
+ interface SwitchDefault : Node {
+    FrozenArray<Statement> consequent;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSwitchDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSwitchDefault(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::SwitchDefault);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Consequent }));
+
+
+
+    MOZ_TRY_DECL(consequent, parseListOfStatement());
+
+
+    TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));return result;
+}
+
+
+/*
+ interface SwitchStatement : Node {
+    Expression discriminant;
+    FrozenArray<SwitchCase> cases;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSwitchStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSwitchStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::SwitchStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::Cases }));
+
+
+
+    MOZ_TRY_DECL(discriminant, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(cases, parseListOfSwitchCase());
+
+
+    TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
+    TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));return result;
+}
+
+
+/*
+ interface SwitchStatementWithDefault : Node {
+    Expression discriminant;
+    FrozenArray<SwitchCase> preDefaultCases;
+    SwitchDefault defaultCase;
+    FrozenArray<SwitchCase> postDefaultCases;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseSwitchStatementWithDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::SwitchStatementWithDefault);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases }));
+
+
+
+    MOZ_TRY_DECL(discriminant, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase());
+
+
+
+
+    MOZ_TRY_DECL(defaultCase, parseSwitchDefault());
+
+
+
+
+    MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase());
+
+
+    // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase`
+    auto cases = preDefaultCases;
+    factory_.addList(cases, defaultCase);
+    ParseNode* iter = postDefaultCases->pn_head;
+    while (iter) {
+        ParseNode* next = iter->pn_next;
+        factory_.addList(cases, iter);
+        iter = next;
+    }
+    TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
+    TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));return result;
+}
+
+
+/*
+ interface TemplateElement : Node {
+    string rawValue;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseTemplateElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceTemplateElement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (TemplateElement)");
+}
+
+
+/*
+ interface TemplateExpression : Node {
+    Expression? tag;
+    FrozenArray<(Expression or TemplateElement)> elements;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseTemplateExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceTemplateExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (TemplateExpression)");
+}
+
+
+/*
+ interface ThisExpression : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseThisExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceThisExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ThisExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields0(kind, fields));
+
+    if (parseContext_->isFunctionBox())
+        parseContext_->functionBox()->usesThis = true;
+
+    TokenPos pos = tokenizer_->pos(start);
+    ParseNode* thisName(nullptr);
+    if (parseContext_->sc()->thisBinding() == ThisBinding::Function)
+        TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_));
+
+    TRY_DECL(result, factory_.newThisLiteral(pos, thisName));return result;
+}
+
+
+/*
+ interface ThrowStatement : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseThrowStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceThrowStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ThrowStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Expression }));
+
+
+
+    MOZ_TRY_DECL(expression, parseExpression());
+
+
+    TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));return result;
+}
+
+
+/*
+ interface TryCatchStatement : Node {
+    Block body;
+    CatchClause catchClause;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseTryCatchStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceTryCatchStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::TryCatchStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause }));
+
+    ParseNode* body;
+    {
+        ParseContext::Statement stmt(parseContext_, StatementKind::Try);
+        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+        TRY(scope.init(parseContext_));
+        MOZ_TRY_VAR(body, parseBlock());
+
+    }
+
+
+
+    MOZ_TRY_DECL(catchClause, parseCatchClause());
+
+
+    TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, /* finally = */ nullptr));return result;
+}
+
+
+/*
+ interface TryFinallyStatement : Node {
+    Block body;
+    CatchClause? catchClause;
+    Block finalizer;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseTryFinallyStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceTryFinallyStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::TryFinallyStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause, BinField::Finalizer }));
+
+    ParseNode* body;
+    {
+        ParseContext::Statement stmt(parseContext_, StatementKind::Try);
+        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+        TRY(scope.init(parseContext_));
+        MOZ_TRY_VAR(body, parseBlock());
+
+    }
+
+
+
+    MOZ_TRY_DECL(catchClause, parseOptionalCatchClause());
+
+
+    ParseNode* finalizer;
+    {
+        ParseContext::Statement stmt(parseContext_, StatementKind::Finally);
+        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+        TRY(scope.init(parseContext_));
+        MOZ_TRY_VAR(finalizer, parseBlock());
+
+    }
+
+    TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, finalizer));return result;
+}
+
+
+/*
+ interface UnaryExpression : Node {
+    UnaryOperator operator;
+    Expression operand;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseUnaryExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceUnaryExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::UnaryExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Operand }));
+
+
+
+    MOZ_TRY_DECL(operator_, parseUnaryOperator());
+
+
+
+
+    MOZ_TRY_DECL(operand, parseExpression());
+
+
+    ParseNodeKind pnk;
+    switch (operator_) {
+      case UnaryOperator::Minus:
+        pnk = ParseNodeKind::Neg;
+        break;
+      case UnaryOperator::Plus:
+        pnk = ParseNodeKind::Pos;
+        break;
+      case UnaryOperator::Not:
+        pnk = ParseNodeKind::Not;
+        break;
+      case UnaryOperator::BitNot:
+        pnk = ParseNodeKind::BitNot;
+        break;
+      case UnaryOperator::Typeof: {
+        if (operand->isKind(ParseNodeKind::Name))
+            pnk = ParseNodeKind::TypeOfName;
+        else
+            pnk = ParseNodeKind::TypeOfExpr;
+        break;
+      }
+      case UnaryOperator::Void:
+        pnk = ParseNodeKind::Void;
+        break;
+      case UnaryOperator::Delete: {
+        switch (operand->getKind()) {
+          case ParseNodeKind::Name:
+            operand->setOp(JSOP_DELNAME);
+            pnk = ParseNodeKind::DeleteName;
+            break;
+          case ParseNodeKind::Dot:
+            pnk = ParseNodeKind::DeleteProp;
+            break;
+          case ParseNodeKind::Elem:
+            pnk = ParseNodeKind::DeleteElem;
+            break;
+          default:
+            pnk = ParseNodeKind::DeleteExpr;
+        }
+        break;
+      }
+    }
+    TRY_DECL(result, factory_.newUnary(pnk, start, operand));return result;
+}
+
+
+/*
+ interface UpdateExpression : Node {
+    bool isPrefix;
+    UpdateOperator operator;
+    SimpleAssignmentTarget operand;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseUpdateExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceUpdateExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::UpdateExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::IsPrefix, BinField::Operator, BinField::Operand }));
+
+
+
+    MOZ_TRY_DECL(isPrefix, readBool());
+
+
+
+
+    MOZ_TRY_DECL(operator_, parseUpdateOperator());
+
+
+
+
+    MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget());
+
+
+    ParseNodeKind pnk;
+    switch (operator_) {
+      case UpdateOperator::Incr:
+        pnk = isPrefix ? ParseNodeKind::PreIncrement
+                       : ParseNodeKind::PostIncrement;
+        break;
+      case UpdateOperator::Decr:
+        pnk = isPrefix ? ParseNodeKind::PreDecrement
+                       : ParseNodeKind::PostDecrement;
+        break;
+    }
+    TRY_DECL(result, factory_.newUnary(pnk, start, operand));return result;
+}
+
+
+/*
+ interface VariableDeclaration : Node {
+    VariableDeclarationKind kind;
+    FrozenArray<VariableDeclarator> declarators;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseVariableDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceVariableDeclaration(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::VariableDeclaration);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Kind, BinField::Declarators }));
+    AutoVariableDeclarationKind kindGuard(this);
+
+
+    MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
+    // Restored by `kindGuard`.
+    variableDeclarationKind_ = kind_;
+
+
+
+    MOZ_TRY_DECL(declarators, parseListOfVariableDeclarator());
+
+
+    // By specification, the list may not be empty.
+    if (declarators->pn_count == 0)
+        return raiseEmpty("VariableDeclaration");
+
+    ParseNodeKind pnk;
+    switch (kind_) {
+      case VariableDeclarationKind::Var:
+        pnk = ParseNodeKind::Var;
+        break;
+      case VariableDeclarationKind::Let:
+        pnk = ParseNodeKind::Let;
+        break;
+      case VariableDeclarationKind::Const:
+        pnk = ParseNodeKind::Const;
+        break;
+    }
+    declarators->setKind(pnk);
+    auto result = declarators;return result;
+}
+
+
+/*
+ interface VariableDeclarator : Node {
+    Binding binding;
+    Expression? init;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseVariableDeclarator()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceVariableDeclarator(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::VariableDeclarator);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Init }));
+
+
+
+    MOZ_TRY_DECL(binding, parseBinding());
+
+
+
+
+    MOZ_TRY_DECL(init, parseOptionalExpression());
+
+
+    ParseNode* result;
+    if (binding->isKind(ParseNodeKind::Name)) {
+        // `var foo [= bar]``
+        MOZ_TRY(checkBinding(binding->pn_atom->asPropertyName()));
+
+        TRY_VAR(result, factory_.newName(binding->pn_atom->asPropertyName(), tokenizer_->pos(start), cx_));
+        if (init)
+            result->pn_expr = init;
+    } else {
+        // `var pattern = bar`
+        if (!init) {
+            // Here, `init` is required.
+            return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init);
+        }
+
+        MOZ_CRASH("Unimplemented: AssertedScope check for BindingPattern variable declaration");
+        TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, binding, init));
+    }return result;
+}
+
+
+/*
+ interface WhileStatement : Node {
+    Expression test;
+    Statement body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseWhileStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceWhileStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::WhileStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body }));
+    ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop);
+
+
+    MOZ_TRY_DECL(test, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(result, factory_.newWhileStatement(start, test, body));return result;
+}
+
+
+/*
+ interface WithStatement : Node {
+    Expression object;
+    Statement body;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseWithStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceWithStatement(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::WithStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(object, parseExpression());
+
+
+
+
+    MOZ_TRY_DECL(body, parseStatement());
+
+
+    TRY_DECL(result, factory_.newWithStatement(start, object, body));return result;
+}
+
+
+/*
+ interface YieldExpression : Node {
+    Expression? expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseYieldExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceYieldExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (YieldExpression)");
+}
+
+
+/*
+ interface YieldStarExpression : Node {
+    Expression expression;
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseYieldStarExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceYieldStarExpression(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (YieldStarExpression)");
+}
+
+
+/*
+ interface _Null : Node {
+ }
+*/
+JS::Result<ParseNode*>
+BinASTParser::parseNull()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceNull(start, kind, fields));
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Null)");
+}
+
+
+
+// ----- String enums (autogenerated, by lexicographical order)
+/*
+enum BinaryOperator {
+    ",",
+    "||",
+    "&&",
+    "|",
+    "^",
+    "&",
+    "==",
+    "!=",
+    "===",
+    "!==",
+    "<",
+    "<=",
+    ">",
+    ">=",
+    "in",
+    "instanceof",
+    "<<",
+    ">>",
+    ">>>",
+    "+",
+    "-",
+    "*",
+    "/",
+    "%",
+    "**"
+};
+*/
+JS::Result<BinASTParser::BinaryOperator>
+BinASTParser::parseBinaryOperator()
+{
+    // Unoptimized implementation.
+    Chars chars(cx_);
+    MOZ_TRY(readString(chars));
+
+    if (chars == ",")
+        return BinaryOperator::Comma;
+    if (chars == "||")
+        return BinaryOperator::LogicalOr;
+    if (chars == "&&")
+        return BinaryOperator::LogicalAnd;
+    if (chars == "|")
+        return BinaryOperator::BitOr;
+    if (chars == "^")
+        return BinaryOperator::BitXor;
+    if (chars == "&")
+        return BinaryOperator::BitAnd;
+    if (chars == "==")
+        return BinaryOperator::Eq;
+    if (chars == "!=")
+        return BinaryOperator::Neq;
+    if (chars == "===")
+        return BinaryOperator::StrictEq;
+    if (chars == "!==")
+        return BinaryOperator::StrictNeq;
+    if (chars == "<")
+        return BinaryOperator::LessThan;
+    if (chars == "<=")
+        return BinaryOperator::LeqThan;
+    if (chars == ">")
+        return BinaryOperator::GreaterThan;
+    if (chars == ">=")
+        return BinaryOperator::GeqThan;
+    if (chars == "in")
+        return BinaryOperator::In;
+    if (chars == "instanceof")
+        return BinaryOperator::Instanceof;
+    if (chars == "<<")
+        return BinaryOperator::Lsh;
+    if (chars == ">>")
+        return BinaryOperator::Rsh;
+    if (chars == ">>>")
+        return BinaryOperator::Ursh;
+    if (chars == "+")
+        return BinaryOperator::Plus;
+    if (chars == "-")
+        return BinaryOperator::Minus;
+    if (chars == "*")
+        return BinaryOperator::Mul;
+    if (chars == "/")
+        return BinaryOperator::Div;
+    if (chars == "%")
+        return BinaryOperator::Mod;
+    if (chars == "**")
+        return BinaryOperator::Pow;
+
+    return raiseInvalidEnum("BinaryOperator", chars);
+}
+
+/*
+enum CompoundAssignmentOperator {
+    "+=",
+    "-=",
+    "*=",
+    "/=",
+    "%=",
+    "**=",
+    "<<=",
+    ">>=",
+    ">>>=",
+    "|=",
+    "^=",
+    "&="
+};
+*/
+JS::Result<BinASTParser::CompoundAssignmentOperator>
+BinASTParser::parseCompoundAssignmentOperator()
+{
+    // Unoptimized implementation.
+    Chars chars(cx_);
+    MOZ_TRY(readString(chars));
+
+    if (chars == "+=")
+        return CompoundAssignmentOperator::PlusAssign;
+    if (chars == "-=")
+        return CompoundAssignmentOperator::MinusAssign;
+    if (chars == "*=")
+        return CompoundAssignmentOperator::MulAssign;
+    if (chars == "/=")
+        return CompoundAssignmentOperator::DivAssign;
+    if (chars == "%=")
+        return CompoundAssignmentOperator::ModAssign;
+    if (chars == "**=")
+        return CompoundAssignmentOperator::PowAssign;
+    if (chars == "<<=")
+        return CompoundAssignmentOperator::LshAssign;
+    if (chars == ">>=")
+        return CompoundAssignmentOperator::RshAssign;
+    if (chars == ">>>=")
+        return CompoundAssignmentOperator::UrshAssign;
+    if (chars == "|=")
+        return CompoundAssignmentOperator::BitOrAssign;
+    if (chars == "^=")
+        return CompoundAssignmentOperator::BitXorAssign;
+    if (chars == "&=")
+        return CompoundAssignmentOperator::BitAndAssign;
+
+    return raiseInvalidEnum("CompoundAssignmentOperator", chars);
+}
+
+/*
+enum UnaryOperator {
+    "+",
+    "-",
+    "!",
+    "~",
+    "typeof",
+    "void",
+    "delete"
+};
+*/
+JS::Result<BinASTParser::UnaryOperator>
+BinASTParser::parseUnaryOperator()
+{
+    // Unoptimized implementation.
+    Chars chars(cx_);
+    MOZ_TRY(readString(chars));
+
+    if (chars == "+")
+        return UnaryOperator::Plus;
+    if (chars == "-")
+        return UnaryOperator::Minus;
+    if (chars == "!")
+        return UnaryOperator::Not;
+    if (chars == "~")
+        return UnaryOperator::BitNot;
+    if (chars == "typeof")
+        return UnaryOperator::Typeof;
+    if (chars == "void")
+        return UnaryOperator::Void;
+    if (chars == "delete")
+        return UnaryOperator::Delete;
+
+    return raiseInvalidEnum("UnaryOperator", chars);
+}
+
+/*
+enum UpdateOperator {
+    "++",
+    "--"
+};
+*/
+JS::Result<BinASTParser::UpdateOperator>
+BinASTParser::parseUpdateOperator()
+{
+    // Unoptimized implementation.
+    Chars chars(cx_);
+    MOZ_TRY(readString(chars));
+
+    if (chars == "++")
+        return UpdateOperator::Incr;
+    if (chars == "--")
+        return UpdateOperator::Decr;
+
+    return raiseInvalidEnum("UpdateOperator", chars);
+}
+
+/*
+enum VariableDeclarationKind {
+    "var",
+    "let",
+    "const"
+};
+*/
+JS::Result<BinASTParser::VariableDeclarationKind>
+BinASTParser::parseVariableDeclarationKind()
+{
+    // Unoptimized implementation.
+    Chars chars(cx_);
+    MOZ_TRY(readString(chars));
+
+    if (chars == "var")
+        return VariableDeclarationKind::Var;
+    if (chars == "let")
+        return VariableDeclarationKind::Let;
+    if (chars == "const")
+        return VariableDeclarationKind::Const;
+
+    return raiseInvalidEnum("VariableDeclarationKind", chars);
+}
+
+
+
+// ----- Lists (autogenerated, by lexicographical order)
+
+JS::Result<ParseNode*>
+BinASTParser::parseArguments()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
+        factory_.addList(/* list = */ result, /* child = */ item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfAssignmentTargetOrAssignmentTargetWithInitializer()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetOrAssignmentTargetWithInitializer)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfAssignmentTargetProperty()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetProperty)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfBindingProperty()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfBindingProperty)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfClassElement()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfClassElement)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfDirective()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseDirective());
+        factory_.addStatementToList(result, item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfExportFromSpecifier()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfExportFromSpecifier)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfExportLocalSpecifier()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfExportLocalSpecifier)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfExpressionOrTemplateElement()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfExpressionOrTemplateElement)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfIdentifierName()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfIdentifierName)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfImportDeclarationOrExportDeclarationOrStatement()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfImportDeclarationOrExportDeclarationOrStatement)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfImportSpecifier()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfImportSpecifier)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfObjectProperty()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newObjectLiteral(start));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseObjectProperty());
+        result->appendWithoutOrderAssumption(item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfOptionalBindingOrBindingWithInitializer()
+{
+    return raiseError("FIXME: Not implemented yet (ListOfOptionalBindingOrBindingWithInitializer)");
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfOptionalSpreadElementOrExpression()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newArrayLiteral(start));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseOptionalSpreadElementOrExpression());
+        if (item)
+            factory_.addArrayElement(result, item); // Infallible.
+        else
+            TRY(factory_.addElision(result, tokenizer_->pos(start)));
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfParameter()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    ParseNode* result = new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseParameter());
+        factory_.addList(/* list = */ result, /* item = */ item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfStatement()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseStatement());
+        factory_.addStatementToList(result, item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfSwitchCase()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseSwitchCase());
+        factory_.addCaseStatementToList(result, item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseListOfVariableDeclarator()
+{
+    uint32_t length;
+    AutoList guard(*tokenizer_);
+
+    const auto start = tokenizer_->offset();
+    TRY(tokenizer_->enterList(length, guard));
+    TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/,
+        tokenizer_->pos(start)));
+
+    for (uint32_t i = 0; i < length; ++i) {
+        MOZ_TRY_DECL(item, parseVariableDeclarator());
+        result->appendWithoutOrderAssumption(item);
+    }
+
+    TRY(guard.done());
+    return result;
+}
+
+
+    // ----- Default values (by lexicographical order)
+JS::Result<Ok>
+BinASTParser::parseOptionalAssertedBlockScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    Ok result;
+    if (kind == BinKind::_Null) {
+        result = Ok();
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseInterfaceAssertedBlockScope(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseOptionalAssertedParameterScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    Ok result;
+    if (kind == BinKind::_Null) {
+        result = Ok();
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseInterfaceAssertedParameterScope(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseOptionalAssertedVarScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    Ok result;
+    if (kind == BinKind::_Null) {
+        result = Ok();
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseInterfaceAssertedVarScope(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumAssignmentTarget(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalBindingIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalBindingOrBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumBindingOrBindingWithInitializer(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalCatchClause()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalIdentifierName()
+{
+    RootedAtom string(cx_);
+    MOZ_TRY(readMaybeString(&string));
+
+
+
+    return raiseError("FIXME: Not implemented yet (OptionalIdentifierName)");
+
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalLabel()
+{
+    RootedAtom string(cx_);
+    MOZ_TRY(readMaybeString(&string));
+
+
+
+    return raiseError("FIXME: Not implemented yet (OptionalLabel)");
+
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalSpreadElementOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+JS::Result<ParseNode*>
+BinASTParser::parseOptionalVariableDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    ParseNode* result;
+    if (kind == BinKind::_Null) {
+        result = nullptr;
+    } else {
+        const auto start = tokenizer_->offset();
+        MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(start, kind, fields));
+    }
+    TRY(guard.done());
+
+    return result;
+}
+
+
+
+#undef TRY
+#undef TRY_VAR
+#undef TRY_DECL
+#undef MOZ_TRY_DECL
+} // namespace frontend
+} // namespace js
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSource-auto.h
@@ -0,0 +1,341 @@
+// 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.
+
+// This file is meant to be included from the declaration
+// of class `BinASTParser`. The include may be public or private.
+
+
+// ----- Declaring string enums (by lexicographical order)
+enum class BinaryOperator {
+    Comma                     /* "," */,
+    LogicalOr                 /* "||" */,
+    LogicalAnd                /* "&&" */,
+    BitOr                     /* "|" */,
+    BitXor                    /* "^" */,
+    BitAnd                    /* "&" */,
+    Eq                        /* "==" */,
+    Neq                       /* "!=" */,
+    StrictEq                  /* "===" */,
+    StrictNeq                 /* "!==" */,
+    LessThan                  /* "<" */,
+    LeqThan                   /* "<=" */,
+    GreaterThan               /* ">" */,
+    GeqThan                   /* ">=" */,
+    In                        /* "in" */,
+    Instanceof                /* "instanceof" */,
+    Lsh                       /* "<<" */,
+    Rsh                       /* ">>" */,
+    Ursh                      /* ">>>" */,
+    Plus                      /* "+" */,
+    Minus                     /* "-" */,
+    Mul                       /* "*" */,
+    Div                       /* "/" */,
+    Mod                       /* "%" */,
+    Pow                       /* "**" */
+};
+
+enum class CompoundAssignmentOperator {
+    PlusAssign                /* "+=" */,
+    MinusAssign               /* "-=" */,
+    MulAssign                 /* "*=" */,
+    DivAssign                 /* "/=" */,
+    ModAssign                 /* "%=" */,
+    PowAssign                 /* "**=" */,
+    LshAssign                 /* "<<=" */,
+    RshAssign                 /* ">>=" */,
+    UrshAssign                /* ">>>=" */,
+    BitOrAssign               /* "|=" */,
+    BitXorAssign              /* "^=" */,
+    BitAndAssign              /* "&=" */
+};
+
+enum class UnaryOperator {
+    Plus                      /* "+" */,
+    Minus                     /* "-" */,
+    Not                       /* "!" */,
+    BitNot                    /* "~" */,
+    Typeof                    /* "typeof" */,
+    Void                      /* "void" */,
+    Delete                    /* "delete" */
+};
+
+enum class UpdateOperator {
+    Incr                      /* "++" */,
+    Decr                      /* "--" */
+};
+
+enum class VariableDeclarationKind {
+    Var                       /* "var" */,
+    Let                       /* "let" */,
+    Const                     /* "const" */
+};
+
+
+
+// ----- Sums of interfaces (by lexicographical order)
+// Implementations are autogenerated
+// `ParseNode*` may never be nullptr
+JS::Result<ParseNode*> parseAssignmentTarget();JS::Result<ParseNode*> parseAssignmentTargetOrAssignmentTargetWithInitializer();JS::Result<ParseNode*> parseAssignmentTargetPattern();JS::Result<ParseNode*> parseAssignmentTargetProperty();JS::Result<ParseNode*> parseBinding();JS::Result<ParseNode*> parseBindingOrBindingWithInitializer();JS::Result<ParseNode*> parseBindingPattern();JS::Result<ParseNode*> parseBindingProperty();JS::Result<ParseNode*> parseExportDeclaration();JS::Result<ParseNode*> parseExpression();JS::Result<ParseNode*> parseExpressionOrSuper();JS::Result<ParseNode*> parseExpressionOrTemplateElement();JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget();JS::Result<ParseNode*> parseFunctionBodyOrExpression();JS::Result<ParseNode*> parseFunctionDeclarationOrClassDeclarationOrExpression();JS::Result<ParseNode*> parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration();JS::Result<ParseNode*> parseImportDeclaration();JS::Result<ParseNode*> parseImportDeclarationOrExportDeclarationOrStatement();JS::Result<ParseNode*> parseIterationStatement();JS::Result<ParseNode*> parseLiteral();JS::Result<ParseNode*> parseMethodDefinition();JS::Result<ParseNode*> parseObjectProperty();JS::Result<ParseNode*> parseParameter();JS::Result<ParseNode*> parseProgram();JS::Result<ParseNode*> parsePropertyName();JS::Result<ParseNode*> parseSimpleAssignmentTarget();JS::Result<ParseNode*> parseSpreadElementOrExpression();JS::Result<ParseNode*> parseStatement();JS::Result<ParseNode*> parseVariableDeclarationOrExpression();JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumAssignmentTargetPattern(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumBindingPattern(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumFunctionBodyOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result<ParseNode*> parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);
+
+// ----- Interfaces (by lexicographical order)
+// Implementations are autogenerated
+// `ParseNode*` may never be nullptr
+JS::Result<ParseNode*> parseArrayAssignmentTarget();
+JS::Result<ParseNode*> parseArrayBinding();
+JS::Result<ParseNode*> parseArrayExpression();
+JS::Result<ParseNode*> parseArrowExpression();
+JS::Result<Ok> parseAssertedBlockScope();
+JS::Result<Ok> parseAssertedParameterScope();
+JS::Result<Ok> parseAssertedVarScope();
+JS::Result<ParseNode*> parseAssignmentExpression();
+JS::Result<ParseNode*> parseAssignmentTargetIdentifier();
+JS::Result<ParseNode*> parseAssignmentTargetPropertyIdentifier();
+JS::Result<ParseNode*> parseAssignmentTargetPropertyProperty();
+JS::Result<ParseNode*> parseAssignmentTargetWithInitializer();
+JS::Result<ParseNode*> parseAwaitExpression();
+JS::Result<ParseNode*> parseBinaryExpression();
+JS::Result<ParseNode*> parseBindingIdentifier();
+JS::Result<ParseNode*> parseBindingPropertyIdentifier();
+JS::Result<ParseNode*> parseBindingPropertyProperty();
+JS::Result<ParseNode*> parseBindingWithInitializer();
+JS::Result<ParseNode*> parseBlock();
+JS::Result<ParseNode*> parseBreakStatement();
+JS::Result<ParseNode*> parseCallExpression();
+JS::Result<ParseNode*> parseCatchClause();
+JS::Result<ParseNode*> parseClassDeclaration();
+JS::Result<ParseNode*> parseClassElement();
+JS::Result<ParseNode*> parseClassExpression();
+JS::Result<ParseNode*> parseCompoundAssignmentExpression();
+JS::Result<ParseNode*> parseComputedMemberAssignmentTarget();
+JS::Result<ParseNode*> parseComputedMemberExpression();
+JS::Result<ParseNode*> parseComputedPropertyName();
+JS::Result<ParseNode*> parseConditionalExpression();
+JS::Result<ParseNode*> parseContinueStatement();
+JS::Result<ParseNode*> parseDataProperty();
+JS::Result<ParseNode*> parseDebuggerStatement();
+JS::Result<ParseNode*> parseDirective();
+JS::Result<ParseNode*> parseDoWhileStatement();
+JS::Result<ParseNode*> parseEmptyStatement();
+JS::Result<ParseNode*> parseExport();
+JS::Result<ParseNode*> parseExportAllFrom();
+JS::Result<ParseNode*> parseExportDefault();
+JS::Result<ParseNode*> parseExportFrom();
+JS::Result<ParseNode*> parseExportFromSpecifier();
+JS::Result<ParseNode*> parseExportLocalSpecifier();
+JS::Result<ParseNode*> parseExportLocals();
+JS::Result<ParseNode*> parseExpressionStatement();
+JS::Result<ParseNode*> parseForInOfBinding();
+JS::Result<ParseNode*> parseForInStatement();
+JS::Result<ParseNode*> parseForOfStatement();
+JS::Result<ParseNode*> parseForStatement();
+JS::Result<ParseNode*> parseFormalParameters();
+JS::Result<ParseNode*> parseFunctionBody();
+JS::Result<ParseNode*> parseFunctionDeclaration();
+JS::Result<ParseNode*> parseFunctionExpression();
+JS::Result<ParseNode*> parseGetter();
+JS::Result<ParseNode*> parseIdentifierExpression();
+JS::Result<ParseNode*> parseIfStatement();
+JS::Result<ParseNode*> parseImport();
+JS::Result<ParseNode*> parseImportNamespace();
+JS::Result<ParseNode*> parseImportSpecifier();
+JS::Result<ParseNode*> parseLabelledStatement();
+JS::Result<ParseNode*> parseLiteralBooleanExpression();
+JS::Result<ParseNode*> parseLiteralInfinityExpression();
+JS::Result<ParseNode*> parseLiteralNullExpression();
+JS::Result<ParseNode*> parseLiteralNumericExpression();
+JS::Result<ParseNode*> parseLiteralPropertyName();
+JS::Result<ParseNode*> parseLiteralRegExpExpression();
+JS::Result<ParseNode*> parseLiteralStringExpression();
+JS::Result<ParseNode*> parseMethod();
+JS::Result<ParseNode*> parseModule();
+JS::Result<ParseNode*> parseNewExpression();
+JS::Result<ParseNode*> parseNewTargetExpression();
+JS::Result<ParseNode*> parseObjectAssignmentTarget();
+JS::Result<ParseNode*> parseObjectBinding();
+JS::Result<ParseNode*> parseObjectExpression();
+JS::Result<ParseNode*> parseReturnStatement();
+JS::Result<ParseNode*> parseScript();
+JS::Result<ParseNode*> parseSetter();
+JS::Result<ParseNode*> parseShorthandProperty();
+JS::Result<ParseNode*> parseSpreadElement();
+JS::Result<ParseNode*> parseStaticMemberAssignmentTarget();
+JS::Result<ParseNode*> parseStaticMemberExpression();
+JS::Result<ParseNode*> parseSuper();
+JS::Result<ParseNode*> parseSwitchCase();
+JS::Result<ParseNode*> parseSwitchDefault();
+JS::Result<ParseNode*> parseSwitchStatement();
+JS::Result<ParseNode*> parseSwitchStatementWithDefault();
+JS::Result<ParseNode*> parseTemplateElement();
+JS::Result<ParseNode*> parseTemplateExpression();
+JS::Result<ParseNode*> parseThisExpression();
+JS::Result<ParseNode*> parseThrowStatement();
+JS::Result<ParseNode*> parseTryCatchStatement();
+JS::Result<ParseNode*> parseTryFinallyStatement();
+JS::Result<ParseNode*> parseUnaryExpression();
+JS::Result<ParseNode*> parseUpdateExpression();
+JS::Result<ParseNode*> parseVariableDeclaration();
+JS::Result<ParseNode*> parseVariableDeclarator();
+JS::Result<ParseNode*> parseWhileStatement();
+JS::Result<ParseNode*> parseWithStatement();
+JS::Result<ParseNode*> parseYieldExpression();
+JS::Result<ParseNode*> parseYieldStarExpression();
+JS::Result<ParseNode*> parseNull();
+JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<Ok> parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceGetter(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields);
+JS::Result<ParseNode*> parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields);
+
+
+// ----- String enums (by lexicographical order)
+// Implementations are autogenerated
+JS::Result<BinASTParser::BinaryOperator> parseBinaryOperator();
+JS::Result<BinASTParser::CompoundAssignmentOperator> parseCompoundAssignmentOperator();
+JS::Result<BinASTParser::UnaryOperator> parseUnaryOperator();
+JS::Result<BinASTParser::UpdateOperator> parseUpdateOperator();
+JS::Result<BinASTParser::VariableDeclarationKind> parseVariableDeclarationKind();
+
+
+// ----- Lists (by lexicographical order)
+// Implementations are autogenerated
+JS::Result<ParseNode*> parseArguments();
+JS::Result<ParseNode*> parseListOfAssignmentTargetOrAssignmentTargetWithInitializer();
+JS::Result<ParseNode*> parseListOfAssignmentTargetProperty();
+JS::Result<ParseNode*> parseListOfBindingProperty();
+JS::Result<ParseNode*> parseListOfClassElement();
+JS::Result<ParseNode*> parseListOfDirective();
+JS::Result<ParseNode*> parseListOfExportFromSpecifier();
+JS::Result<ParseNode*> parseListOfExportLocalSpecifier();
+JS::Result<ParseNode*> parseListOfExpressionOrTemplateElement();
+JS::Result<ParseNode*> parseListOfIdentifierName();
+JS::Result<ParseNode*> parseListOfImportDeclarationOrExportDeclarationOrStatement();
+JS::Result<ParseNode*> parseListOfImportSpecifier();
+JS::Result<ParseNode*> parseListOfObjectProperty();
+JS::Result<ParseNode*> parseListOfOptionalBindingOrBindingWithInitializer();
+JS::Result<ParseNode*> parseListOfOptionalSpreadElementOrExpression();
+JS::Result<ParseNode*> parseListOfParameter();
+JS::Result<ParseNode*> parseListOfStatement();
+JS::Result<ParseNode*> parseListOfSwitchCase();
+JS::Result<ParseNode*> parseListOfVariableDeclarator();
+
+
+// ----- Default values (by lexicographical order)
+// Implementations are autogenerated
+JS::Result<Ok> parseOptionalAssertedBlockScope();
+JS::Result<Ok> parseOptionalAssertedParameterScope();
+JS::Result<Ok> parseOptionalAssertedVarScope();
+JS::Result<ParseNode*> parseOptionalAssignmentTarget();
+JS::Result<ParseNode*> parseOptionalBinding();
+JS::Result<ParseNode*> parseOptionalBindingIdentifier();
+JS::Result<ParseNode*> parseOptionalBindingOrBindingWithInitializer();
+JS::Result<ParseNode*> parseOptionalCatchClause();
+JS::Result<ParseNode*> parseOptionalExpression();
+JS::Result<ParseNode*> parseOptionalIdentifierName();
+JS::Result<ParseNode*> parseOptionalLabel();
+JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression();
+JS::Result<ParseNode*> parseOptionalStatement();
+JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression();
+
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -115,45 +115,17 @@ using AutoList = BinTokenReaderTester::A
 using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple;
 using AutoTuple = BinTokenReaderTester::AutoTuple;
 using BinFields = BinTokenReaderTester::BinFields;
 using Chars = BinTokenReaderTester::Chars;
 using NameBag = GCHashSet<JSString*>;
 using Names = GCVector<JSString*, 8>;
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
 
-namespace {
-    // Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
-    // a string literal (and ONLY a string literal).
-    template<size_t N>
-    bool operator==(const Chars& left, const char (&right)[N]) {
-        return BinTokenReaderTester::equals(left, right);
-    }
-
-    bool isMethod(BinKind kind) {
-        switch (kind) {
-          case BinKind::ObjectMethod:
-          case BinKind::ObjectGetter:
-          case BinKind::ObjectSetter:
-            return true;
-          default:
-            return false;
-        }
-    }
-
-#if defined(DEBUG)
-    bool isMethodOrFunction(BinKind kind) {
-        if (isMethod(kind))
-            return true;
-        if (kind == BinKind::FunctionExpression || kind == BinKind::FunctionDeclaration)
-            return true;
-        return false;
-    }
-#endif // defined(DEBUG)
-}
+// ------------- Toplevel constructions
 
 JS::Result<ParseNode*>
 BinASTParser::parse(const Vector<uint8_t>& data)
 {
     return parse(data.begin(), data.length());
 }
 
 JS::Result<ParseNode*>
@@ -187,181 +159,152 @@ BinASTParser::parseAux(const uint8_t* st
     Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_, parseContext_);
     if (!bindings)
         return cx_->alreadyReportedError();
     globalsc.bindings = *bindings;
 
     return result; // Magic conversion to Ok.
 }
 
-Result<ParseNode*>
-BinASTParser::parseProgram()
+JS::Result<FunctionBox*>
+BinASTParser::buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind)
 {
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
+    // Allocate the function before walking down the tree.
+    RootedFunction fun(cx_);
+    TRY_VAR(fun, NewFunctionWithProto(cx_,
+            /* native = */ nullptr,
+            /* nargs placeholder = */ 0,
+            JSFunction::INTERPRETED_NORMAL,
+            /* enclosingEnv = */ nullptr,
+            /* name (placeholder) = */ nullptr,
+            /* proto = */ nullptr,
+            gc::AllocKind::FUNCTION,
+            TenuredObject
+    ));
+    TRY_DECL(funbox, alloc_.new_<FunctionBox>(cx_,
+        traceListHead_,
+        fun,
+        /* toStringStart = */ 0,
+        Directives(parseContext_),
+        /* extraWarning = */ false,
+        generatorKind,
+        functionAsyncKind));
 
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::Program)
-        return this->raiseInvalidKind("Program", kind);
-
-    ParseNode* result;
-    MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields));
-
-    TRY(guard.done());
-    return result;
+    traceListHead_ = funbox;
+    FunctionSyntaxKind syntax = PrimaryExpression; // FIXME - What if we're assigning?
+    // FIXME: The only thing we need to know is whether this is a
+    // ClassConstructor/DerivedClassConstructor
+    funbox->initWithEnclosingParseContext(parseContext_, syntax);
+    return funbox;
 }
 
 JS::Result<ParseNode*>
-BinASTParser::parseBlockStatement()
+BinASTParser::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
+                            ParseNode* params, ParseNode* body, FunctionBox* funbox)
 {
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
+    TokenPos pos = tokenizer_->pos(start);
+
+    RootedAtom atom((cx_));
+    if (name)
+        atom = name->name();
+
+
+    funbox->function()->setArgCount(uint16_t(params->pn_count));
+    funbox->function()->initAtom(atom);
+
+    // ParseNode represents the body as concatenated after the params.
+    params->appendWithoutOrderAssumption(body);
 
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-    switch (kind) {
-      default:
-        return raiseInvalidKind("BlockStatement", kind);
-      case BinKind::BlockStatement:
-        MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields));
-        break;
+    TRY_DECL(result, kind == BinKind::FunctionDeclaration
+                     ? factory_.newFunctionStatement(pos)
+                     : factory_.newFunctionExpression(pos));
+
+    factory_.setFunctionBox(result, funbox);
+    factory_.setFunctionFormalParametersAndBody(result, params);
+
+    HandlePropertyName dotThis = cx_->names().dotThis;
+    const bool declareThis = hasUsedName(dotThis) ||
+                             funbox->bindingsAccessedDynamically() ||
+                             funbox->isDerivedClassConstructor();
+
+    if (declareThis) {
+        ParseContext::Scope& funScope = parseContext_->functionScope();
+        ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
+        MOZ_ASSERT(!p);
+        TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var,
+                                     DeclaredNameInfo::npos));
+        funbox->setHasThisBinding();
     }
 
+    TRY_DECL(bindings,
+             NewFunctionScopeData(cx_, parseContext_->functionScope(),
+                                  /* hasParameterExprs = */ false, alloc_, parseContext_));
+
+    funbox->functionScopeBindings().set(*bindings);
+
+    return result;
+}
+
+JS::Result<Ok>
+BinASTParser::parseAndUpdateCapturedNames()
+{
+    // For the moment, we do not attempt to validate the list of captured names.
+    AutoList guard(*tokenizer_);
+    uint32_t length = 0;
+
+    TRY(tokenizer_->enterList(length, guard));
+    RootedAtom name(cx_);
+    for (uint32_t i = 0; i < length; ++i) {
+        name = nullptr;
+
+        MOZ_TRY(readString(&name));
+    }
     TRY(guard.done());
-    return result;
+    return Ok();
 }
 
 JS::Result<Ok>
 BinASTParser::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind)
 {
     AutoList guard(*tokenizer_);
     uint32_t length = 0;
 
     TRY(tokenizer_->enterList(length, guard));
     RootedAtom name(cx_);
     for (uint32_t i = 0; i < length; ++i) {
         name = nullptr;
 
         MOZ_TRY(readString(&name));
         auto ptr = scope.lookupDeclaredNameForAdd(name);
-        if (ptr) {
-            if (kind == DeclarationKind::Let || kind == DeclarationKind::Const)
-                return raiseError("Variable redeclaration");
-
-#if defined(DEBUG)
-            // FIXME: Fix binjs-ref.
-            fprintf(stderr, "Weird: `var` redeclaration. Check encoder: ");
-            name->dump();
-            fprintf(stderr, "\n");
-#endif // defined(DEBUG)
-            continue;
-        }
+        if (ptr)
+            return raiseError("Variable redeclaration");
 
         TRY(scope.addDeclaredName(parseContext_, ptr, name.get(), kind, tokenizer_->offset()));
     }
     TRY(guard.done());
     return Ok();
 }
 
 JS::Result<Ok>
-BinASTParser::parseAndUpdateCurrentScope()
+BinASTParser::checkBinding(JSAtom* name)
 {
-    return parseAndUpdateScope(parseContext_->varScope(), *parseContext_->innermostScope());
-}
-
-JS::Result<Ok>
-BinASTParser::parseAndUpdateScope(ParseContext::Scope& varScope, ParseContext::Scope& letScope)
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
+    // Check that the variable appears in the corresponding scope.
+    ParseContext::Scope& scope =
+        variableDeclarationKind_ == VariableDeclarationKind::Var
+        ? parseContext_->varScope()
+        : *parseContext_->innermostScope();
 
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    switch (kind) {
-      default:
-        return raiseInvalidKind("Scope", kind);
-      case BinKind::BINJS_Scope:
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::BINJS_HasDirectEval:
-                MOZ_TRY(readBool()); // Currently ignored.
-                break;
-              case BinField::BINJS_LetDeclaredNames:
-                MOZ_TRY(parseAndUpdateScopeNames(letScope, DeclarationKind::Let));
-                break;
-              case BinField::BINJS_ConstDeclaredNames:
-                MOZ_TRY(parseAndUpdateScopeNames(letScope, DeclarationKind::Const));
-                break;
-              case BinField::BINJS_VarDeclaredNames:
-                MOZ_TRY(parseAndUpdateScopeNames(varScope, DeclarationKind::Var));
-                break;
-              case BinField::BINJS_CapturedNames: {
-                Rooted<Maybe<Names>> names(cx_); //FIXME: Currently ignored.
-                MOZ_TRY(parseStringList(&names));
-                break;
-              }
-              default:
-                return raiseInvalidField("Scope", field);
-            }
-        }
-        break;
-    }
+    auto ptr = scope.lookupDeclaredName(name->asPropertyName());
+    if (!ptr)
+        return raiseMissingVariableInAssertedScope(name);
 
-    TRY(guard.done());
     return Ok();
 }
 
 JS::Result<ParseNode*>
-BinASTParser::parseBlockStatementAux(const BinKind kind, const BinFields& fields)
-{
-    ParseContext::Statement stmt(parseContext_, StatementKind::Block);
-    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
-    TRY(scope.init(parseContext_));
-
-    ParseNode* body(nullptr);
-    ParseNode* directives(nullptr); // FIXME: Largely ignored
-
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::BINJS_Scope:
-            MOZ_TRY(parseAndUpdateCurrentScope());
-            break;
-          case BinField::Body:
-            MOZ_TRY_VAR(body, parseStatementList());
-            break;
-          case BinField::Directives:
-            if (kind != BinKind::Program)
-                return raiseInvalidField("BlockStatement", field);
-            MOZ_TRY_VAR(directives, parseDirectiveList());
-            break;
-          default:
-            return raiseInvalidField("BlockStatement", field);
-        }
-    }
-
-    // In case of absent optional fields, inject default values.
-    if (!body)
-        TRY_VAR(body, factory_.newStatementList(tokenizer_->pos()));
-
-    MOZ_TRY_VAR(body, appendDirectivesToBody(body, directives));
-
-    ParseNode* result;
-    if (kind == BinKind::Program) {
-        result = body;
-    } else {
-        TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
-        TRY_VAR(result, factory_.newLexicalScope(*bindings, body));
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
 BinASTParser::appendDirectivesToBody(ParseNode* body, ParseNode* directives)
 {
     ParseNode* result = body;
     if (directives && directives->pn_count >= 1) {
         MOZ_ASSERT(directives->isArity(PN_LIST));
 
         // Convert directive list to a list of strings.
         TRY_DECL(prefix, factory_.newStatementList(directives->pn_head->pn_pos));
@@ -384,2004 +327,62 @@ BinASTParser::appendDirectivesToBody(Par
         result->checkListConsistency();
 #endif // defined(DEBUG)
     }
 
     return result;
 }
 
 JS::Result<Ok>
-BinASTParser::parseStringList(MutableHandle<Maybe<Names>> out)
-{
-    MOZ_ASSERT(out.get().isNothing()); // Sanity check: the node must not have been parsed yet.
-
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    Names result(cx_);
-
-    TRY(tokenizer_->enterList(length, guard));
-    if (!result.reserve(length))
-        return raiseOOM();
-
-    RootedAtom string(cx_);
-    for (uint32_t i = 0; i < length; ++i) {
-        string = nullptr;
-
-        MOZ_TRY(readString(&string));
-        result.infallibleAppend(Move(string)); // Checked in the call to `reserve`.
-    }
-
-    TRY(guard.done());
-    out.set(Move(Some(Move(result))));
-    return Ok();
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseStatementList()
-{
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    TRY_DECL(result, factory_.newStatementList(tokenizer_->pos()));
-
-    TRY(tokenizer_->enterList(length, guard));
-    for (uint32_t i = 0; i < length; ++i) {
-        BinKind kind;
-        BinFields fields(cx_);
-        AutoTaggedTuple guard(*tokenizer_);
-
-        ParseNode* statement(nullptr);
-
-        TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-        switch (kind) {
-          case BinKind::FunctionDeclaration:
-            MOZ_TRY_VAR(statement, parseFunctionAux(kind, fields));
-            break;
-          default:
-            MOZ_TRY_VAR(statement, parseStatementAux(kind, fields));
-            break;
-        }
-
-        TRY(guard.done());
-        result->appendWithoutOrderAssumption(statement);
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseStatement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    MOZ_TRY_VAR(result, parseStatementAux(kind, fields));
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseStatementAux(const BinKind kind, const BinFields& fields)
+BinASTParser::readString(MutableHandleAtom out)
 {
-    const size_t start = tokenizer_->offset();
-
-    ParseNode* result(nullptr);
-    switch (kind) {
-      case BinKind::EmptyStatement: {
-        TRY_VAR(result, factory_.newEmptyStatement(tokenizer_->pos(start)));
-        break;
-      }
-      case BinKind::BlockStatement:
-        MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields));
-        break;
-      case BinKind::ExpressionStatement:
-        MOZ_TRY_VAR(result, parseExpressionStatementAux(kind, fields));
-        break;
-      case BinKind::DebuggerStatement: {
-        TRY_VAR(result, factory_.newDebuggerStatement(tokenizer_->pos(start)));
-        break;
-      }
-      case BinKind::WithStatement: {
-        ParseNode* body(nullptr);
-        ParseNode* expr(nullptr);
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Body:
-                MOZ_TRY_VAR(body, parseStatement());
-                break;
-              case BinField::Object:
-                MOZ_TRY_VAR(expr, parseExpression());
-                break;
-              default:
-                return raiseInvalidField("WithStatement", field);
-            }
-        }
-
-        if (!body)
-            return raiseMissingField("WithStatement", BinField::Body);
-        if (!expr)
-            return raiseMissingField("WithStatement", BinField::Object);
-
-        TRY_VAR(result, factory_.newWithStatement(start, expr, body));
-
-        break;
-      }
-      case BinKind::ReturnStatement: {
-        if (!parseContext_->isFunctionBox()) {
-            // Return statements are permitted only inside functions.
-            return raiseInvalidKind("Toplevel Statement", kind);
-        }
-        parseContext_->functionBox()->usesReturn = true;
-
-        ParseNode* arg(nullptr);
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Argument:
-                MOZ_TRY_VAR(arg, parseExpression());
-                break;
-              default:
-                return raiseInvalidField("ReturnStatement", field);
-            }
-        }
-
-        TRY_VAR(result, factory_.newReturnStatement(arg, tokenizer_->pos(start)));
-
-        break;
-      }
-      case BinKind::LabeledStatement: {
-        // We check for the existence of the jump target when parsing `break label;` or `continue label;`.
-        ParseContext::Statement stmt(parseContext_, StatementKind::Label);
-        ParseNode* label(nullptr);
-        ParseNode* body(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Label:
-                MOZ_TRY_VAR(label, parseIdentifier());
-                break;
-              case BinField::Body: {
-                if (!label)  // By order of fields, `label` MUST always be before `body` in the file.
-                    return raiseMissingField("LabeledStatement", BinField::Label);
-                MOZ_ASSERT(label->name());
-                ParseContext::LabelStatement stmt(parseContext_, label->name());
-                MOZ_TRY_VAR(body, parseStatement());
-                break;
-              }
-              default:
-                return raiseInvalidField("LabeledStatement", field);
-            }
-        }
-
-        if (!label)
-            return raiseMissingField("LabeledStatement", BinField::Label);
-        if (!body)
-            return raiseMissingField("LabeledStatement", BinField::Body);
-
-        TRY_VAR(result, factory_.newLabeledStatement(label->name(), body, start));
-
-        break;
-      }
-
-      case BinKind::BreakStatement:
-      case BinKind::ContinueStatement:
-        MOZ_TRY_VAR(result, parseBreakOrContinueStatementAux(kind, fields));
-        break;
-
-      case BinKind::IfStatement: {
-        ParseContext::Statement stmt(parseContext_, StatementKind::If);
-
-        ParseNode* test(nullptr);
-        ParseNode* consequent(nullptr);
-        ParseNode* alternate(nullptr); // Optional
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Test:
-                MOZ_TRY_VAR(test, parseExpression());
-                break;
-              case BinField::Consequent:
-                MOZ_TRY_VAR(consequent, parseStatement());
-                break;
-              case BinField::Alternate:
-                MOZ_TRY_VAR(alternate, parseStatement());
-                break;
-              default:
-                return raiseInvalidField("IfStatement", field);
-            }
-        }
-
-        if (!test)
-            return raiseMissingField("IfStatement", BinField::Test);
-        if (!consequent)
-            return raiseMissingField("IfStatement", BinField::Consequent);
-
-        TRY_VAR(result, factory_.newIfStatement(start, test, consequent, alternate));
-
-        break;
-      }
-      case BinKind::SwitchStatement: {
-        ParseContext::Statement stmt(parseContext_, StatementKind::Switch);
-        ParseNode* discriminant(nullptr);
-        ParseNode* cases(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Discriminant: {
-                MOZ_TRY_VAR(discriminant, parseExpression());
-                break;
-              }
-              case BinField::Cases: {
-                MOZ_TRY_VAR(cases, parseSwitchCaseList());
-                break;
-              }
-              default:
-                return raiseInvalidField("SwitchStatement", field);
-            }
-        }
-
-        if (!discriminant)
-            return raiseMissingField("SwitchStatement", BinField::Discriminant);
-        if (!cases) {
-            TRY_VAR(cases, factory_.newStatementList(tokenizer_->pos()));
-
-            TRY_VAR(cases, factory_.newLexicalScope(nullptr, cases));
-        }
-
-        TRY_VAR(result, factory_.newSwitchStatement(start, discriminant, cases));
-
-        break;
-      }
-
-      case BinKind::ThrowStatement: {
-        ParseNode* arg(nullptr);
-        for (auto field : fields) {
-            if (field != BinField::Argument)
-                return raiseInvalidField("ThrowStatement", field);
-
-            MOZ_TRY_VAR(arg, parseExpression());
-        }
-
-        if (!arg)
-            return raiseMissingField("ThrowStatement", BinField::Argument);
-
-        TRY_VAR(result, factory_.newThrowStatement(arg, tokenizer_->pos(start)));
-
-        break;
-      }
-
-      case BinKind::TryStatement: {
-        ParseNode* block(nullptr);
-        ParseNode* handler(nullptr);
-        ParseNode* finalizer(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Block: {
-                ParseContext::Statement stmt(parseContext_, StatementKind::Try);
-                ParseContext::Scope scope(cx_, parseContext_, usedNames_);
-                TRY(scope.init(parseContext_));
-                MOZ_TRY_VAR(block, parseBlockStatement());
-                break;
-              }
-              case BinField::Handler:
-                MOZ_TRY_VAR(handler, parseCatchClause());
-                break;
-
-              case BinField::Finalizer: {
-                ParseContext::Statement stmt(parseContext_, StatementKind::Finally);
-                ParseContext::Scope scope(cx_, parseContext_, usedNames_);
-                TRY(scope.init(parseContext_));
-                MOZ_TRY_VAR(finalizer, parseBlockStatement());
-                break;
-              }
-
-              default:
-                return raiseInvalidField("TryStatement", field);
-            }
-        }
-
-        if (!block)
-            return raiseMissingField("TryStatement", BinField::Handler);
-        if (!handler && !finalizer)
-            return raiseMissingField("TryStatement (without catch)", BinField::Finalizer);
-
-        TRY_VAR(result, factory_.newTryStatement(start, block, handler, finalizer));
-        break;
-      }
-
-      case BinKind::WhileStatement:
-      case BinKind::DoWhileStatement: {
-        ParseContext::Statement stmt(parseContext_, kind == BinKind::WhileStatement ? StatementKind::WhileLoop : StatementKind::DoLoop);
-        ParseNode* test(nullptr);
-        ParseNode* body(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Test:
-                MOZ_TRY_VAR(test, parseExpression());
-                break;
-              case BinField::Body:
-                MOZ_TRY_VAR(body, parseStatement());
-                break;
-              default:
-                return raiseInvalidField("WhileStatement | DoWhileStatement", field);
-            }
-        }
-
-        if (!test)
-            return raiseMissingField("WhileStatement | DoWhileStatement", BinField::Test);
-        if (!body)
-            return raiseMissingField("WhileStatement | DoWhileStatement", BinField::Body);
-
-        if (kind == BinKind::WhileStatement)
-            TRY_VAR(result, factory_.newWhileStatement(start, test, body));
-        else
-            TRY_VAR(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
-
-        break;
-      }
-      case BinKind::ForStatement: {
-        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_);
-        TRY(scope.init(parseContext_));
-        ParseNode* init(nullptr); // Optional
-        ParseNode* test(nullptr); // Optional
-        ParseNode* update(nullptr); // Optional
-        ParseNode* body(nullptr); // Required
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Init:
-                MOZ_TRY_VAR(init, parseForInit());
-                break;
-              case BinField::Test:
-                MOZ_TRY_VAR(test, parseExpression());
-                break;
-              case BinField::Update:
-                MOZ_TRY_VAR(update, parseExpression());
-                break;
-              case BinField::BINJS_Scope: // The scope always appears before the body.
-                MOZ_TRY(parseAndUpdateCurrentScope());
-                break;
-              case BinField::Body:
-                MOZ_TRY_VAR(body, parseStatement());
-                break;
-              default:
-                return raiseInvalidField("ForStatement", field);
-            }
-        }
-
-        if (!body)
-            return raiseMissingField("ForStatement", BinField::Body);
-
-        TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start)));
-        TRY_VAR(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0));
-
-        if (!scope.isEmpty()) {
-            TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
-            TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
-        }
-
-        break;
-      }
-      case BinKind::ForInStatement: {
-        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 `BINJS_Scope`.
-        ParseContext::Scope scope(cx_, parseContext_, usedNames_);
-        TRY(scope.init(parseContext_));
-        ParseNode* left(nullptr);
-        ParseNode* right(nullptr);
-        ParseNode* body(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Left:
-                MOZ_TRY_VAR(left, parseForInInit());
-                break;
-              case BinField::Right:
-                MOZ_TRY_VAR(right, parseExpression());
-                break;
-              case BinField::Body:
-                MOZ_TRY_VAR(body, parseStatement());
-                break;
-              case BinField::BINJS_Scope:
-                MOZ_TRY(parseAndUpdateCurrentScope());
-                break;
-              default:
-                return raiseInvalidField("ForInStatement", field);
-            }
-        }
-
-        if (!left)
-            return raiseMissingField("ForInStatement", BinField::Left);
-        if (!right)
-            return raiseMissingField("ForInStatement", BinField::Right);
-        if (!body)
-            return raiseMissingField("ForInStatement", BinField::Body);
-
-        TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right,
-                                                    tokenizer_->pos(start)));
-        TRY_VAR(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0));
-
-        if (!scope.isEmpty()) {
-            TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
-            TRY_VAR(result, factory_.newLexicalScope(*bindings, result));
-        }
-        break;
-      }
-
-      case BinKind::VariableDeclaration:
-        MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields));
-        break;
-
-      default:
-        return raiseInvalidKind("Statement", kind);
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseBreakOrContinueStatementAux(const BinKind kind, const BinFields& fields)
-{
-    const auto start = tokenizer_->offset();
-    ParseNode* label(nullptr);
-
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Label:
-            MOZ_TRY_VAR(label, parsePattern());
-
-            if (label && !label->isKind(ParseNodeKind::Name))
-                return raiseError("ContinueStatement | BreakStatement - Label MUST be an identifier"); // FIXME: This should be changed in the grammar.
-
-            break;
-          default:
-            return raiseInvalidField("ContinueStatement", field);
-        }
-    }
+    MOZ_ASSERT(!out);
 
-    TokenPos pos = tokenizer_->pos(start);
-    ParseNode* result;
-    if (kind == BinKind::ContinueStatement) {
-#if 0 // FIXME: We probably need to fix the AST before making this check.
-        auto validity = parseContext_->checkContinueStatement(label ? label->name() : 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");
-            }
-        }
-#endif // 0
-        // Ok, this is a valid continue statement.
-        TRY_VAR(result, factory_.newContinueStatement(label ? label->name() : nullptr, pos));
-    } else {
-#if 0 // FIXME: We probably need to fix the AST before making this check.
-        auto validity = parseContext_->checkBreakStatement(label ? label->name() : nullptr);
-        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");
-            }
-        }
-#endif // 0
-        // Ok, this is a valid break statement.
-        TRY_VAR(result, factory_.newBreakStatement(label ? label->name() : nullptr, pos));
-    }
-
-    MOZ_ASSERT(result);
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseForInit()
-{
-    // This can be either a VarDecl or an Expression.
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    BinKind kind;
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-
-    switch (kind) {
-      case BinKind::VariableDeclaration:
-        MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields));
-        break;
-      default:
-        // Parse as expression
-        MOZ_TRY_VAR(result, parseExpressionAux(kind, fields));
-        break;
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseForInInit()
-{
-    // This can be either a VarDecl or a Pattern.
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    BinKind kind;
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-
-    switch (kind) {
-      case BinKind::VariableDeclaration:
-        MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields));
-        break;
-      default:
-        // Parse as expression. Not a joke: http://www.ecma-international.org/ecma-262/5.1/index.html#sec-12.6.4 .
-        MOZ_TRY_VAR(result, parseExpressionAux(kind, fields));
-        break;
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(isMethodOrFunction(kind));
-
-    const size_t start = tokenizer_->offset();
-
-    ParseNode* id(nullptr);
-    ParseNode* params(nullptr);
-    ParseNode* body(nullptr);
-    ParseNode* directives(nullptr); // Largely ignored for the moment.
-    ParseNode* key(nullptr);  // Methods only
-
-    // Allocate the function before walking down the tree.
-    RootedFunction fun(cx_);
-    TRY_VAR(fun, NewFunctionWithProto(cx_,
-            /*native*/nullptr,
-            /*nargs ?*/0,
-            /*flags */ JSFunction::INTERPRETED_NORMAL,
-            /*enclosing env*/nullptr,
-            /*name*/ nullptr, // Will be known later
-            /*proto*/ nullptr,
-            /*alloc*/gc::AllocKind::FUNCTION,
-            TenuredObject
-    ));
-    TRY_DECL(funbox, alloc_.new_<FunctionBox>(cx_,
-        traceListHead_,
-        fun,
-        /* toStringStart = */0,
-        /* directives = */Directives(parseContext_),
-        /* extraWarning = */false,
-        GeneratorKind::NotGenerator,
-        FunctionAsyncKind::SyncFunction
-    ));
-
-    traceListHead_ = funbox;
-
-    FunctionSyntaxKind syntax;
-    switch (kind) {
-      case BinKind::FunctionDeclaration:
-        syntax = Statement;
-        break;
-      case BinKind::FunctionExpression:
-        syntax = PrimaryExpression; // FIXME: Probably doesn't work.
-        break;
-      case BinKind::ObjectMethod:
-        syntax = Method;
-        break;
-      case BinKind::ObjectGetter:
-        syntax = Getter;
-        break;
-      case BinKind::ObjectSetter:
-        syntax = Setter;
-        break;
-      default:
-        MOZ_CRASH("Invalid FunctionSyntaxKind"); // Checked above.
-    }
-    funbox->initWithEnclosingParseContext(parseContext_, syntax);
-
-    // Container scopes.
-    ParseContext::Scope& varScope = parseContext_->varScope();
-    ParseContext::Scope* letScope = parseContext_->innermostScope();
-
-    // Push a new ParseContext.
-    BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr);
-    TRY(funpc.init());
-    parseContext_->functionScope().useAsVarScope(parseContext_);
-    MOZ_ASSERT(parseContext_->isFunctionBox());
-
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Id:
-            MOZ_TRY_VAR(id, parseIdentifier());
-            break;
-          case BinField::Params:
-            MOZ_TRY_VAR(params, parseArgumentList());
-            break;
-          case BinField::BINJS_Scope:
-            // This scope information affects the scopes contained in the function body. MUST appear before the `body`.
-            MOZ_TRY(parseAndUpdateScope(varScope, *letScope));
-            break;
-          case BinField::Directives:
-            MOZ_TRY_VAR(directives, parseDirectiveList());
-            break;
-          case BinField::Body:
-            MOZ_TRY_VAR(body, parseBlockStatement());
-            break;
-          case BinField::Key:
-            if (!isMethod(kind))
-                return raiseInvalidField("Functions (unless defined as methods)", field);
-
-            MOZ_TRY_VAR(key, parseObjectPropertyName());
-            break;
-          default:
-            return raiseInvalidField("Function", field);
-        }
-    }
-
-    // Inject default values for absent fields.
-    if (!params)
-        TRY_VAR(params, new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos()));
-
-    if (!body)
-        TRY_VAR(body, factory_.newStatementList(tokenizer_->pos()));
-
-    if (kind == BinKind::FunctionDeclaration && !id) {
-        // The name is compulsory only for function declarations.
-        return raiseMissingField("FunctionDeclaration", BinField::Id);
-    }
-
-    // Reject if required values are missing.
-    if (isMethod(kind) && !key)
-        return raiseMissingField("method", BinField::Key);
-
-    if (id)
-        fun->initAtom(id->pn_atom);
-
-    MOZ_ASSERT(params->isArity(PN_LIST));
-
-    if (!(body->isKind(ParseNodeKind::LexicalScope) &&
-          body->pn_u.scope.body->isKind(ParseNodeKind::StatementList)))
-    {
-        // Promote to lexical scope + statement list.
-        if (!body->isKind(ParseNodeKind::StatementList)) {
-            TRY_DECL(list, factory_.newStatementList(tokenizer_->pos(start)));
-
-            list->initList(body);
-            body = list;
-        }
-
-        // Promote to lexical scope.
-        TRY_VAR(body, factory_.newLexicalScope(nullptr, body));
-    }
-    MOZ_ASSERT(body->isKind(ParseNodeKind::LexicalScope));
-
-    MOZ_TRY_VAR(body, appendDirectivesToBody(body, directives));
-
-    params->appendWithoutOrderAssumption(body);
-
-    TokenPos pos = tokenizer_->pos(start);
-    TRY_DECL(function, kind == BinKind::FunctionDeclaration
-                       ? factory_.newFunctionStatement(pos)
-                       : factory_.newFunctionExpression(pos));
-
-    factory_.setFunctionBox(function, funbox);
-    factory_.setFunctionFormalParametersAndBody(function, params);
-
-    ParseNode* result;
-    if (kind == BinKind::ObjectMethod)
-        TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::None));
-    else if (kind == BinKind::ObjectGetter)
-        TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::Getter));
-    else if (kind == BinKind::ObjectSetter)
-        TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::Setter));
-    else
-        result = function;
-
-    // Now handle bindings.
-    HandlePropertyName dotThis = cx_->names().dotThis;
-    const bool declareThis = hasUsedName(dotThis) || funbox->bindingsAccessedDynamically() || funbox->isDerivedClassConstructor();
+    Maybe<Chars> string;
+    MOZ_TRY(readMaybeString(string));
+    MOZ_ASSERT(string);
 
-    if (declareThis) {
-        ParseContext::Scope& funScope = parseContext_->functionScope();
-        ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
-        MOZ_ASSERT(!p);
-        TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var,
-                                      DeclaredNameInfo::npos));
-        funbox->setHasThisBinding();
-    }
-
-    TRY_DECL(bindings,
-             NewFunctionScopeData(cx_, parseContext_->functionScope(),
-                                  /* hasParameterExprs = */false, alloc_, parseContext_));
-
-    funbox->functionScopeBindings().set(*bindings);
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseObjectPropertyName()
-{
-    auto start = tokenizer_->offset();
-
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    BinKind kind;
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::StringLiteral: {
-        ParseNode* string;
-        MOZ_TRY_VAR(string, parseStringLiteralAux(kind, fields));
-        uint32_t index;
-        if (string->pn_atom->isIndex(&index))
-            TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset())));
-        else
-            result = string;
-
-        break;
-      }
-      case BinKind::NumericLiteral:
-        MOZ_TRY_VAR(result, parseNumericLiteralAux(kind, fields));
-        break;
-      case BinKind::Identifier:
-        MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields, /* expectObjectPropertyName = */ true));
-        break;
-      case BinKind::ComputedPropertyName: {
-        ParseNode* expr;
-        MOZ_TRY_VAR(expr, parseExpressionAux(kind, fields));
-        TRY_VAR(result, factory_.newComputedName(expr, start, tokenizer_->offset()));
-        break;
-      }
-      default:
-        return raiseInvalidKind("ObjectLiteralPropertyName", kind);
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseVariableDeclarationAux(const BinKind kind, const BinFields& fields)
-{
-    const size_t start = tokenizer_->offset();
-
-    ParseNode* result(nullptr);
-    switch (kind) {
-      default:
-        return raiseInvalidKind("VariableDeclaration", kind);
-      case BinKind::VariableDeclaration:
-        ParseNodeKind pnk = ParseNodeKind::Limit;
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Kind: {
-                Maybe<Chars> kindName;
-                MOZ_TRY(readString(kindName));
-
-                if (*kindName == "let")
-                    pnk = ParseNodeKind::Let;
-                else if (*kindName == "var")
-                    pnk = ParseNodeKind::Var;
-                else if (*kindName == "const")
-                    pnk = ParseNodeKind::Const;
-                else
-                    return raiseInvalidEnum("VariableDeclaration", *kindName);
-
-                break;
-              }
-              case BinField::Declarations: {
-                uint32_t length;
-                AutoList guard(*tokenizer_);
-
-                TRY(tokenizer_->enterList(length, guard));
-                TRY_VAR(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/,
-                                                            tokenizer_->pos(start)));
-
-                for (uint32_t i = 0; i < length; ++i) {
-                    ParseNode* current;
-                    MOZ_TRY_VAR(current, parseVariableDeclarator());
-                    MOZ_ASSERT(current);
-
-                    result->appendWithoutOrderAssumption(current);
-                }
-
-                TRY(guard.done());
-                break;
-              }
-              default:
-                return raiseInvalidField("VariableDeclaration", field);
-            }
-        }
-
-        if (!result || pnk == ParseNodeKind::Limit)
-            return raiseMissingField("VariableDeclaration", BinField::Declarations);
-
-        result->setKind(pnk);
-    }
-
-    return result;
-}
-
+    RootedAtom atom(cx_);
+    TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)string->begin(), string->length()));
 
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionStatementAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(kind == BinKind::ExpressionStatement);
-
-    ParseNode* expr(nullptr);
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Expression:
-            MOZ_TRY_VAR(expr, parseExpression());
-
-            break;
-          default:
-            return raiseInvalidField("ExpressionStatement", field);
-        }
-    }
-
-    if (!expr)
-        return raiseMissingField("ExpressionStatement", BinField::Expression);
-
-    TRY_DECL(result, factory_.newExprStatement(expr, tokenizer_->offset()));
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseVariableDeclarator()
-{
-    const size_t start = tokenizer_->offset();
-
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::VariableDeclarator)
-        return raiseInvalidKind("VariableDeclarator", kind);
-
-    ParseNode* id(nullptr);
-    ParseNode* init(nullptr); // Optional.
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Id:
-            MOZ_TRY_VAR(id, parsePattern());
-
-            break;
-          case BinField::Init:
-            MOZ_TRY_VAR(init, parseExpression());
-
-            break;
-          default:
-            return raiseInvalidField("VariableDeclarator", field);
-        }
-    }
-
-    TRY(guard.done());
-    if (!id)
-        return raiseMissingField("VariableDeclarator", BinField::Id);
-
-    ParseNode* result(nullptr);
-
-    // FIXME: Documentation in ParseNode is clearly obsolete.
-    if (id->isKind(ParseNodeKind::Name)) {
-        // `var foo [= bar]``
-        TRY_VAR(result, factory_.newName(id->pn_atom->asPropertyName(), tokenizer_->pos(start), cx_));
-
-        if (init)
-            result->pn_expr = init;
-
-    } else {
-        // `var pattern = bar`
-        if (!init) {
-            // Here, `init` is required.
-            return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init);
-        }
-
-        TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, id, init));
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionList(bool acceptElisions)
-{
-    const size_t start = tokenizer_->offset();
-
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    TRY(tokenizer_->enterList(length, guard));
-    TRY_DECL(result, factory_.newArrayLiteral(start));
-
-    for (uint32_t i = 0; i < length; ++i) {
-        BinFields fields(cx_);
-        AutoTaggedTuple guard(*tokenizer_);
-        BinKind kind;
-
-        TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-        switch (kind) {
-          case BinKind::Elision: {
-            if (!acceptElisions)
-                return raiseInvalidKind("[Expression]", kind);
-
-            MOZ_TRY(parseElisionAux(kind, fields));
-            TRY(!factory_.addElision(result, tokenizer_->pos(start)));
-            break;
-          }
-          default: {
-            ParseNode* expr(nullptr);
-            MOZ_TRY_VAR(expr, parseExpressionAux(kind, fields));
-
-            MOZ_ASSERT(expr);
-            factory_.addArrayElement(result, expr);
-          }
-        }
-
-        TRY(guard.done());
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<Ok>
-BinASTParser::parseElisionAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(kind == BinKind::Elision);
-    MOZ_TRY(checkEmptyTuple(kind, fields));
-
+    out.set(Move(atom));
     return Ok();
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSwitchCaseList()
+JS::Result<Ok>
+BinASTParser::readMaybeString(MutableHandleAtom out)
 {
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    TRY(tokenizer_->enterList(length, guard));
-    TRY_DECL(list, factory_.newStatementList(tokenizer_->pos()));
-
-    // Set to `true` once we have encountered a `default:` case.
-    // Two `default:` cases is an error.
-    bool haveDefault = false;
+    MOZ_ASSERT(!out);
 
-    for (uint32_t i = 0; i < length; ++i) {
-        ParseNode* caseNode(nullptr);
-        MOZ_TRY_VAR(caseNode, parseSwitchCase());
-        MOZ_ASSERT(caseNode);
-
-        if (caseNode->pn_left == nullptr) {
-            // Ah, seems that we have encountered a default case.
-            if (haveDefault) {
-                // Oh, wait, two defaults? That's an error.
-                return raiseError("This switch() has more than one `default:` case");
-            }
-            haveDefault = true;
-        }
-        factory_.addCaseStatementToList(list, caseNode);
+    Maybe<Chars> string;
+    MOZ_TRY(readMaybeString(string));
+    if (!string) {
+        return Ok();
     }
 
-    TRY(guard.done());
-    TRY_DECL(result, factory_.newLexicalScope(nullptr, list));
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseExpression()
-{
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    BinKind kind;
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-    MOZ_TRY_VAR(result, parseExpressionAux(kind, fields));
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionAux(const BinKind kind, const BinFields& fields)
-{
-    const size_t start = tokenizer_->offset();
-
-    ParseNode* result(nullptr);
-
-    switch (kind) {
-      case BinKind::Identifier: {
-        MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields));
-        break;
-      }
-      case BinKind::BooleanLiteral: {
-        Maybe<bool> value;
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Value:
-                MOZ_TRY_EMPLACE(value, readBool());
-                break;
-              default:
-                return raiseInvalidField("BooleanLiteral", field);
-            }
-        }
-
-        // In case of absent optional fields, inject default values.
-        if (!value)
-            value.emplace(false);
-
-        TRY_VAR(result, factory_.newBooleanLiteral(*value, tokenizer_->pos(start)));
-
-        break;
-      }
-      case BinKind::NullLiteral: {
-        MOZ_TRY(checkEmptyTuple(kind, fields));
-        TRY_VAR(result, factory_.newNullLiteral(tokenizer_->pos(start)));
-        break;
-      }
-      case BinKind::NumericLiteral:
-        MOZ_TRY_VAR(result, parseNumericLiteralAux(kind, fields));
-        break;
-
-      case BinKind::RegExpLiteral: {
-        RootedAtom pattern(cx_);
-        Maybe<Chars> flags;
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Pattern:
-                MOZ_TRY(readString(&pattern));
-                break;
-              case BinField::Flags:
-                MOZ_TRY(readString(flags));
-                break;
-              default:
-                return raiseInvalidField("RegExpLiteral", field);
-            }
-        }
-
-        if (!pattern)
-            return raiseMissingField("RegExpLiteral", BinField::Pattern);
-        if (!flags)
-            return raiseMissingField("RegExpLiteral", BinField::Flags);
-
-        RegExpFlag reflags = NoFlags;
-        for (auto c : *flags) {
-            if (c == 'g' && !(reflags & GlobalFlag))
-                reflags = RegExpFlag(reflags | GlobalFlag);
-            else if (c == 'i' && !(reflags & IgnoreCaseFlag))
-                reflags = RegExpFlag(reflags | IgnoreCaseFlag);
-            else if (c == 'm' && !(reflags & MultilineFlag))
-                reflags = RegExpFlag(reflags | MultilineFlag);
-            else if (c == 'y' && !(reflags & StickyFlag))
-                reflags = RegExpFlag(reflags | StickyFlag);
-            else if (c == 'u' && !(reflags & UnicodeFlag))
-                reflags = RegExpFlag(reflags | UnicodeFlag);
-            else
-                return raiseInvalidEnum("RegExpLiteral", *flags);
-        }
-
-
-        Rooted<RegExpObject*> reobj(cx_);
-        TRY_VAR(reobj, RegExpObject::create(cx_,
-            pattern,
-            reflags,
-            alloc_,
-            TenuredObject));
-
-        TRY_VAR(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this));
-
-        break;
-      }
-      case BinKind::StringLiteral:
-        MOZ_TRY_VAR(result, parseStringLiteralAux(kind, fields));
-        break;
-
-      case BinKind::ThisExpression: {
-        MOZ_TRY(checkEmptyTuple(kind, fields));
-
-        if (parseContext_->isFunctionBox())
-            parseContext_->functionBox()->usesThis = true;
-
-        TokenPos pos = tokenizer_->pos(start);
-        ParseNode* thisName(nullptr);
-        if (parseContext_->sc()->thisBinding() == ThisBinding::Function)
-            TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_));
-
-        TRY_VAR(result, factory_.newThisLiteral(pos, thisName));
-        break;
-      }
-      case BinKind::ArrayExpression:
-        MOZ_TRY_VAR(result, parseArrayExpressionAux(kind, fields));
-        break;
-
-      case BinKind::ObjectExpression:
-        MOZ_TRY_VAR(result, parseObjectExpressionAux(kind, fields));
-        break;
-
-      case BinKind::FunctionExpression:
-        MOZ_TRY_VAR(result, parseFunctionAux(kind, fields));
-        result->setOp(JSOP_LAMBDA);
-        break;
-
-      case BinKind::UnaryExpression:
-      case BinKind::UpdateExpression: {
-        ParseNode* expr(nullptr);
-        Maybe<Chars> operation;
-        Maybe<bool> prefix; // FIXME: Ignored for unary_expression?
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Operator:
-                MOZ_TRY(readString(operation));
-                break;
-              case BinField::Prefix:
-                MOZ_TRY_EMPLACE(prefix, readBool());
-                break;
-              case BinField::Argument:
-                  // arguments are always parsed *after* operator.
-                  if (operation.isNothing())
-                      return raiseMissingField("UpdateExpression", BinField::Operator);
-                MOZ_TRY_VAR(expr, parseExpression());
-                break;
-              default:
-                return raiseInvalidField("UpdateExpression", field);
-            }
-        }
-
-        if (!expr)
-            return raiseMissingField("UpdateExpression", BinField::Argument);
-        if (operation.isNothing())
-            return raiseMissingField("UpdateExpression", BinField::Operator);
-
-        // In case of absent optional fields, inject default values.
-        if (prefix.isNothing())
-            prefix.emplace(false);
-
-        ParseNodeKind pnk = ParseNodeKind::Limit;
-        if (kind == BinKind::UnaryExpression) {
-            if (*operation == "-") {
-                pnk = ParseNodeKind::Neg;
-            } else if (*operation == "+") {
-                pnk = ParseNodeKind::Pos;
-            } else if (*operation == "!") {
-                pnk = ParseNodeKind::Not;
-            } else if (*operation == "~") {
-                pnk = ParseNodeKind::BitNot;
-            } else if (*operation == "typeof") {
-                if (expr->isKind(ParseNodeKind::Name))
-                    pnk = ParseNodeKind::TypeOfName;
-                else
-                    pnk = ParseNodeKind::TypeOfExpr;
-            } else if (*operation == "void") {
-                pnk = ParseNodeKind::Void;
-            } else if (*operation == "delete") {
-                switch (expr->getKind()) {
-                  case ParseNodeKind::Name:
-                    expr->setOp(JSOP_DELNAME);
-                    pnk = ParseNodeKind::DeleteName;
-                    break;
-                  case ParseNodeKind::Dot:
-                    pnk = ParseNodeKind::DeleteProp;
-                    break;
-                  case ParseNodeKind::Elem:
-                    pnk = ParseNodeKind::DeleteElem;
-                    break;
-                  default:
-                    pnk = ParseNodeKind::DeleteExpr;
-                }
-            } else {
-                return raiseInvalidEnum("UnaryOperator", *operation);
-            }
-        } else if (kind == BinKind::UpdateExpression) {
-            if (!expr->isKind(ParseNodeKind::Name) && !factory_.isPropertyAccess(expr))
-                return raiseError("Invalid increment/decrement operand"); // FIXME: Shouldn't this be part of the syntax?
-
-            if (*operation == "++") {
-                if (*prefix)
-                    pnk = ParseNodeKind::PreIncrement;
-                else
-                    pnk = ParseNodeKind::PostIncrement;
-            } else if (*operation == "--") {
-                if (*prefix)
-                    pnk = ParseNodeKind::PreDecrement;
-                else
-                    pnk = ParseNodeKind::PostDecrement;
-            } else {
-                return raiseInvalidEnum("UpdateOperator", *operation);
-            }
-        }
-
-        TRY_VAR(result, factory_.newUnary(pnk, start, expr));
-
-        break;
-      }
-      case BinKind::BinaryExpression:
-      case BinKind::LogicalExpression: {
-        ParseNode* left(nullptr);
-        ParseNode* right(nullptr);
-        Maybe<Chars> operation;
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Left:
-                MOZ_TRY_VAR(left, parseExpression());
-                break;
-              case BinField::Right:
-                MOZ_TRY_VAR(right, parseExpression());
-                break;
-              case BinField::Operator:
-                MOZ_TRY(readString(operation));
-                break;
-              default:
-                return raiseInvalidField("LogicalExpression | BinaryExpression", field);
-            }
-        }
-
-        if (!left)
-            return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Left);
-        if (!right)
-            return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Right);
-        if (operation.isNothing())
-            return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Operator);
-
-        // FIXME: Instead of Chars, we should use atoms and comparison
-        // between atom ptr.
-        ParseNodeKind pnk = ParseNodeKind::Limit;
-        if (*operation == "==")
-            pnk = ParseNodeKind::Eq;
-        else if (*operation == "!=")
-            pnk = ParseNodeKind::Ne;
-        else if (*operation == "===")
-            pnk = ParseNodeKind::StrictEq;
-        else if (*operation == "!==")
-            pnk = ParseNodeKind::StrictNe;
-        else if (*operation == "<")
-            pnk = ParseNodeKind::Lt;
-        else if (*operation == "<=")
-            pnk = ParseNodeKind::Le;
-        else if (*operation == ">")
-            pnk = ParseNodeKind::Gt;
-        else if (*operation == ">=")
-            pnk = ParseNodeKind::Ge;
-        else if (*operation == "<<")
-            pnk = ParseNodeKind::Lsh;
-        else if (*operation == ">>")
-            pnk = ParseNodeKind::Rsh;
-        else if (*operation == ">>>")
-            pnk = ParseNodeKind::Ursh;
-        else if (*operation == "+")
-            pnk = ParseNodeKind::Add;
-        else if (*operation == "-")
-            pnk = ParseNodeKind::Sub;
-        else if (*operation == "*")
-            pnk = ParseNodeKind::Star;
-        else if (*operation == "/")
-            pnk = ParseNodeKind::Div;
-        else if (*operation == "%")
-            pnk = ParseNodeKind::Mod;
-        else if (*operation == "|")
-            pnk = ParseNodeKind::BitOr;
-        else if (*operation == "^")
-            pnk = ParseNodeKind::BitXor;
-        else if (*operation == "&")
-            pnk = ParseNodeKind::BitAnd;
-        else if (*operation == "in")
-            pnk = ParseNodeKind::In;
-        else if (*operation == "instanceof")
-            pnk = ParseNodeKind::InstanceOf;
-        else if (*operation == "||")
-            pnk = ParseNodeKind::Or;
-        else if (*operation == "&&")
-            pnk = ParseNodeKind::And;
-        else if (*operation == "**")
-            pnk = ParseNodeKind::Pow;
-        else
-            return raiseInvalidEnum("BinaryOperator | LogicalOperator", *operation);
-
-        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 {
-            TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start)));
-
-            list->appendWithoutOrderAssumption(left);
-            list->appendWithoutOrderAssumption(right);
-            result = list;
-        }
-
-         break;
-      }
-      case BinKind::AssignmentExpression: {
-        ParseNode* left(nullptr);
-        ParseNode* right(nullptr);
-        Maybe<Chars> operation;
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Left:
-                MOZ_TRY_VAR(left, parseExpression());
-                break;
-              case BinField::Right:
-                MOZ_TRY_VAR(right, parseExpression());
-                break;
-              case BinField::Operator:
-                MOZ_TRY(readString(operation));
-                break;
-              default:
-                return raiseInvalidField("AssignmentExpression", field);
-            }
-        }
-
-        if (!left)
-            return raiseMissingField("AssignmentExpression", BinField::Left);
-        if (!right)
-            return raiseMissingField("AssignmentExpression", BinField::Right);
-        if (operation.isNothing())
-            return raiseMissingField("AssignmentExpression", BinField::Operator);
-
-        // FIXME: Instead of Chars, we should use atoms and comparison
-        // between atom ptr.
-        // FIXME: We should probably turn associative operations into lists.
-        ParseNodeKind pnk = ParseNodeKind::Limit;
-        if (*operation == "=")
-            pnk = ParseNodeKind::Assign;
-        else if (*operation == "+=")
-            pnk = ParseNodeKind::AddAssign;
-        else if (*operation == "-=")
-            pnk = ParseNodeKind::SubAssign;
-        else if (*operation == "*=")
-            pnk = ParseNodeKind::MulAssign;
-        else if (*operation == "/=")
-            pnk = ParseNodeKind::DivAssign;
-        else if (*operation == "%=")
-            pnk = ParseNodeKind::ModAssign;
-        else if (*operation == "<<=")
-            pnk = ParseNodeKind::LshAssign;
-        else if (*operation == ">>=")
-            pnk = ParseNodeKind::RshAssign;
-        else if (*operation == ">>>=")
-            pnk = ParseNodeKind::UrshAssign;
-        else if (*operation == "|=")
-            pnk = ParseNodeKind::BitOrAssign;
-        else if (*operation == "^=")
-            pnk = ParseNodeKind::BitXorAssign;
-        else if (*operation == "&=")
-            pnk = ParseNodeKind::BitAndAssign;
-        else
-            return raiseInvalidEnum("AssignmentOperator", *operation);
-
-        TRY_VAR(result, factory_.newAssignment(pnk, left, right));
-
-        break;
-      }
-      case BinKind::BracketExpression:
-      case BinKind::DotExpression:
-        MOZ_TRY_VAR(result, parseMemberExpressionAux(kind, fields));
-
-        break;
-      case BinKind::ConditionalExpression: {
-        ParseNode* test(nullptr);
-        ParseNode* alternate(nullptr);
-        ParseNode* consequent(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Test:
-                MOZ_TRY_VAR(test, parseExpression());
-                break;
-              case BinField::Consequent:
-                MOZ_TRY_VAR(consequent, parseExpression());
-                break;
-              case BinField::Alternate:
-                MOZ_TRY_VAR(alternate, parseExpression());
-                break;
-              default:
-                return raiseInvalidField("ConditionalExpression", field);
-            }
-        }
-
-        if (!test)
-            return raiseMissingField("ConditionalExpression", BinField::Test);
-        if (!consequent)
-            return raiseMissingField("ConditionalExpression", BinField::Consequent);
-        if (!alternate)
-            return raiseMissingField("ConditionalExpression", BinField::Alternate);
-
-        TRY_VAR(result, factory_.newConditional(test, consequent, alternate));
-
-        break;
-      }
-      case BinKind::CallExpression:
-      case BinKind::NewExpression: {
-        ParseNode* callee(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Callee:
-                MOZ_TRY_VAR(callee, parseExpression());
-                break;
-              case BinField::Arguments:
-                MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ false));
-                break;
-              default:
-                return raiseInvalidField("NewExpression", field);
-            }
-        }
-
-        // In case of absent required fields, fail.
-        if (!callee)
-            return raiseMissingField("NewExpression", BinField::Callee);
-
-        // In case of absent optional fields, inject default values.
-        if (!result)
-            TRY_VAR(result, factory_.newArrayLiteral(start));
-
-        ParseNodeKind pnk =
-            kind == BinKind::CallExpression
-            ? ParseNodeKind::Call
-            : ParseNodeKind::New;
-        result->setKind(pnk);
-        result->prepend(callee);
+    RootedAtom atom(cx_);
+    TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)string->begin(), string->length()));
 
-        break;
-      }
-      case BinKind::SequenceExpression: {
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Expressions:
-                MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ false));
-                break;
-              default:
-                return raiseInvalidField("SequenceExpression", field);
-            }
-        }
-
-        if (!result)
-            return raiseMissingField("SequenceExpression", BinField::Expression);
-
-        result->setKind(ParseNodeKind::Comma);
-        break;
-      }
-      default:
-        return raiseInvalidKind("Expression", kind);
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseNumericLiteralAux(const BinKind kind, const BinFields& fields)
-{
-    auto start = tokenizer_->offset();
-
-    Maybe<double> value;
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Value:
-            MOZ_TRY_EMPLACE(value, readNumber());
-            break;
-          default:
-            return raiseInvalidField("NumericLiteral", field);
-        }
-    }
-
-    // In case of absent optional fields, inject default values.
-    if (!value)
-        value.emplace(0);
-
-    TRY_DECL(result, factory_.newNumber(*value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseStringLiteralAux(const BinKind kind, const BinFields& fields)
-{
-    auto start = tokenizer_->offset();
-
-    RootedAtom value(cx_);
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Value:
-            MOZ_TRY(readString(&value));
-            break;
-          default:
-            return raiseInvalidField("StringLiteral", field);
-        }
-    }
-
-    if (!value)
-        return raiseMissingField("StringLiteral", BinField::Value);
-
-    TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseArrayExpressionAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(kind == BinKind::ArrayExpression);
-
-    ParseNode* result(nullptr);
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Elements: {
-            MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ true));
-            break;
-          }
-          default:
-            return raiseInvalidField("ArrayExpression", field);
-        }
-    }
-
-    // Inject default values for absent fields.
-    if (!result)
-        TRY_VAR(result, factory_.newArrayLiteral(tokenizer_->offset()));
-
-    MOZ_ASSERT(result->isKind(ParseNodeKind::Array));
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseObjectExpressionAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(kind == BinKind::ObjectExpression);
-
-    ParseNode* result(nullptr);
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Properties: {
-            MOZ_TRY_VAR(result, parseObjectMemberList());
-            break;
-          }
-          default:
-            return raiseInvalidField("Property | Method", field);
-        }
-    }
-
-    if (!result)
-        TRY_VAR(result, factory_.newObjectLiteral(tokenizer_->offset()));
-
-    MOZ_ASSERT(result->isArity(PN_LIST));
-    MOZ_ASSERT(result->isKind(ParseNodeKind::Object));
-
-#if defined(DEBUG)
-    // Sanity check.
-    for (ParseNode* iter = result->pn_head; iter != nullptr; iter = iter->pn_next) {
-        MOZ_ASSERT(iter->isKind(ParseNodeKind::Colon));
-        MOZ_ASSERT(iter->pn_left != nullptr);
-        MOZ_ASSERT(iter->pn_right != nullptr);
-    }
-#endif // defined(DEBUG)
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseMemberExpressionAux(const BinKind kind, const BinFields& fields)
-{
-    MOZ_ASSERT(kind == BinKind::DotExpression || kind == BinKind::BracketExpression);
-
-    ParseNode* object(nullptr);
-    ParseNode* property(nullptr);
-
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Object:
-            MOZ_TRY_VAR(object, parseExpression());
-            break;
-          case BinField::Property:
-            if (kind == BinKind::BracketExpression)
-                MOZ_TRY_VAR(property, parseExpression());
-            else
-                MOZ_TRY_VAR(property, parseIdentifier());
-            break;
-          default:
-            return raiseInvalidField("MemberExpression", field);
-        }
-    }
-
-    // In case of absent required fields, fail.
-    if (!object)
-        return raiseMissingField("MemberExpression", BinField::Object);
-    if (!property)
-        return raiseMissingField("MemberExpression", BinField::Property);
-
-    ParseNode* result(nullptr);
-    if (kind == BinKind::DotExpression) {
-        MOZ_ASSERT(property->isKind(ParseNodeKind::Name));
-        PropertyName* name = property->pn_atom->asPropertyName();
-        TRY_VAR(result, factory_.newPropertyAccess(object, name, tokenizer_->offset()));
-    } else {
-        TRY_VAR(result, factory_.newPropertyByValue(object, property, tokenizer_->offset()));
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseDirectiveList()
-{
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-    TRY(tokenizer_->enterList(length, guard));
-
-    TokenPos pos = tokenizer_->pos();
-    TRY_DECL(result, factory_.newStatementList(pos));
-
-    RootedAtom value(cx_);
-    for (uint32_t i = 0; i < length; ++i) {
-        value = nullptr;
-        MOZ_TRY(readString(&value));
-
-        TRY_DECL(directive, factory_.newStringLiteral(value, pos));
-        factory_.addStatementToList(result, directive);
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseSwitchCase()
-{
-    const size_t start = tokenizer_->offset();
-
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    if (kind != BinKind::SwitchCase)
-        return raiseInvalidKind("SwitchCase", kind);
-
-    ParseNode* test(nullptr); // Optional.
-    ParseNode* statements(nullptr); // Required.
-
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Test:
-            MOZ_TRY_VAR(test, parseExpression());
-            break;
-          case BinField::Consequent:
-            MOZ_TRY_VAR(statements, parseStatementList());
-            break;
-          default:
-            return raiseInvalidField("SwitchCase", field);
-        }
-    }
-
-    TRY(guard.done());
-    if (!statements)
-        return raiseMissingField("SwitchCase", BinField::Consequent);
-
-    MOZ_ASSERT(statements->isKind(ParseNodeKind::StatementList));
-
-    TRY_DECL(result, factory_.newCaseOrDefault(start, test, statements));
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseCatchClause()
-{
-    ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
-    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
-    TRY(scope.init(parseContext_));
-
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-
-    switch (kind) {
-      default:
-        return raiseInvalidKind("CatchClause", kind);
-      case BinKind::CatchClause: {
-        ParseNode* param(nullptr);
-        ParseNode* body(nullptr);
-
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Param:
-                MOZ_TRY_VAR(param, parsePattern());
-                break;
-              case BinField::Body:
-                MOZ_TRY_VAR(body, parseBlockStatement());
-                break;
-              case BinField::BINJS_Scope:
-                MOZ_TRY(parseAndUpdateCurrentScope());
-                break;
-              default:
-                return raiseInvalidField("CatchClause", field);
-            }
-        }
-
-        if (!param)
-            return raiseMissingField("CatchClause", BinField::Param);
-        if (!body)
-            return raiseMissingField("CatchClause", BinField::Body);
-
-        TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_));
-        TRY_VAR(result, factory_.newLexicalScope(*bindings, body));
-        TRY(factory_.setupCatchScope(result, param, body));
-      }
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseArgumentList()
-{
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    TRY(tokenizer_->enterList(length, guard));
-    ParseNode* result = new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos());
-
-    for (uint32_t i = 0; i < length; ++i) {
-        ParseNode* pattern;
-        MOZ_TRY_VAR(pattern, parsePattern());
-
-        result->appendWithoutOrderAssumption(pattern);
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseIdentifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields));
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseIdentifierAux(const BinKind, const BinFields& fields, const bool expectObjectPropertyName /* = false */)
-{
-    const size_t start = tokenizer_->offset();
-
-    RootedAtom id(cx_);
-    for (auto field : fields) {
-        switch (field) {
-          case BinField::Name:
-            MOZ_TRY(readString(&id));
-            break;
-          default:
-            return raiseInvalidField("Identifier", field);
-        }
-    }
-
-    if (!id)
-        return raiseMissingField("Identifier", BinField::Name);
-
-    if (!IsIdentifier(id))
-        return raiseError("Invalid identifier");
-    if (!expectObjectPropertyName && IsKeyword(id))
-        return raiseError("Invalid identifier (keyword)");
-
-    // Once `IsIdentifier` has returned true, we may call `asPropertyName()` without fear.
-    TokenPos pos = tokenizer_->pos(start);
-
-    ParseNode* result;
-    if (expectObjectPropertyName)
-        TRY_VAR(result, factory_.newObjectLiteralPropertyName(id->asPropertyName(), pos));
-    else
-        TRY_VAR(result, factory_.newName(id->asPropertyName(), pos, cx_));
-
-    return result;
-}
-
-
-JS::Result<ParseNode*>
-BinASTParser::parsePattern()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result;
-    MOZ_TRY_VAR(result, parsePatternAux(kind, fields));
-
-    TRY(guard.done());
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parsePatternAux(const BinKind kind, const BinFields& fields)
-{
-    ParseNode* result;
-    switch (kind) {
-      case BinKind::Identifier:
-        MOZ_TRY_VAR(result, parseIdentifierAux(kind ,fields));
-        break;
-      default:
-        return raiseInvalidKind("Pattern", kind);
-    }
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseObjectMember()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-    ParseNode* result(nullptr);
-
-    switch (kind) {
-      case BinKind::ObjectProperty: {
-        ParseNode* key(nullptr);
-        ParseNode* value(nullptr);
-        for (auto field : fields) {
-            switch (field) {
-              case BinField::Key:
-                MOZ_TRY_VAR(key, parseObjectPropertyName());
-                break;
-              case BinField::Value:
-                MOZ_TRY_VAR(value, parseExpression());
-                break;
-              default:
-                return raiseInvalidField("ObjectMember", field);
-            }
-        }
-
-        if (!key)
-            return raiseMissingField("ObjectMember", BinField::Key);
-        if (!value)
-            return raiseMissingField("ObjectMember", BinField::Value);
-
-        if (!factory_.isUsableAsObjectPropertyName(key))
-            return raiseError("ObjectMember key kind");
-
-        TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, value, AccessorType::None));
-
-        break;
-      }
-      case BinKind::ObjectMethod:
-      case BinKind::ObjectGetter:
-      case BinKind::ObjectSetter:
-        MOZ_TRY_VAR(result, parseFunctionAux(kind, fields));
-
-        if (!result)
-            return raiseEmpty("ObjectMethod");
-
-        MOZ_ASSERT(result->isKind(ParseNodeKind::Colon));
-        break;
-      default:
-        return raiseInvalidKind("ObjectMember", kind);
-    }
-
-    TRY(guard.done());
-    MOZ_ASSERT(result);
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseObjectMemberList()
-{
-    uint32_t length;
-    AutoList guard(*tokenizer_);
-
-    auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
-
-    TRY_DECL(result, factory_.newObjectLiteral(start));
-
-    for (uint32_t i = 0; i < length; ++i) {
-        ParseNode* keyValue;
-        MOZ_TRY_VAR(keyValue, parseObjectMember());
-        MOZ_ASSERT(keyValue);
-
-        result->appendWithoutOrderAssumption(keyValue);
-    }
-
-    TRY(guard.done());
-    return result;
-}
-
-
-JS::Result<Ok>
-BinASTParser::checkEmptyTuple(const BinKind kind, const BinFields& fields)
-{
-    if (fields.length() != 0)
-        return raiseInvalidField(describeBinKind(kind), fields[0]);
-
+    out.set(Move(atom));
     return Ok();
 }
 
 
 JS::Result<Ok>
-BinASTParser::readString(MutableHandleAtom out)
+BinASTParser::readString(Chars& result)
 {
-    MOZ_ASSERT(!out);
-
-    Maybe<Chars> string;
-    MOZ_TRY(readString(string));
-    MOZ_ASSERT(string);
-
-    RootedAtom atom(cx_);
-    TRY_VAR(atom, Atomize(cx_, (const char*)string->begin(), string->length()));
-
-    out.set(Move(atom));
+    TRY(tokenizer_->readChars(result));
     return Ok();
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parsePropertyName()
-{
-    RootedAtom atom(cx_);
-    MOZ_TRY(readString(&atom));
-
-    TokenPos pos = tokenizer_->pos();
-
-    ParseNode* result;
-
-    // If the atom matches an index (e.g. "3"), we need to normalize the
-    // propertyName to ensure that it has the same representation as
-    // the numeric index (e.g. 3).
-    uint32_t index;
-    if (atom->isIndex(&index))
-        TRY_VAR(result, factory_.newNumber(index, NoDecimal, pos));
-    else
-        TRY_VAR(result, factory_.newStringLiteral(atom, pos));
-
-    return result;
-}
-
 JS::Result<Ok>
-BinASTParser::readString(Maybe<Chars>& out)
+BinASTParser::readMaybeString(Maybe<Chars>& out)
 {
     MOZ_ASSERT(out.isNothing());
-    Chars result(cx_);
-    TRY(tokenizer_->readChars(result));
-
-    out.emplace(Move(result));
+    TRY(tokenizer_->readMaybeChars(out));
     return Ok();
 }
 
 JS::Result<double>
 BinASTParser::readNumber()
 {
     double result;
     TRY(tokenizer_->readDouble(result));
@@ -2394,16 +395,30 @@ BinASTParser::readBool()
 {<