Bug 1437004 - Porting BinAST to AST v3;r?arai,jorendorff draft
authorDavid Teller <dteller@mozilla.com>
Wed, 21 Feb 2018 17:07:03 +0100
changeset 778389 f78b35a6cb8bcc717fe09b8a200ac3eb8fee314f
parent 777852 3be52f7bb42088899f3b7166101feffc8d98a3e6
child 778390 501aa0f9a7bcde0beb0f68d4a686dbc883dd3bc4
push id105484
push userdteller@mozilla.com
push dateFri, 06 Apr 2018 09:27:53 +0000
reviewersarai, jorendorff
bugs1437004
milestone61.0a1
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()
 {
     bool result;
     TRY(tokenizer_->readBool(result));
 
     return result;
 }
 
 mozilla::GenericErrorResult<JS::Error&>
+BinASTParser::raiseMissingVariableInAssertedScope(JSAtom* name)
+{
+    // For the moment, we don't trust inputs sufficiently to put the name
+    // in an error message.
+    return raiseError("Missing variable in AssertedScope");
+}
+
+mozilla::GenericErrorResult<JS::Error&>
+BinASTParser::raiseMissingDirectEvalInAssertedScope()
+{
+    return raiseError("Direct call to `eval` was not declared in AssertedScope");
+}
+
+mozilla::GenericErrorResult<JS::Error&>
 BinASTParser::raiseInvalidKind(const char* superKind, const BinKind kind)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, invalid kind %s", superKind, describeBinKind(kind)));
     return raiseError(out.string());
 }
 
@@ -2412,16 +427,26 @@ BinASTParser::raiseInvalidField(const ch
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, invalid field '%s'", kind, describeBinField(field)));
     return raiseError(out.string());
 }
 
 mozilla::GenericErrorResult<JS::Error&>
+BinASTParser::raiseInvalidNumberOfFields(const BinKind kind, const uint32_t expected, const uint32_t got)
+{
+    Sprinter out(cx_);
+    TRY(out.init());
+    TRY(out.printf("In %s, invalid number of fields: expected %u, got %u",
+        describeBinKind(kind), expected, got));
+    return raiseError(out.string());
+}
+
+mozilla::GenericErrorResult<JS::Error&>
 BinASTParser::raiseInvalidEnum(const char* kind, const Chars& value)
 {
     // We don't trust the actual chars of `value` to be properly formatted anything, so let's not use
     // them anywhere.
     return raiseError("Invalid enum");
 }
 
 mozilla::GenericErrorResult<JS::Error&>
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -34,19 +34,20 @@ class BinASTParser;
 /**
  * The parser for a Binary AST.
  *
  * By design, this parser never needs to backtrack or look ahead. Errors are not
  * recoverable.
  */
 class BinASTParser : private JS::AutoGCRooter, public ErrorReporter
 {
+    using Tokenizer = BinTokenReaderTester;
+    using BinFields = Tokenizer::BinFields;
+    using Chars = Tokenizer::Chars;
     using Names = JS::GCVector<JSString*, 8>;
-    using Tokenizer = BinTokenReaderTester;
-    using Chars = Tokenizer::Chars;
 
   public:
     BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
         : AutoGCRooter(cx, BINPARSER)
         , traceListHead_(nullptr)
         , options_(options)
         , cx_(cx)
         , alloc_(alloc)
@@ -87,97 +88,73 @@ class BinASTParser : private JS::AutoGCR
 
   private:
     MOZ_MUST_USE JS::Result<ParseNode*> parseAux(const uint8_t* start, const size_t length);
 
     // --- Raise errors.
     //
     // These methods return a (failed) JS::Result for convenience.
 
-    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidKind(const char* superKind, const BinKind kind);
-    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidField(const char* kind, const BinField field);
-    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidEnum(const char* kind, const Chars& value);
-    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingField(const char* kind, const BinField field);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingVariableInAssertedScope(JSAtom* name);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingDirectEvalInAssertedScope();
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidKind(const char* superKind,
+        const BinKind kind);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidField(const char* kind,
+        const BinField field);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidNumberOfFields(
+        const BinKind kind, const uint32_t expected, const uint32_t got);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidEnum(const char* kind,
+        const Chars& value);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingField(const char* kind,
+        const BinField field);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseEmpty(const char* description);
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseOOM();
     MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseError(const char* description);
-    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseError(BinKind kind, const char* description);
+    MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseError(BinKind kind,
+        const char* description);
+
 
     // Ensure that this parser will never be used again.
     void poison();
 
-    // --- Parse full nodes (methods are sorted by alphabetical order)
-    //
-    // These method may NEVER return `nullptr`. // FIXME: We can probably optimize Result<> based on this.
+    // Auto-generated methods
+#include "frontend/BinSource-auto.h"
 
-    MOZ_MUST_USE JS::Result<ParseNode*> parseBlockStatement();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseCatchClause();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseExpression();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseForInit();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseForInInit();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseIdentifier();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseObjectPropertyName();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseObjectMember();
-    MOZ_MUST_USE JS::Result<ParseNode*> parsePattern(); // Parse a *binding* pattern.
-    MOZ_MUST_USE JS::Result<ParseNode*> parsePropertyName();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseProgram();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseStatement();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseSwitchCase();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseVariableDeclarator();
-
-
-    // --- Parse lists of nodes (methods are sorted by alphabetical order)
-
-    MOZ_MUST_USE JS::Result<ParseNode*> parseArgumentList();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseDirectiveList();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseExpressionList(bool acceptElisions);
-
-    // Returns a list of PNK_COLON.
-    MOZ_MUST_USE JS::Result<ParseNode*> parseObjectMemberList();
+    // --- Auxiliary parsing functions
+    template<size_t N>
+    JS::Result<Ok, JS::Error&>
+    checkFields(const BinKind kind, const BinFields& actual, const BinField (&expected)[N]);
+    JS::Result<Ok, JS::Error&>
+    checkFields0(const BinKind kind, const BinFields& actual);
 
-    MOZ_MUST_USE JS::Result<ParseNode*> parseStatementList();
-    MOZ_MUST_USE JS::Result<ParseNode*> parseSwitchCaseList();
-
-    // --- Parse the contents of a node whose kind has already been determined.
+    JS::Result<ParseNode*>
+    buildFunction(const size_t start, const BinKind kind, ParseNode* name, ParseNode* params,
+        ParseNode* body, FunctionBox* funbox);
+    JS::Result<FunctionBox*>
+    buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind);
 
-    MOZ_MUST_USE JS::Result<ParseNode*> parseArrayExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseBreakOrContinueStatementAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseBlockStatementAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseExpressionStatementAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseFunctionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseIdentifierAux(const BinKind, const Tokenizer::BinFields& fields, const bool expectObjectPropertyName = false);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseMemberExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseNumericLiteralAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseObjectExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parsePatternAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseStringLiteralAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseStatementAux(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<ParseNode*> parseVariableDeclarationAux(const BinKind kind, const Tokenizer::BinFields& fields);
-
-    // --- Auxiliary parsing functions that may have a side-effect on the parser but do not return a node.
-
-    MOZ_MUST_USE JS::Result<Ok> checkEmptyTuple(const BinKind kind, const Tokenizer::BinFields& fields);
-    MOZ_MUST_USE JS::Result<Ok> parseElisionAux(const BinKind kind, const Tokenizer::BinFields& fields);
-
-    // Parse full scope information to the current innermost scope.
-    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateCurrentScope();
     // Parse full scope information to a specific var scope / let scope combination.
-    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScope(ParseContext::Scope& varScope, ParseContext::Scope& letScope);
+    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScope(ParseContext::Scope& varScope,
+        ParseContext::Scope& letScope);
     // Parse a list of names and add it to a given scope.
-    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind);
-    MOZ_MUST_USE JS::Result<Ok> parseStringList(MutableHandle<Maybe<Names>> out);
+    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateScopeNames(ParseContext::Scope& scope,
+        DeclarationKind kind);
+    MOZ_MUST_USE JS::Result<Ok> parseAndUpdateCapturedNames();
+    MOZ_MUST_USE JS::Result<Ok> checkBinding(JSAtom* name);
 
     // --- Utilities.
 
-    MOZ_MUST_USE JS::Result<ParseNode*> appendDirectivesToBody(ParseNode* body, ParseNode* directives);
+    MOZ_MUST_USE JS::Result<ParseNode*> appendDirectivesToBody(ParseNode* body,
+        ParseNode* directives);
 
-    // Read a string as a `Chars`.
-    MOZ_MUST_USE JS::Result<Ok> readString(Maybe<Chars>& out);
+    // Read a string
+    MOZ_MUST_USE JS::Result<Ok> readString(Chars& out);
+    MOZ_MUST_USE JS::Result<Ok> readMaybeString(Maybe<Chars>& out);
     MOZ_MUST_USE JS::Result<Ok> readString(MutableHandleAtom out);
+    MOZ_MUST_USE JS::Result<Ok> readMaybeString(MutableHandleAtom out);
     MOZ_MUST_USE JS::Result<bool> readBool();
     MOZ_MUST_USE JS::Result<double> readNumber();
 
     const ReadOnlyCompileOptions& options() const override {
         return this->options_;
     }
 
     // Names
@@ -256,27 +233,30 @@ class BinASTParser : private JS::AutoGCR
     // Root atoms and objects allocated for the parse tree.
     AutoKeepAtoms keepAtoms_;
 
     // The current ParseContext, holding directives, etc.
     ParseContext* parseContext_;
     UsedNameTracker& usedNames_;
     Maybe<Tokenizer> tokenizer_;
     FullParseHandler factory_;
+    VariableDeclarationKind variableDeclarationKind_;
 
     friend class BinParseContext;
+    friend class AutoVariableDeclarationKind;
 
     // Needs access to AutoGCRooter.
     friend void TraceBinParser(JSTracer* trc, AutoGCRooter* parser);
 };
 
 class BinParseContext : public ParseContext
 {
   public:
-    BinParseContext(JSContext* cx, BinASTParser* parser, SharedContext* sc, Directives* newDirectives)
+    BinParseContext(JSContext* cx, BinASTParser* parser, SharedContext* sc,
+        Directives* newDirectives)
         : ParseContext(cx, parser->parseContext_, sc, *parser,
                        parser->usedNames_, newDirectives, /* isFull = */ true)
     { }
 };
 
 
 } // namespace frontend
 } // namespace js
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSource.webidl_
@@ -0,0 +1,871 @@
+// Type aliases and enums.
+
+typedef FrozenArray<(SpreadElement or Expression)> Arguments;
+typedef DOMString string;
+typedef string Identifier;
+typedef string IdentifierName;
+typedef string Label;
+
+enum VariableDeclarationKind {
+  "var",
+  "let",
+  "const"
+};
+
+enum CompoundAssignmentOperator {
+  "+=",
+  "-=",
+  "*=",
+  "/=",
+  "%=",
+  "**=",
+  "<<=",
+  ">>=",
+  ">>>=",
+  "|=",
+  "^=",
+  "&="
+};
+
+enum BinaryOperator {
+  ",",
+  "||",
+  "&&",
+  "|",
+  "^",
+  "&",
+  "==",
+  "!=",
+  "===",
+  "!==",
+  "<",
+  "<=",
+  ">",
+  ">=",
+  "in",
+  "instanceof",
+  "<<",
+  ">>",
+  ">>>",
+  "+",
+  "-",
+  "*",
+  "/",
+  "%",
+  "**",
+};
+
+enum UnaryOperator {
+  "+",
+  "-",
+  "!",
+  "~",
+  "typeof",
+  "void",
+  "delete"
+};
+
+enum UpdateOperator {
+  "++",
+  "--"
+};
+
+
+// deferred assertions
+
+interface AssertedBlockScope {
+  // checked eagerly during transformation
+  attribute FrozenArray<IdentifierName> lexicallyDeclaredNames;
+
+  // checked lazily as inner functions are invoked
+  attribute FrozenArray<IdentifierName> capturedNames;
+  attribute boolean hasDirectEval;
+};
+
+interface AssertedVarScope {
+  // checked eagerly during transformation
+  attribute FrozenArray<IdentifierName> lexicallyDeclaredNames;
+  attribute FrozenArray<IdentifierName> varDeclaredNames;
+
+  // checked lazily as inner functions are invoked
+  attribute FrozenArray<IdentifierName> capturedNames;
+  attribute boolean hasDirectEval;
+};
+
+interface AssertedParameterScope {
+  // checked eagerly during transformation
+  attribute FrozenArray<IdentifierName> parameterNames;
+
+  // checked lazily as inner functions are invoked
+  attribute FrozenArray<IdentifierName> capturedNames;
+  attribute boolean hasDirectEval;
+};
+
+// nodes
+
+interface Node {
+  [TypeIndicator] readonly attribute Type type;
+};
+
+typedef (Script or Module) Program;
+
+typedef (DoWhileStatement or
+         ForInStatement or
+         ForOfStatement or
+         ForStatement or
+         WhileStatement)
+        IterationStatement;
+
+typedef (Block or
+         BreakStatement or
+         ContinueStatement or
+         ClassDeclaration or
+         DebuggerStatement or
+         EmptyStatement or
+         ExpressionStatement or
+         FunctionDeclaration or
+         IfStatement or
+         IterationStatement or
+         LabelledStatement or
+         ReturnStatement or
+         SwitchStatement or
+         SwitchStatementWithDefault or
+         ThrowStatement or
+         TryCatchStatement or
+         TryFinallyStatement or
+         VariableDeclaration or
+         WithStatement)
+        Statement;
+
+typedef (LiteralBooleanExpression or
+         LiteralInfinityExpression or
+         LiteralNullExpression or
+         LiteralNumericExpression or
+         LiteralStringExpression)
+        Literal;
+
+typedef (Literal or
+         LiteralRegExpExpression or
+         ArrayExpression or
+         ArrowExpression or
+         AssignmentExpression or
+         BinaryExpression or
+         CallExpression or
+         CompoundAssignmentExpression or
+         ComputedMemberExpression or
+         ConditionalExpression or
+         ClassExpression or
+         FunctionExpression or
+         IdentifierExpression or
+         NewExpression or
+         NewTargetExpression or
+         ObjectExpression or
+         UnaryExpression or
+         StaticMemberExpression or
+         TemplateExpression or
+         ThisExpression or
+         UpdateExpression or
+         YieldExpression or
+         YieldStarExpression or
+         AwaitExpression)
+        Expression;
+
+typedef (ComputedPropertyName or
+         LiteralPropertyName)
+        PropertyName;
+
+typedef (Method or Getter or Setter) MethodDefinition;
+
+typedef (MethodDefinition or
+         DataProperty or
+         ShorthandProperty)
+        ObjectProperty;
+
+typedef (ExportAllFrom or
+         ExportFrom or
+         ExportLocals or
+         ExportDefault or
+         Export)
+        ExportDeclaration;
+
+typedef (ImportNamespace or Import) ImportDeclaration;
+
+
+// bindings
+
+interface BindingIdentifier : Node {
+  attribute Identifier name;
+};
+
+typedef (ObjectBinding or
+         ArrayBinding)
+        BindingPattern;
+typedef (BindingPattern or
+         BindingIdentifier)
+        Binding;
+
+typedef (AssignmentTargetIdentifier or
+         ComputedMemberAssignmentTarget or
+         StaticMemberAssignmentTarget)
+        SimpleAssignmentTarget;
+typedef (ObjectAssignmentTarget or
+         ArrayAssignmentTarget)
+        AssignmentTargetPattern;
+// `DestructuringAssignmentTarget`
+typedef (AssignmentTargetPattern or
+         SimpleAssignmentTarget)
+        AssignmentTarget;
+
+// `FormalParameter`
+typedef (Binding or
+         BindingWithInitializer)
+        Parameter;
+
+interface BindingWithInitializer : Node {
+  attribute Binding binding;
+  attribute Expression init;
+};
+
+interface AssignmentTargetIdentifier : Node {
+  attribute Identifier name;
+};
+
+interface ComputedMemberAssignmentTarget : Node {
+  // The object whose property is being assigned.
+  attribute (Expression or Super) _object;
+  // The expression resolving to the name of the property to be accessed.
+  attribute Expression expression;
+};
+
+interface StaticMemberAssignmentTarget : Node {
+  // The object whose property is being assigned.
+  attribute (Expression or Super) _object;
+  // The name of the property to be accessed.
+  attribute IdentifierName property;
+};
+
+// `ArrayBindingPattern`
+interface ArrayBinding : Node {
+  // The elements of the array pattern; a null value represents an elision.
+  attribute FrozenArray<(Binding or BindingWithInitializer)?> elements;
+  attribute Binding? rest;
+};
+
+// `SingleNameBinding`
+interface BindingPropertyIdentifier : Node {
+  attribute BindingIdentifier binding;
+  attribute Expression? init;
+};
+
+// `BindingProperty :: PropertyName : BindingElement`
+interface BindingPropertyProperty : Node {
+  attribute PropertyName name;
+  attribute (Binding or BindingWithInitializer) binding;
+};
+
+typedef (BindingPropertyIdentifier or
+         BindingPropertyProperty)
+        BindingProperty;
+
+interface ObjectBinding : Node {
+  attribute FrozenArray<BindingProperty> properties;
+};
+
+// This interface represents the case where the initializer is present in
+// `AssignmentElement :: DestructuringAssignmentTarget Initializer_opt`.
+interface AssignmentTargetWithInitializer : Node {
+  attribute AssignmentTarget binding;
+  attribute Expression init;
+};
+
+// `ArrayAssignmentPattern`
+interface ArrayAssignmentTarget : Node {
+  // The elements of the array pattern; a null value represents an elision.
+  attribute FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer?)> elements;
+  attribute AssignmentTarget? rest;
+};
+
+// `AssignmentProperty :: IdentifierReference Initializer_opt`
+interface AssignmentTargetPropertyIdentifier : Node {
+  attribute AssignmentTargetIdentifier binding;
+  attribute Expression? init;
+};
+
+// `AssignmentProperty :: PropertyName : Node`
+interface AssignmentTargetPropertyProperty : Node {
+  attribute PropertyName name;
+  attribute (AssignmentTarget or AssignmentTargetWithInitializer) binding;
+};
+
+typedef (AssignmentTargetPropertyIdentifier or
+         AssignmentTargetPropertyProperty)
+        AssignmentTargetProperty;
+
+// `ObjectAssignmentPattern`
+interface ObjectAssignmentTarget : Node {
+  attribute FrozenArray<AssignmentTargetProperty> properties;
+};
+
+
+// classes
+
+interface ClassExpression : Node {
+  attribute BindingIdentifier? name;
+  attribute Expression? super;
+  attribute FrozenArray<ClassElement> elements;
+};
+
+interface ClassDeclaration : Node {
+  attribute BindingIdentifier name;
+  attribute Expression? super;
+  attribute FrozenArray<ClassElement> elements;
+};
+
+interface ClassElement : Node {
+  // True iff `IsStatic` of ClassElement is true.
+  attribute boolean isStatic;
+  attribute MethodDefinition method;
+};
+
+
+// modules
+
+interface Module : Node {
+  attribute AssertedVarScope? scope;
+  attribute FrozenArray<Directive> directives;
+  attribute FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items;
+};
+
+// An `ImportDeclaration` not including a namespace import.
+interface Import : Node {
+  attribute string moduleSpecifier;
+  // `ImportedDefaultBinding`, if present.
+  attribute BindingIdentifier? defaultBinding;
+  attribute FrozenArray<ImportSpecifier> namedImports;
+};
+
+// An `ImportDeclaration` including a namespace import.
+interface ImportNamespace : Node {
+  attribute string moduleSpecifier;
+  // `ImportedDefaultBinding`, if present.
+  attribute BindingIdentifier? defaultBinding;
+  attribute BindingIdentifier namespaceBinding;
+};
+
+interface ImportSpecifier : Node {
+  // The `IdentifierName` in the production `ImportSpecifier :: IdentifierName as ImportedBinding`;
+  // absent if this specifier represents the production `ImportSpecifier :: ImportedBinding`.
+  attribute IdentifierName? name;
+  attribute BindingIdentifier binding;
+};
+
+// `export * FromClause;`
+interface ExportAllFrom : Node {
+  attribute string moduleSpecifier;
+};
+
+// `export ExportClause FromClause;`
+interface ExportFrom : Node {
+  attribute FrozenArray<ExportFromSpecifier> namedExports;
+  attribute string moduleSpecifier;
+};
+
+// `export ExportClause;`
+interface ExportLocals : Node {
+  attribute FrozenArray<ExportLocalSpecifier> namedExports;
+};
+
+// `export VariableStatement`, `export Declaration`
+interface Export : Node {
+  attribute (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration;
+};
+
+// `export default HoistableDeclaration`,
+// `export default ClassDeclaration`,
+// `export default AssignmentExpression`
+interface ExportDefault : Node {
+  attribute (FunctionDeclaration or ClassDeclaration or Expression) body;
+};
+
+// `ExportSpecifier`, as part of an `ExportFrom`.
+interface ExportFromSpecifier : Node {
+  // The only `IdentifierName in `ExportSpecifier :: IdentifierName`,
+  // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`.
+  attribute IdentifierName name;
+  // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`,
+  // if that is the production represented.
+  attribute IdentifierName? exportedName;
+};
+
+// `ExportSpecifier`, as part of an `ExportLocals`.
+interface ExportLocalSpecifier : Node {
+  // The only `IdentifierName in `ExportSpecifier :: IdentifierName`,
+  // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`.
+  attribute IdentifierExpression name;
+  // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`, if present.
+  attribute IdentifierName? exportedName;
+};
+
+
+// property definition
+
+// `MethodDefinition :: PropertyName ( UniqueFormalParameters ) { FunctionBody }`,
+// `GeneratorMethod :: * PropertyName ( UniqueFormalParameters ) { GeneratorBody }`,
+// `AsyncMethod :: async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }`
+interface Method : Node {
+  // True for `AsyncMethod`, false otherwise.
+  attribute boolean isAsync;
+  // True for `GeneratorMethod`, false otherwise.
+  attribute boolean isGenerator;
+  attribute AssertedParameterScope? parameterScope;
+  attribute AssertedVarScope? bodyScope;
+  attribute PropertyName name;
+  // The `UniqueFormalParameters`.
+  attribute FormalParameters params;
+  attribute FunctionBody body;
+};
+
+// `get PropertyName ( ) { FunctionBody }`
+interface Getter : Node {
+  attribute AssertedVarScope? bodyScope;
+  attribute PropertyName name;
+  attribute FunctionBody body;
+};
+
+// `set PropertyName ( PropertySetParameterList ) { FunctionBody }`
+interface Setter : Node {
+  attribute AssertedParameterScope? parameterScope;
+  attribute AssertedVarScope? bodyScope;
+  attribute PropertyName name;
+  // The `PropertySetParameterList`.
+  attribute Parameter param;
+  attribute FunctionBody body;
+};
+
+// `PropertyDefinition :: PropertyName : AssignmentExpression`
+interface DataProperty : Node {
+  attribute PropertyName name;
+  // The `AssignmentExpression`.
+  attribute Expression expression;
+};
+
+// `PropertyDefinition :: IdentifierReference`
+interface ShorthandProperty : Node {
+  // The `IdentifierReference`.
+  attribute IdentifierExpression name;
+};
+
+interface ComputedPropertyName : Node {
+  attribute Expression expression;
+};
+
+// `LiteralPropertyName`
+interface LiteralPropertyName : Node {
+  attribute string value;
+};
+
+
+// literals
+
+// `BooleanLiteral`
+interface LiteralBooleanExpression : Node {
+  attribute boolean value;
+};
+
+// A `NumericLiteral` for which the Number value of its MV is positive infinity.
+interface LiteralInfinityExpression : Node { };
+
+// `NullLiteral`
+interface LiteralNullExpression : Node { };
+
+// `NumericLiteral`
+interface LiteralNumericExpression : Node {
+  attribute double value;
+};
+
+// `RegularExpressionLiteral`
+interface LiteralRegExpExpression : Node {
+  attribute string pattern;
+  attribute string flags;
+};
+
+// `StringLiteral`
+interface LiteralStringExpression : Node {
+  attribute string value;
+};
+
+
+// other expressions
+
+// `ArrayLiteral`
+interface ArrayExpression : Node {
+  // The elements of the array literal; a null value represents an elision.
+  attribute FrozenArray<(SpreadElement or Expression)?> elements;
+};
+
+// `ArrowFunction`,
+// `AsyncArrowFunction`
+interface ArrowExpression : Node {
+  // True for `AsyncArrowFunction`, false otherwise.
+  attribute boolean isAsync;
+  attribute AssertedParameterScope? parameterScope;
+  attribute AssertedVarScope? bodyScope;
+  attribute FormalParameters params;
+  attribute (FunctionBody or Expression) body;
+};
+
+// `AssignmentExpression :: LeftHandSideExpression = AssignmentExpression`
+interface AssignmentExpression : Node {
+  // The `LeftHandSideExpression`.
+  attribute AssignmentTarget binding;
+  // The `AssignmentExpression` following the `=`.
+  attribute Expression expression;
+};
+
+// `ExponentiationExpression`,
+// `MultiplicativeExpression`,
+// `AdditiveExpression`,
+// `ShiftExpression`,
+// `RelationalExpression`,
+// `EqualityExpression`,
+// `BitwiseANDExpression`,
+// `BitwiseXORExpression`,
+// `BitwiseORExpression`,
+// `LogicalANDExpression`,
+// `LogicalORExpression`
+interface BinaryExpression : Node {
+  attribute BinaryOperator operator;
+  // The expression before the operator.
+  attribute Expression left;
+  // The expression after the operator.
+  attribute Expression right;
+};
+
+interface CallExpression : Node {
+  attribute (Expression or Super) callee;
+  attribute Arguments arguments;
+};
+
+// `AssignmentExpression :: LeftHandSideExpression AssignmentOperator AssignmentExpression`
+interface CompoundAssignmentExpression : Node {
+  attribute CompoundAssignmentOperator operator;
+  // The `LeftHandSideExpression`.
+  attribute SimpleAssignmentTarget binding;
+  // The `AssignmentExpression`.
+  attribute Expression expression;
+};
+
+interface ComputedMemberExpression : Node {
+  // The object whose property is being accessed.
+  attribute (Expression or Super) _object;
+  // The expression resolving to the name of the property to be accessed.
+  attribute Expression expression;
+};
+
+// `ConditionalExpression :: LogicalORExpression ? AssignmentExpression : AssignmentExpression`
+interface ConditionalExpression : Node {
+  // The `LogicalORExpression`.
+  attribute Expression test;
+  // The first `AssignmentExpression`.
+  attribute Expression consequent;
+  // The second `AssignmentExpression`.
+  attribute Expression alternate;
+};
+
+// `FunctionExpression`,
+// `GeneratorExpression`,
+// `AsyncFunctionExpression`,
+interface FunctionExpression : Node {
+  attribute boolean isAsync;
+  attribute boolean isGenerator;
+  attribute AssertedParameterScope? parameterScope;
+  attribute AssertedVarScope? bodyScope;
+  attribute BindingIdentifier? name;
+  attribute FormalParameters params;
+  attribute FunctionBody body;
+};
+
+// `IdentifierReference`
+interface IdentifierExpression : Node {
+  attribute Identifier name;
+};
+
+interface NewExpression : Node {
+  attribute Expression callee;
+  attribute Arguments arguments;
+};
+
+interface NewTargetExpression : Node { };
+
+interface ObjectExpression : Node {
+  attribute FrozenArray<ObjectProperty> properties;
+};
+
+interface UnaryExpression : Node {
+  attribute UnaryOperator operator;
+  attribute Expression operand;
+};
+
+interface StaticMemberExpression : Node {
+  // The object whose property is being accessed.
+  attribute (Expression or Super) _object;
+  // The name of the property to be accessed.
+  attribute IdentifierName property;
+};
+
+// `TemplateLiteral`,
+// `MemberExpression :: MemberExpression TemplateLiteral`,
+// `CallExpression : CallExpression TemplateLiteral`
+interface TemplateExpression : Node {
+  // The second `MemberExpression` or `CallExpression`, if present.
+  attribute Expression? tag;
+  // The contents of the template. This list must be alternating
+  // TemplateElements and Expressions, beginning and ending with
+  // TemplateElement.
+  attribute FrozenArray<(Expression or TemplateElement)> elements;
+};
+
+// `PrimaryExpression :: this`
+interface ThisExpression : Node { };
+
+// `UpdateExpression :: LeftHandSideExpression ++`,
+// `UpdateExpression :: LeftHandSideExpression --`,
+// `UpdateExpression :: ++ LeftHandSideExpression`,
+// `UpdateExpression :: -- LeftHandSideExpression`
+interface UpdateExpression : Node {
+  // True for `UpdateExpression :: ++ LeftHandSideExpression` and
+  // `UpdateExpression :: -- LeftHandSideExpression`, false otherwise.
+  attribute boolean isPrefix;
+  attribute UpdateOperator operator;
+  attribute SimpleAssignmentTarget operand;
+};
+
+// `YieldExpression :: yield`,
+// `YieldExpression :: yield AssignmentExpression`
+interface YieldExpression : Node {
+  // The `AssignmentExpression`, if present.
+  attribute Expression? expression;
+};
+
+// `YieldExpression :: yield * AssignmentExpression`
+interface YieldStarExpression : Node {
+  attribute Expression expression;
+};
+
+interface AwaitExpression : Node {
+  attribute Expression expression;
+};
+
+
+// other statements
+
+interface BreakStatement : Node {
+  attribute Label? label;
+};
+
+interface ContinueStatement : Node {
+  attribute Label? label;
+};
+
+interface DebuggerStatement : Node { };
+
+interface DoWhileStatement : Node {
+  attribute Expression test;
+  attribute Statement body;
+};
+
+interface EmptyStatement : Node { };
+
+interface ExpressionStatement : Node {
+  attribute Expression expression;
+};
+
+interface ForInOfBinding : Node {
+  attribute VariableDeclarationKind kind;
+  attribute Binding binding;
+};
+
+// `for ( LeftHandSideExpression in Expression ) Statement`,
+// `for ( var ForBinding in Expression ) Statement`,
+// `for ( ForDeclaration in Expression ) Statement`,
+// `for ( var BindingIdentifier Initializer in Expression ) Statement`
+interface ForInStatement : Node {
+  // The expression or declaration before `in`.
+  attribute (ForInOfBinding or AssignmentTarget) left;
+  // The expression after `in`.
+  attribute Expression right;
+  attribute Statement body;
+};
+
+// `for ( LeftHandSideExpression of Expression ) Statement`,
+// `for ( var ForBinding of Expression ) Statement`,
+// `for ( ForDeclaration of Expression ) Statement`
+interface ForOfStatement : Node {
+  // The expression or declaration before `of`.
+  attribute (ForInOfBinding or AssignmentTarget) left;
+  // The expression after `of`.
+  attribute Expression right;
+  attribute Statement body;
+};
+
+// `for ( Expression ; Expression ; Expression ) Statement`,
+// `for ( var VariableDeclarationList ; Expression ; Expression ) Statement`
+interface ForStatement : Node {
+  // The expression or declaration before the first `;`, if present.
+  attribute (VariableDeclaration or Expression)? init;
+  // The expression before the second `;`, if present
+  attribute Expression? test;
+  // The expression after the second `;`, if present
+  attribute Expression? update;
+  attribute Statement body;
+};
+
+// `if ( Expression ) Statement`,
+// `if ( Expression ) Statement else Statement`,
+interface IfStatement : Node {
+  attribute Expression test;
+  // The first `Statement`.
+  attribute Statement consequent;
+  // The second `Statement`, if present.
+  attribute Statement? alternate;
+};
+
+interface LabelledStatement : Node {
+  attribute Label label;
+  attribute Statement body;
+};
+
+interface ReturnStatement : Node {
+  attribute Expression? expression;
+};
+
+// A `SwitchStatement` whose `CaseBlock` is
+//   `CaseBlock :: { CaseClauses }`.
+interface SwitchStatement : Node {
+  attribute Expression discriminant;
+  attribute FrozenArray<SwitchCase> cases;
+};
+
+// A `SwitchStatement` whose `CaseBlock` is
+//   `CaseBlock :: { CaseClauses DefaultClause CaseClauses }`.
+interface SwitchStatementWithDefault : Node {
+  attribute Expression discriminant;
+  // The `CaseClauses` before the `DefaultClause`.
+  attribute FrozenArray<SwitchCase> preDefaultCases;
+  // The `DefaultClause`.
+  attribute SwitchDefault defaultCase;
+  // The `CaseClauses` after the `DefaultClause`.
+  attribute FrozenArray<SwitchCase> postDefaultCases;
+};
+
+interface ThrowStatement : Node {
+  attribute Expression expression;
+};
+
+// `TryStatement :: try Block Catch`
+interface TryCatchStatement : Node {
+  attribute Block body;
+  attribute CatchClause catchClause;
+};
+
+// `TryStatement :: try Block Finally`,
+// `TryStatement :: try Block Catch Finally`
+interface TryFinallyStatement : Node {
+  // The `Block`.
+  attribute Block body;
+  // The `Catch`, if present.
+  attribute CatchClause? catchClause;
+  // The `Finally`.
+  attribute Block finalizer;
+};
+
+interface WhileStatement : Node {
+  attribute Expression test;
+  attribute Statement body;
+};
+
+interface WithStatement : Node {
+  attribute Expression _object;
+  attribute Statement body;
+};
+
+
+// other nodes
+
+interface Block : Node {
+  attribute AssertedBlockScope? scope;
+  attribute FrozenArray<Statement> statements;
+};
+
+// `Catch`
+interface CatchClause : Node {
+  attribute Binding binding;
+  attribute Block body;
+};
+
+// An item in a `DirectivePrologue`
+interface Directive : Node {
+  attribute string rawValue;
+};
+
+interface FormalParameters : Node {
+  attribute FrozenArray<Parameter> items;
+  attribute Binding? rest;
+};
+
+interface FunctionBody : Node {
+  attribute FrozenArray<Directive> directives;
+  attribute FrozenArray<Statement> statements;
+};
+
+// `FunctionDeclaration`,
+// `GeneratorDeclaration`,
+// `AsyncFunctionDeclaration`
+interface FunctionDeclaration : Node {
+  attribute boolean isAsync;
+  attribute boolean isGenerator;
+  attribute AssertedParameterScope? parameterScope;
+  attribute AssertedVarScope? bodyScope;
+  attribute BindingIdentifier name;
+  attribute FormalParameters params;
+  attribute FunctionBody body;
+};
+
+interface Script : Node {
+  attribute AssertedVarScope? scope;
+  attribute FrozenArray<Directive> directives;
+  attribute FrozenArray<Statement> statements;
+};
+
+interface SpreadElement : Node {
+  attribute Expression expression;
+};
+
+// `super`
+interface Super : Node { };
+
+// `CaseClause`
+interface SwitchCase : Node {
+  attribute Expression test;
+  attribute FrozenArray<Statement> consequent;
+};
+
+// `DefaultClause`
+interface SwitchDefault : Node {
+  attribute FrozenArray<Statement> consequent;
+};
+
+// `TemplateCharacters`
+interface TemplateElement : Node {
+  attribute string rawValue;
+};
+
+interface VariableDeclaration : Node {
+  attribute VariableDeclarationKind kind;
+  [NonEmpty] attribute FrozenArray<VariableDeclarator> declarators;
+};
+
+interface VariableDeclarator : Node {
+  attribute Binding binding;
+  attribute Expression? init;
+};
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSource.yaml
@@ -0,0 +1,1086 @@
+# 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/.
+
+# Rules for generating BinSource-auto.cpp
+cpp:
+    header: |
+        /* -*- 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
+        };
+
+    footer: |
+
+        #undef TRY
+        #undef TRY_VAR
+        #undef TRY_DECL
+        #undef MOZ_TRY_DECL
+        } // namespace frontend
+        } // namespace js
+
+hpp:
+    # Rules for generating BinSource-class.h
+    class:
+        header: |
+            /* -*- 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.
+
+    # Rules for generating BinToken.h
+    tokens:
+        kind:
+            doc: |
+                /**
+                 * The different kinds of Binary AST nodes, as per the specifications of
+                 * Binary AST.
+                 *
+                 * These kinds match roughly with the `ParseNodeKind` used internally.
+                 *
+                 * Usage:
+                 *
+                 * ```c++
+                 * #define WITH_KIND(CPP_NAME, SPEC_NAME) ...
+                 * FOR_EACH_BIN_KIND(WITH_KIND)
+                 * ```
+                 *
+                 *
+                 * (sorted by alphabetical order)
+                 */
+        field:
+            doc: |
+                /**
+                 * The different fields of Binary AST nodes, as per the specifications of
+                 * Binary AST.
+                 *
+                 * Usage:
+                 *
+                 * ```c++
+                 * #define WITH_FIELD(CPP_NAME, SPEC_NAME) ...
+                 * FOR_EACH_BIN_FIELD(WITH_FIELD)
+                 * ```
+                 *
+                 * (sorted by alphabetical order)
+                 */
+
+        header: |
+            /* -*- 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.
+
+            #ifndef frontend_BinToken_h
+            #define frontend_BinToken_h
+
+            #include <stddef.h>
+
+            /**
+             * Definition of Binary AST tokens.
+             *
+             * In the Binary AST world, an AST is composed of nodes, where a node is
+             * defined by:
+             * - a Kind (see `BinKind`);
+             * - a list of fields, where each field is:
+             *    - a Name (see `BinField`);
+             *    - a Value, which may be either a node or a primitive value.
+             *
+             * The mapping between Kind and list of fields is determined entirely by
+             * the grammar of Binary AST. The mapping between (Kind, Name) and the
+             * structure of Value is also determined entirely by the grammar of
+             * Binary AST.
+             *
+             * As per the specifications of Binary AST, kinds may be added as the
+             * language grows, but never removed. The mapping between Kind and list
+             * of fields may also change to add new fields or make some fields optional,
+             * but may never remove a field. Finally, the mapping between (Kind, Name)
+             * and the structure of Value may be modified to add new possible values,
+             * but never to remove a value.
+             *
+             * A Binary AST parser must be able to fail gracefully when confronted with
+             * unknown Kinds or Names.
+             */
+
+            namespace js {
+            namespace frontend {
+        footer: |
+
+            /**
+             * Return a string describing a `BinKind`.
+             */
+            const char* describeBinKind(const BinKind& kind);
+
+            /**
+             * Return a string describing a `BinField`.
+             */
+            const char* describeBinField(const BinField& kind);
+
+            } // namespace frontend
+            } // namespace js
+
+            #endif // frontend_BinToken_h
+
+Arguments:
+    init:
+        TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
+    append:
+        factory_.addList(/* list = */ result, /* child = */ item);
+
+ArrayExpression:
+    build:
+        auto result = elements;
+
+AssertedBlockScope:
+    type-ok:
+        Ok
+    build: |
+        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();
+    fields:
+        capturedNames:
+            block:
+                replace: |
+                    MOZ_TRY(parseAndUpdateCapturedNames());
+        hasDirectEval:
+            after: |
+                if (hasDirectEval) {
+                    parseContext_->sc()->setHasDirectEval();
+                    parseContext_->sc()->setBindingsAccessedDynamically();
+                }
+        lexicallyDeclaredNames:
+            block:
+                replace:
+                    MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
+
+AssertedParameterScope:
+    inherits: AssertedBlockScope
+    fields:
+        parameterNames:
+            block:
+                replace: |
+                    MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter));
+
+AssertedVarScope:
+    inherits: AssertedBlockScope
+    fields:
+        varDeclaredNames:
+            block:
+                replace:
+                    MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var));
+
+AssignmentExpression:
+    build: |
+        TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression));
+
+AssignmentTargetIdentifier:
+    build: |
+        if (!IsIdentifier(name))
+            return raiseError("Invalid identifier");
+        TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
+
+BindingIdentifier:
+    build: |
+        if (!IsIdentifier(name))
+            return raiseError("Invalid identifier");
+        TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
+
+BinaryExpression:
+    build: |
+        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;
+        }
+
+Block:
+    init: |
+        fprintf(stderr, "Block: PUSH parse context\n");
+        ParseContext::Statement stmt(parseContext_, StatementKind::Block);
+        ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
+        TRY(currentScope.init(parseContext_));
+    build: |
+        TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_));
+        TRY_DECL(result, factory_.newLexicalScope(*bindings, statements));
+        fprintf(stderr, "Block: POP parse context\n");
+
+BreakStatement:
+    fields:
+        label:
+            block:
+                replace: |
+                    RootedAtom label(cx_);
+                    MOZ_TRY(readMaybeString(&label));
+
+                    if (label && !IsIdentifier(label))
+                        return raiseError("Invalid identifier");
+    build: |
+        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)));
+
+CallExpression:
+    build: |
+        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);
+
+
+CatchClause:
+    init: |
+        ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
+        ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
+        TRY(currentScope.init(parseContext_));
+    build: |
+        // 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));
+
+CompoundAssignmentExpression:
+    build: |
+        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));
+
+ComputedMemberAssignmentTarget:
+    build: |
+        TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+
+ComputedMemberExpression:
+    build: |
+        TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+
+ConditionalExpression:
+    build: |
+        TRY_DECL(result, factory_.newConditional(test, consequent, alternate));
+
+ContinueStatement:
+    fields:
+        label:
+            block:
+                replace: |
+                    RootedAtom label(cx_);
+                    MOZ_TRY(readMaybeString(&label));
+
+                    if (label && !IsIdentifier(label))
+                        return raiseError("ContinueStatement - Label MUST be an identifier");
+    build: |
+        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)));
+
+DataProperty:
+    build: |
+        if (!factory_.isUsableAsObjectPropertyName(name))
+            return raiseError("DataProperty key kind");
+
+        TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));
+
+Directive:
+    build: |
+        TokenPos pos = tokenizer_->pos(start);
+        TRY_DECL(result, factory_.newStringLiteral(rawValue, pos));
+
+DoWhileStatement:
+    init:
+        ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop);
+    build:
+        TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
+
+EmptyStatement:
+    build:
+        TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));
+
+ExpressionStatement:
+    build:
+        TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset()));
+
+ForInOfBinding:
+    init:
+        AutoVariableDeclarationKind kindGuard(this);
+    build: |
+        // 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);
+
+
+
+ForInStatement:
+    init: |
+        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_));
+    build: |
+        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));
+        }
+
+FormalParameters:
+    build: |
+        auto result = items;
+        if (rest) {
+            TRY_DECL(spread, factory_.newSpread(start, rest));
+            factory_.addList(result, spread);
+        }
+
+ForStatement:
+    init: |
+        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_));
+    build: |
+        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));
+        }
+
+FunctionBody:
+    build: |
+        MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));
+
+FunctionDeclaration:
+    inherits: FunctionExpression
+
+FunctionExpression:
+    fields:
+        parameterScope:
+            before: |
+                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_));
+    build: |
+        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));
+
+IdentifierExpression:
+    build: |
+        if (!IsIdentifier(name))
+            return raiseError("Invalid identifier");
+        TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));
+
+IfStatement:
+    build: |
+        TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate));
+
+LabelledStatement:
+    fields:
+        label:
+            after: |
+                if (!IsIdentifier(label))
+                    return raiseError("Invalid identifier");
+                ParseContext::LabelStatement stmt(parseContext_, label);
+    build:
+        TRY_DECL(result, factory_.newLabeledStatement(label->asPropertyName(), body, start));
+
+ListOfDirective:
+    init:
+        TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+    append:
+        factory_.addStatementToList(result, item);
+
+ListOfObjectProperty:
+    init:
+        TRY_DECL(result, factory_.newObjectLiteral(start));
+
+ListOfOptionalSpreadElementOrExpression:
+    init:
+        TRY_DECL(result, factory_.newArrayLiteral(start));
+    append: |
+        if (item)
+            factory_.addArrayElement(result, item); // Infallible.
+        else
+            TRY(factory_.addElision(result, tokenizer_->pos(start)));
+
+ListOfParameter:
+    init: |
+        ParseNode* result = new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start));
+    append:
+        factory_.addList(/* list = */ result, /* item = */ item);
+
+ListOfStatement:
+    init:
+        TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+    append:
+        factory_.addStatementToList(result, item);
+
+
+#ListOfSpreadElementOrExpression:
+#    init:
+#        ParseNode* result = new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos());
+#    append:
+#        result->appendWithoutOrderAssumption(item);
+
+ListOfSwitchCase:
+    init:
+        TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
+    append:
+        factory_.addCaseStatementToList(result, item);
+
+ListOfVariableDeclarator:
+    init: |
+        TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/,
+            tokenizer_->pos(start)));
+
+LiteralBooleanExpression:
+    build:
+        TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start)));
+
+LiteralNumericExpression:
+    build:
+        TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));
+
+LiteralNullExpression:
+    build:
+        TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));
+
+LiteralPropertyName:
+    build: |
+        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)));
+
+LiteralRegExpExpression:
+    fields:
+        flags:
+            block:
+                replace:
+                    Chars flags(cx_);
+                    MOZ_TRY(readString(flags));
+    build: |
+        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));
+
+LiteralStringExpression:
+    build:
+        TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));
+
+Method:
+    inherits: FunctionExpression
+    build: |
+        MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox));
+        TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None));
+
+NewExpression:
+    build: |
+        auto result = arguments;
+        result->setKind(ParseNodeKind::New);
+        result->prepend(callee);
+
+ObjectExpression:
+    build:
+        auto result = properties;
+
+OptionalAssertedBlockScope:
+    type-ok:
+        Ok
+
+OptionalAssertedVarScope:
+    type-ok:
+        Ok
+
+OptionalAssertedParameterScope:
+    type-ok:
+        Ok
+
+ReturnStatement:
+    init: |
+        if (!parseContext_->isFunctionBox()) {
+            // Return statements are permitted only inside functions.
+            return raiseInvalidKind("Toplevel Statement", kind);
+        }
+
+        parseContext_->functionBox()->usesReturn = true;
+    build:
+        TRY_DECL(result, factory_.newReturnStatement(expression, tokenizer_->pos(start)));
+
+Script:
+    build:
+        MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));
+
+Setter:
+    inherits: Method
+    init: |
+        const auto isAsync = false;
+        const auto isGenerator = false;
+    build: |
+        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));
+
+ShorthandProperty:
+    build: |
+        if (!factory_.isUsableAsObjectPropertyName(name))
+            TRY_VAR(name, factory_.newObjectLiteralPropertyName(name->name(), tokenizer_->pos(start)));
+
+        TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, name, AccessorType::None));
+
+SwitchCase:
+    build: |
+        TRY_DECL(result, factory_.newCaseOrDefault(start, test, consequent));
+
+SwitchDefault:
+    build: |
+        TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));
+
+SwitchStatement:
+    build: |
+        TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
+        TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));
+
+SwitchStatementWithDefault:
+    build: |
+        // 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));
+
+StaticMemberAssignmentTarget:
+    build: |
+        TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+
+StaticMemberExpression:
+    build: |
+        TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+
+ThisExpression:
+    build: |
+        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));
+
+ThrowStatement:
+    build:
+        TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));
+
+TryCatchStatement:
+    fields:
+        body:
+            block:
+                declare:
+                    ParseNode* body;
+                before: |
+                    ParseContext::Statement stmt(parseContext_, StatementKind::Try);
+                    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+                    TRY(scope.init(parseContext_));
+    build:
+        TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, /* finally = */ nullptr));
+
+TryFinallyStatement:
+    fields:
+        body:
+            block:
+                declare:
+                    ParseNode* body;
+                before: |
+                    ParseContext::Statement stmt(parseContext_, StatementKind::Try);
+                    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+                    TRY(scope.init(parseContext_));
+        finalizer:
+            block:
+                declare:
+                    ParseNode* finalizer;
+                before: |
+                    ParseContext::Statement stmt(parseContext_, StatementKind::Finally);
+                    ParseContext::Scope scope(cx_, parseContext_, usedNames_);
+                    TRY(scope.init(parseContext_));
+    build:
+        TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, finalizer));
+
+UnaryExpression:
+    build: |
+        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));
+
+UpdateExpression:
+    build: |
+        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));
+
+VariableDeclaration:
+    init:
+        AutoVariableDeclarationKind kindGuard(this);
+
+    fields:
+        kind:
+            after: |
+                // Restored by `kindGuard`.
+                variableDeclarationKind_ = kind_;
+
+    build: |
+        // 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;
+
+VariableDeclarator:
+    build: |
+        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));
+        }
+
+WhileStatement:
+    init:
+        ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop);
+    build:
+        TRY_DECL(result, factory_.newWhileStatement(start, test, body));
+
+WithStatement:
+    build:
+        TRY_DECL(result, factory_.newWithStatement(start, object, body));
--- a/js/src/frontend/BinToken.h
+++ b/js/src/frontend/BinToken.h
@@ -1,207 +1,347 @@
+// 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.
+
 #ifndef frontend_BinToken_h
 #define frontend_BinToken_h
 
+#include <stddef.h>
+
 /**
  * Definition of Binary AST tokens.
  *
  * In the Binary AST world, an AST is composed of nodes, where a node is
  * defined by:
  * - a Kind (see `BinKind`);
  * - a list of fields, where each field is:
  *    - a Name (see `BinField`);
  *    - a Value, which may be either a node or a primitive value.
  *
  * The mapping between Kind and list of fields is determined entirely by
- * the grammar of Binary AST. The mapping between (Kind, Name) and the structure
- * of Value is also determined entirely by the grammar of Binary AST.
+ * the grammar of Binary AST. The mapping between (Kind, Name) and the
+ * structure of Value is also determined entirely by the grammar of
+ * Binary AST.
  *
- * As per the specifications of Binary AST, kinds may be added as the language
- * grows, but never removed. The mapping between Kind and list of fields may
- * also change to add new fields or make some fields optional, but may never
- * remove a field. Finally, the mapping between (Kind, Name) and the structure
- * of Value may be modified to add new possible values, but never to remove a
- * value.
+ * As per the specifications of Binary AST, kinds may be added as the
+ * language grows, but never removed. The mapping between Kind and list
+ * of fields may also change to add new fields or make some fields optional,
+ * but may never remove a field. Finally, the mapping between (Kind, Name)
+ * and the structure of Value may be modified to add new possible values,
+ * but never to remove a value.
  *
  * A Binary AST parser must be able to fail gracefully when confronted with
  * unknown Kinds or Names.
- *
- * At the time of this writing, the Binary AST defined from the Babylon AST
- * (see https://github.com/babel/babylon/blob/master/ast/spec.md) restricted
- * to ES5, with a few amendments to store additional scoping data and to
- * represent the empty AST.
- *
- * Future versions of the Binary AST will progressively grow to encompass ES6
- * and beyond.
  */
 
 namespace js {
 namespace frontend {
 
- /**
+/**
  * The different kinds of Binary AST nodes, as per the specifications of
  * Binary AST.
  *
  * These kinds match roughly with the `ParseNodeKind` used internally.
  *
  * Usage:
  *
  * ```c++
  * #define WITH_KIND(CPP_NAME, SPEC_NAME) ...
  * FOR_EACH_BIN_KIND(WITH_KIND)
  * ```
  *
  *
  * (sorted by alphabetical order)
  */
 #define FOR_EACH_BIN_KIND(F) \
+    F(Arguments, Arguments) \
+    F(ArrayAssignmentTarget, ArrayAssignmentTarget) \
+    F(ArrayBinding, ArrayBinding) \
     F(ArrayExpression, ArrayExpression) \
+    F(ArrowExpression, ArrowExpression) \
+    F(AssertedBlockScope, AssertedBlockScope) \
+    F(AssertedParameterScope, AssertedParameterScope) \
+    F(AssertedVarScope, AssertedVarScope) \
     F(AssignmentExpression, AssignmentExpression) \
-    F(AssignmentOperator, AssignmentOperator) \
+    F(AssignmentTarget, AssignmentTarget) \
+    F(AssignmentTargetIdentifier, AssignmentTargetIdentifier) \
+    F(AssignmentTargetOrAssignmentTargetWithInitializer, AssignmentTargetOrAssignmentTargetWithInitializer) \
+    F(AssignmentTargetPattern, AssignmentTargetPattern) \
+    F(AssignmentTargetProperty, AssignmentTargetProperty) \
+    F(AssignmentTargetPropertyIdentifier, AssignmentTargetPropertyIdentifier) \
+    F(AssignmentTargetPropertyProperty, AssignmentTargetPropertyProperty) \
+    F(AssignmentTargetWithInitializer, AssignmentTargetWithInitializer) \
+    F(AwaitExpression, AwaitExpression) \
     F(BinaryExpression, BinaryExpression) \
     F(BinaryOperator, BinaryOperator) \
-    F(BINJS_Scope, BINJS:Scope) \
-    F(BlockStatement, BlockStatement) \
-    F(BooleanLiteral, BooleanLiteral) \
-    F(BracketExpression, BracketExpression) \
+    F(Binding, Binding) \
+    F(BindingIdentifier, BindingIdentifier) \
+    F(BindingOrBindingWithInitializer, BindingOrBindingWithInitializer) \
+    F(BindingPattern, BindingPattern) \
+    F(BindingProperty, BindingProperty) \
+    F(BindingPropertyIdentifier, BindingPropertyIdentifier) \
+    F(BindingPropertyProperty, BindingPropertyProperty) \
+    F(BindingWithInitializer, BindingWithInitializer) \
+    F(Block, Block) \
     F(BreakStatement, BreakStatement) \
     F(CallExpression, CallExpression) \
     F(CatchClause, CatchClause) \
+    F(ClassDeclaration, ClassDeclaration) \
+    F(ClassElement, ClassElement) \
+    F(ClassExpression, ClassExpression) \
+    F(CompoundAssignmentExpression, CompoundAssignmentExpression) \
+    F(CompoundAssignmentOperator, CompoundAssignmentOperator) \
+    F(ComputedMemberAssignmentTarget, ComputedMemberAssignmentTarget) \
+    F(ComputedMemberExpression, ComputedMemberExpression) \
     F(ComputedPropertyName, ComputedPropertyName) \
     F(ConditionalExpression, ConditionalExpression) \
     F(ContinueStatement, ContinueStatement) \
+    F(DataProperty, DataProperty) \
     F(DebuggerStatement, DebuggerStatement) \
-    F(Declaration, Declaration) \
     F(Directive, Directive) \
-    F(DirectiveLiteral, DirectiveLiteral) \
-    F(DotExpression, DotExpression) \
     F(DoWhileStatement, DoWhileStatement) \
-    F(Elision, Elision) \
     F(EmptyStatement, EmptyStatement) \
+    F(Export, Export) \
+    F(ExportAllFrom, ExportAllFrom) \
+    F(ExportDeclaration, ExportDeclaration) \
+    F(ExportDefault, ExportDefault) \
+    F(ExportFrom, ExportFrom) \
+    F(ExportFromSpecifier, ExportFromSpecifier) \
+    F(ExportLocalSpecifier, ExportLocalSpecifier) \
+    F(ExportLocals, ExportLocals) \
     F(Expression, Expression) \
+    F(ExpressionOrSuper, ExpressionOrSuper) \
+    F(ExpressionOrTemplateElement, ExpressionOrTemplateElement) \
     F(ExpressionStatement, ExpressionStatement) \
+    F(ForInOfBinding, ForInOfBinding) \
+    F(ForInOfBindingOrAssignmentTarget, ForInOfBindingOrAssignmentTarget) \
+    F(ForInStatement, ForInStatement) \
+    F(ForOfStatement, ForOfStatement) \
     F(ForStatement, ForStatement) \
-    F(ForInStatement, ForInStatement) \
+    F(FormalParameters, FormalParameters) \
+    F(FunctionBody, FunctionBody) \
+    F(FunctionBodyOrExpression, FunctionBodyOrExpression) \
+    F(FunctionDeclaration, FunctionDeclaration) \
+    F(FunctionDeclarationOrClassDeclarationOrExpression, FunctionDeclarationOrClassDeclarationOrExpression) \
+    F(FunctionDeclarationOrClassDeclarationOrVariableDeclaration, FunctionDeclarationOrClassDeclarationOrVariableDeclaration) \
     F(FunctionExpression, FunctionExpression) \
-    F(FunctionDeclaration, FunctionDeclaration) \
+    F(Getter, Getter) \
     F(Identifier, Identifier) \
+    F(IdentifierExpression, IdentifierExpression) \
+    F(IdentifierName, IdentifierName) \
     F(IfStatement, IfStatement) \
-    F(LabeledStatement, LabeledStatement) \
+    F(Import, Import) \
+    F(ImportDeclaration, ImportDeclaration) \
+    F(ImportDeclarationOrExportDeclarationOrStatement, ImportDeclarationOrExportDeclarationOrStatement) \
+    F(ImportNamespace, ImportNamespace) \
+    F(ImportSpecifier, ImportSpecifier) \
+    F(IterationStatement, IterationStatement) \
+    F(Label, Label) \
+    F(LabelledStatement, LabelledStatement) \
+    F(ListOfAssignmentTargetOrAssignmentTargetWithInitializer, ListOfAssignmentTargetOrAssignmentTargetWithInitializer) \
+    F(ListOfAssignmentTargetProperty, ListOfAssignmentTargetProperty) \
+    F(ListOfBindingProperty, ListOfBindingProperty) \
+    F(ListOfClassElement, ListOfClassElement) \
+    F(ListOfDirective, ListOfDirective) \
+    F(ListOfExportFromSpecifier, ListOfExportFromSpecifier) \
+    F(ListOfExportLocalSpecifier, ListOfExportLocalSpecifier) \
+    F(ListOfExpressionOrTemplateElement, ListOfExpressionOrTemplateElement) \
+    F(ListOfIdentifierName, ListOfIdentifierName) \
+    F(ListOfImportDeclarationOrExportDeclarationOrStatement, ListOfImportDeclarationOrExportDeclarationOrStatement) \
+    F(ListOfImportSpecifier, ListOfImportSpecifier) \
+    F(ListOfObjectProperty, ListOfObjectProperty) \
+    F(ListOfOptionalBindingOrBindingWithInitializer, ListOfOptionalBindingOrBindingWithInitializer) \
+    F(ListOfOptionalSpreadElementOrExpression, ListOfOptionalSpreadElementOrExpression) \
+    F(ListOfParameter, ListOfParameter) \
+    F(ListOfStatement, ListOfStatement) \
+    F(ListOfSwitchCase, ListOfSwitchCase) \
+    F(ListOfVariableDeclarator, ListOfVariableDeclarator) \
     F(Literal, Literal) \
-    F(LogicalExpression, LogicalExpression) \
-    F(LogicalOperator, LogicalOperator) \
+    F(LiteralBooleanExpression, LiteralBooleanExpression) \
+    F(LiteralInfinityExpression, LiteralInfinityExpression) \
+    F(LiteralNullExpression, LiteralNullExpression) \
+    F(LiteralNumericExpression, LiteralNumericExpression) \
+    F(LiteralPropertyName, LiteralPropertyName) \
+    F(LiteralRegExpExpression, LiteralRegExpExpression) \
+    F(LiteralStringExpression, LiteralStringExpression) \
+    F(Method, Method) \
+    F(MethodDefinition, MethodDefinition) \
+    F(Module, Module) \
     F(NewExpression, NewExpression) \
-    F(NullLiteral, NullLiteral) \
-    F(NumericLiteral, NumericLiteral) \
+    F(NewTargetExpression, NewTargetExpression) \
+    F(ObjectAssignmentTarget, ObjectAssignmentTarget) \
+    F(ObjectBinding, ObjectBinding) \
     F(ObjectExpression, ObjectExpression) \
-    F(ObjectGetter, ObjectGetter) \
-    F(ObjectMethod, ObjectMethod) \
-    F(ObjectSetter, ObjectSetter) \
     F(ObjectProperty, ObjectProperty) \
-    F(Pattern, Pattern) \
+    F(OptionalAssertedBlockScope, OptionalAssertedBlockScope) \
+    F(OptionalAssertedParameterScope, OptionalAssertedParameterScope) \
+    F(OptionalAssertedVarScope, OptionalAssertedVarScope) \
+    F(OptionalAssignmentTarget, OptionalAssignmentTarget) \
+    F(OptionalBinding, OptionalBinding) \
+    F(OptionalBindingIdentifier, OptionalBindingIdentifier) \
+    F(OptionalBindingOrBindingWithInitializer, OptionalBindingOrBindingWithInitializer) \
+    F(OptionalCatchClause, OptionalCatchClause) \
+    F(OptionalExpression, OptionalExpression) \
+    F(OptionalIdentifierName, OptionalIdentifierName) \
+    F(OptionalLabel, OptionalLabel) \
+    F(OptionalSpreadElementOrExpression, OptionalSpreadElementOrExpression) \
+    F(OptionalStatement, OptionalStatement) \
+    F(OptionalVariableDeclarationOrExpression, OptionalVariableDeclarationOrExpression) \
+    F(Parameter, Parameter) \
     F(Program, Program) \
-    F(PropertyKind, PropertyKind) \
-    F(RegExpLiteral, RegExpLiteral) \
+    F(PropertyName, PropertyName) \
     F(ReturnStatement, ReturnStatement) \
-    F(SequenceExpression, SequenceExpression) \
-    F(StringLiteral, StringLiteral) \
+    F(Script, Script) \
+    F(Setter, Setter) \
+    F(ShorthandProperty, ShorthandProperty) \
+    F(SimpleAssignmentTarget, SimpleAssignmentTarget) \
+    F(SpreadElement, SpreadElement) \
+    F(SpreadElementOrExpression, SpreadElementOrExpression) \
     F(Statement, Statement) \
+    F(StaticMemberAssignmentTarget, StaticMemberAssignmentTarget) \
+    F(StaticMemberExpression, StaticMemberExpression) \
+    F(Super, Super) \
     F(SwitchCase, SwitchCase) \
+    F(SwitchDefault, SwitchDefault) \
     F(SwitchStatement, SwitchStatement) \
+    F(SwitchStatementWithDefault, SwitchStatementWithDefault) \
+    F(TemplateElement, TemplateElement) \
+    F(TemplateExpression, TemplateExpression) \
     F(ThisExpression, ThisExpression) \
     F(ThrowStatement, ThrowStatement) \
-    F(TryStatement, TryStatement) \
+    F(TryCatchStatement, TryCatchStatement) \
+    F(TryFinallyStatement, TryFinallyStatement) \
     F(UnaryExpression, UnaryExpression) \
     F(UnaryOperator, UnaryOperator) \
     F(UpdateExpression, UpdateExpression) \
     F(UpdateOperator, UpdateOperator) \
     F(VariableDeclaration, VariableDeclaration) \
+    F(VariableDeclarationKind, VariableDeclarationKind) \
+    F(VariableDeclarationOrExpression, VariableDeclarationOrExpression) \
     F(VariableDeclarator, VariableDeclarator) \
-    F(VariableKind, VariableKind) \
     F(WhileStatement, WhileStatement) \
-    F(WithStatement, WithStatement)
+    F(WithStatement, WithStatement) \
+    F(YieldExpression, YieldExpression) \
+    F(YieldStarExpression, YieldStarExpression) \
+    F(_Null, _Null) \
+    F(string, string)
+
 
 enum class BinKind {
 #define EMIT_ENUM(name, _) name,
     FOR_EACH_BIN_KIND(EMIT_ENUM)
 #undef EMIT_ENUM
-    BINKIND_LIMIT /* domain size */
 };
 
-const char* describeBinKind(const BinKind& kind);
+// The number of distinct values of BinKind.
+const size_t BINKIND_LIMIT = 171;
+
 
 /**
  * The different fields of Binary AST nodes, as per the specifications of
  * Binary AST.
  *
  * Usage:
  *
  * ```c++
  * #define WITH_FIELD(CPP_NAME, SPEC_NAME) ...
  * FOR_EACH_BIN_FIELD(WITH_FIELD)
  * ```
  *
  * (sorted by alphabetical order)
  */
- #define FOR_EACH_BIN_FIELD(F) \
+#define FOR_EACH_BIN_FIELD(F) \
     F(Alternate, alternate) \
-    F(Argument, argument) \
     F(Arguments, arguments) \
-    F(BINJS_CapturedNames, BINJS:CapturedNames) \
-    F(BINJS_ConstDeclaredNames, BINJS:ConstDeclaredNames) \
-    F(BINJS_HasDirectEval, BINJS:HasDirectEval) \
-    F(BINJS_LetDeclaredNames, BINJS:LetDeclaredNames) \
-    F(BINJS_VarDeclaredNames, BINJS:VarDeclaredNames) \
-    F(BINJS_Scope, BINJS:Scope) \
-    F(Block, block) \
+    F(Binding, binding) \
+    F(Body, body) \
+    F(BodyScope, bodyScope) \
     F(Callee, callee) \
+    F(CapturedNames, capturedNames) \
     F(Cases, cases) \
+    F(CatchClause, catchClause) \
     F(Consequent, consequent) \
-    F(Body, body) \
-    F(Declarations, declarations) \
+    F(Declaration, declaration) \
+    F(Declarators, declarators) \
+    F(DefaultBinding, defaultBinding) \
+    F(DefaultCase, defaultCase) \
     F(Directives, directives) \
     F(Discriminant, discriminant) \
     F(Elements, elements) \
+    F(ExportedName, exportedName) \
     F(Expression, expression) \
-    F(Expressions, expressions) \
     F(Finalizer, finalizer) \
     F(Flags, flags) \
-    F(Handler, handler) \
-    F(Id, id) \
+    F(HasDirectEval, hasDirectEval) \
     F(Init, init) \
-    F(Key, key) \
+    F(IsAsync, isAsync) \
+    F(IsGenerator, isGenerator) \
+    F(IsPrefix, isPrefix) \
+    F(IsStatic, isStatic) \
+    F(Items, items) \
     F(Kind, kind) \
     F(Label, label) \
     F(Left, left) \
+    F(LexicallyDeclaredNames, lexicallyDeclaredNames) \
+    F(Method, method) \
+    F(ModuleSpecifier, moduleSpecifier) \
     F(Name, name) \
+    F(NamedExports, namedExports) \
+    F(NamedImports, namedImports) \
+    F(NamespaceBinding, namespaceBinding) \
     F(Object, object) \
+    F(Operand, operand) \
     F(Operator, operator) \
     F(Param, param) \
+    F(ParameterNames, parameterNames) \
+    F(ParameterScope, parameterScope) \
     F(Params, params) \
     F(Pattern, pattern) \
-    F(Prefix, prefix) \
+    F(PostDefaultCases, postDefaultCases) \
+    F(PreDefaultCases, preDefaultCases) \
     F(Properties, properties) \
     F(Property, property) \
+    F(RawValue, rawValue) \
+    F(Rest, rest) \
     F(Right, right) \
+    F(Scope, scope) \
+    F(Statements, statements) \
+    F(Super, super) \
+    F(Tag, tag) \
     F(Test, test) \
     F(Update, update) \
-    F(Value, value)
+    F(Value, value) \
+    F(VarDeclaredNames, varDeclaredNames)
+
 
 enum class BinField {
 #define EMIT_ENUM(name, _) name,
     FOR_EACH_BIN_FIELD(EMIT_ENUM)
 #undef EMIT_ENUM
-    BINFIELD_LIMIT /* domain size */
 };
 
+// The number of distinct values of BinField.
+const size_t BINFIELD_LIMIT = 61;
+
+/**
+ * Return a string describing a `BinKind`.
+ */
+const char* describeBinKind(const BinKind& kind);
+
+/**
+ * Return a string describing a `BinField`.
+ */
 const char* describeBinField(const BinField& kind);
 
 } // namespace frontend
 } // namespace js
 
 #endif // frontend_BinToken_h
+
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -701,16 +701,17 @@ DEFINES['ENABLE_WASM_GLOBAL'] = True
 
 if CONFIG['JS_BUILD_BINAST']:
     # Using SOURCES as UNIFIED_SOURCES causes mysterious bugs on 32-bit platforms.
     # These parts of BinAST are designed only to test evolutions of the
     # specification.
     SOURCES += ['frontend/BinTokenReaderTester.cpp']
     # These parts of BinAST should eventually move to release.
     SOURCES += [
+        'frontend/BinSource-auto.cpp',
         'frontend/BinSource.cpp',
         'frontend/BinToken.cpp'
     ]
 
     # Instrument BinAST files for fuzzing as we have a fuzzing target for BinAST.
     if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
         SOURCES['frontend/BinSource.cpp'].flags += libfuzzer_flags_cmp
         SOURCES['frontend/BinToken.cpp'].flags += libfuzzer_flags_cmp