Bug 1439855 - Bunch of macros shared among BinAST files;r=arai
☠☠ backed out by ac148c181d2b ☠ ☠
authorDavid Teller <dteller@mozilla.com>
Thu, 05 Apr 2018 14:31:39 +0200
changeset 414039 6e57f703e46d1066d6607f58445c1c9295fe998f
parent 414038 e19f06ed8be932735c42db90f7dfe501dd3e6751
child 414040 bb47995e64812293236032bc57d20a7bee183d60
push id33857
push userncsoregi@mozilla.com
push dateTue, 17 Apr 2018 21:54:38 +0000
treeherdermozilla-central@1a1223d74b7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1439855
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1439855 - Bunch of macros shared among BinAST files;r=arai MozReview-Commit-ID: 6q27OFhLlc6
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource-macros.h
js/src/frontend/BinToken.h
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -12,158 +12,102 @@
 #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/BinSource-macros.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
-};
+template<typename Tok, size_t N>
+bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
+    return Tok::equals(left, right);
+}
 
 
 // ----- Sums of interfaces (autogenerated, by lexicographical order)
 // Sums of sums are flattened.
 /*
+ArrowExpression ::= EagerArrowExpression
+    SkippableArrowExpression
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArrowExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumArrowExpression(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("ArrowExpression", kind);
+    }
+    return result;
+}
+
+/*
 AssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTarget()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
         break;
       case BinKind::AssignmentTargetIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
@@ -186,34 +130,34 @@ BinASTParser::parseSumAssignmentTarget(c
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetOrAssignmentTargetWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
         break;
       case BinKind::AssignmentTargetIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
@@ -235,34 +179,34 @@ BinASTParser::parseSumAssignmentTargetOr
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetPattern()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumAssignmentTargetPattern(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
         break;
       case BinKind::ObjectAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields));
@@ -272,34 +216,34 @@ BinASTParser::parseSumAssignmentTargetPa
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::AssignmentTargetPropertyIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields));
         break;
       case BinKind::AssignmentTargetPropertyProperty:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields));
@@ -310,34 +254,34 @@ BinASTParser::parseSumAssignmentTargetPr
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayBinding:
         MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
         break;
       case BinKind::BindingIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
@@ -352,34 +296,34 @@ BinASTParser::parseSumBinding(const size
 }
 
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingOrBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayBinding:
         MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
         break;
       case BinKind::BindingIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
@@ -395,34 +339,34 @@ BinASTParser::parseSumBindingOrBindingWi
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingPattern()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumBindingPattern(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayBinding:
         MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
         break;
       case BinKind::ObjectBinding:
         MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
@@ -432,34 +376,34 @@ BinASTParser::parseSumBindingPattern(con
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::BindingPropertyIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields));
         break;
       case BinKind::BindingPropertyProperty:
         MOZ_TRY_VAR(result, parseInterfaceBindingPropertyProperty(start, kind, fields));
@@ -472,34 +416,34 @@ BinASTParser::parseSumBindingProperty(co
 
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::Export:
         MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields));
         break;
       case BinKind::ExportAllFrom:
         MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields));
@@ -516,71 +460,70 @@ BinASTParser::parseSumExportDeclaration(
       default:
         return raiseInvalidKind("ExportDeclaration", kind);
     }
     return result;
 }
 
 /*
 Expression ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -595,18 +538,21 @@ BinASTParser::parseSumExpression(const s
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -628,16 +574,22 @@ BinASTParser::parseSumExpression(const s
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
         break;
       case BinKind::ThisExpression:
         MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
@@ -657,72 +609,71 @@ BinASTParser::parseSumExpression(const s
       default:
         return raiseInvalidKind("Expression", kind);
     }
     return result;
 }
 
 /*
 ExpressionOrSuper ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExpressionOrSuper()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -737,18 +688,21 @@ BinASTParser::parseSumExpressionOrSuper(
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -770,16 +724,22 @@ BinASTParser::parseSumExpressionOrSuper(
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::Super:
         MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
@@ -802,72 +762,71 @@ BinASTParser::parseSumExpressionOrSuper(
       default:
         return raiseInvalidKind("ExpressionOrSuper", kind);
     }
     return result;
 }
 
 /*
 ExpressionOrTemplateElement ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExpressionOrTemplateElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -882,18 +841,21 @@ BinASTParser::parseSumExpressionOrTempla
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -915,16 +877,22 @@ BinASTParser::parseSumExpressionOrTempla
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateElement:
         MOZ_TRY_VAR(result, parseInterfaceTemplateElement(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
@@ -953,34 +921,34 @@ BinASTParser::parseSumExpressionOrTempla
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields));
         break;
       case BinKind::AssignmentTargetIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
@@ -1000,72 +968,71 @@ BinASTParser::parseSumForInOfBindingOrAs
       default:
         return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
     }
     return result;
 }
 
 /*
 FunctionBodyOrExpression ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     FunctionBody
-    FunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionBodyOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumFunctionBodyOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -1080,22 +1047,25 @@ BinASTParser::parseSumFunctionBodyOrExpr
         MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields));
         break;
       case BinKind::ComputedMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields));
         break;
       case BinKind::ConditionalExpression:
         MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields));
         break;
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
+        break;
       case BinKind::FunctionBody:
         MOZ_TRY_VAR(result, parseInterfaceFunctionBody(start, kind, fields));
         break;
-      case BinKind::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));
@@ -1116,16 +1086,22 @@ BinASTParser::parseSumFunctionBodyOrExpr
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
         break;
       case BinKind::ThisExpression:
         MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
@@ -1144,74 +1120,111 @@ BinASTParser::parseSumFunctionBodyOrExpr
         break;
       default:
         return raiseInvalidKind("FunctionBodyOrExpression", kind);
     }
     return result;
 }
 
 /*
+FunctionDeclaration ::= EagerFunctionDeclaration
+    SkippableFunctionDeclaration
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumFunctionDeclaration(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("FunctionDeclaration", kind);
+    }
+    return result;
+}
+
+/*
 FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassDeclaration
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionDeclaration
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionDeclaration
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionDeclaration
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionDeclarationOrClassDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -1229,21 +1242,24 @@ BinASTParser::parseSumFunctionDeclaratio
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -1265,16 +1281,25 @@ BinASTParser::parseSumFunctionDeclaratio
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
         break;
       case BinKind::ThisExpression:
         MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
@@ -1294,77 +1319,155 @@ BinASTParser::parseSumFunctionDeclaratio
       default:
         return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrExpression", kind);
     }
     return result;
 }
 
 /*
 FunctionDeclarationOrClassDeclarationOrVariableDeclaration ::= ClassDeclaration
-    FunctionDeclaration
+    EagerFunctionDeclaration
+    SkippableFunctionDeclaration
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ClassDeclaration:
         MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
         break;
-      case BinKind::FunctionDeclaration:
-        MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields));
+      case BinKind::EagerFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
         break;
       case BinKind::VariableDeclaration:
         MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields));
         break;
       default:
         return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrVariableDeclaration", kind);
     }
     return result;
 }
 
 /*
+FunctionExpression ::= EagerFunctionExpression
+    SkippableFunctionExpression
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumFunctionExpression(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("FunctionExpression", kind);
+    }
+    return result;
+}
+
+/*
+Getter ::= EagerGetter
+    SkippableGetter
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseGetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumGetter(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumGetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerGetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
+        break;
+      case BinKind::SkippableGetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("Getter", kind);
+    }
+    return result;
+}
+
+/*
 ImportDeclaration ::= Import
     ImportNamespace
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImportDeclaration()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseImportDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::Import:
         MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields));
         break;
       case BinKind::ImportNamespace:
         MOZ_TRY_VAR(result, parseInterfaceImportNamespace(start, kind, fields));
@@ -1377,59 +1480,60 @@ BinASTParser::parseSumImportDeclaration(
 
 /*
 ImportDeclarationOrExportDeclarationOrStatement ::= Block
     BreakStatement
     ClassDeclaration
     ContinueStatement
     DebuggerStatement
     DoWhileStatement
+    EagerFunctionDeclaration
     EmptyStatement
     Export
     ExportAllFrom
     ExportDefault
     ExportFrom
     ExportLocals
     ExpressionStatement
     ForInStatement
     ForOfStatement
     ForStatement
-    FunctionDeclaration
     IfStatement
     Import
     ImportNamespace
     LabelledStatement
     ReturnStatement
+    SkippableFunctionDeclaration
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseImportDeclarationOrExportDeclarationOrStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::Block:
         MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
         break;
       case BinKind::BreakStatement:
         MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
@@ -1441,16 +1545,19 @@ BinASTParser::parseSumImportDeclarationO
         MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
         break;
       case BinKind::DebuggerStatement:
         MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
         break;
       case BinKind::DoWhileStatement:
         MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
         break;
+      case BinKind::EagerFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+        break;
       case BinKind::EmptyStatement:
         MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
         break;
       case BinKind::Export:
         MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields));
         break;
       case BinKind::ExportAllFrom:
         MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields));
@@ -1471,34 +1578,34 @@ BinASTParser::parseSumImportDeclarationO
         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::SkippableFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
+        break;
       case BinKind::SwitchStatement:
         MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
         break;
       case BinKind::SwitchStatementWithDefault:
         MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields));
         break;
       case BinKind::ThrowStatement:
         MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
@@ -1526,34 +1633,34 @@ BinASTParser::parseSumImportDeclarationO
 
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseIterationStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::DoWhileStatement:
         MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
         break;
       case BinKind::ForInStatement:
         MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
@@ -1575,34 +1682,34 @@ BinASTParser::parseSumIterationStatement
 
 /*
 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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteral()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
@@ -1618,129 +1725,190 @@ BinASTParser::parseSumLiteral(const size
         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)
+Method ::= EagerMethod
+    SkippableMethod
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseMethod()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumMethod(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumMethod(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
-      case BinKind::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));
+      case BinKind::EagerMethod:
+        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
+        break;
+      case BinKind::SkippableMethod:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("Method", kind);
+    }
+    return result;
+}
+
+/*
+MethodDefinition ::= EagerGetter
+    EagerMethod
+    EagerSetter
+    SkippableGetter
+    SkippableMethod
+    SkippableSetter
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseMethodDefinition()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumMethodDefinition(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerGetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
+        break;
+      case BinKind::EagerMethod:
+        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
+        break;
+      case BinKind::EagerSetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
+        break;
+      case BinKind::SkippableGetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(start, kind, fields));
+        break;
+      case BinKind::SkippableMethod:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
+        break;
+      case BinKind::SkippableSetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(start, kind, fields));
         break;
       default:
         return raiseInvalidKind("MethodDefinition", kind);
     }
     return result;
 }
 
 /*
 ObjectProperty ::= DataProperty
-    Getter
-    Method
-    Setter
+    EagerGetter
+    EagerMethod
+    EagerSetter
     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));
+    SkippableGetter
+    SkippableMethod
+    SkippableSetter
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseObjectProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::DataProperty:
         MOZ_TRY_VAR(result, parseInterfaceDataProperty(start, kind, fields));
         break;
-      case BinKind::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));
+      case BinKind::EagerGetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
+        break;
+      case BinKind::EagerMethod:
+        MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
+        break;
+      case BinKind::EagerSetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
         break;
       case BinKind::ShorthandProperty:
         MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
         break;
+      case BinKind::SkippableGetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableGetter(start, kind, fields));
+        break;
+      case BinKind::SkippableMethod:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableMethod(start, kind, fields));
+        break;
+      case BinKind::SkippableSetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(start, kind, fields));
+        break;
       default:
         return raiseInvalidKind("ObjectProperty", kind);
     }
     return result;
 }
 
 /*
 Parameter ::= ArrayBinding
     BindingIdentifier
     BindingWithInitializer
     ObjectBinding
 */
-JS::Result<ParseNode*>
-BinASTParser::parseParameter()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseParameter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayBinding:
         MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
         break;
       case BinKind::BindingIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
@@ -1756,34 +1924,34 @@ BinASTParser::parseSumParameter(const si
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseProgram()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::Module:
         MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields));
         break;
       case BinKind::Script:
         MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields));
@@ -1793,72 +1961,109 @@ BinASTParser::parseSumProgram(const size
     }
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parsePropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ComputedPropertyName:
         MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind, fields));
         break;
       case BinKind::LiteralPropertyName:
         MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields));
         break;
       default:
         return raiseInvalidKind("PropertyName", kind);
     }
     return result;
 }
 
 /*
+Setter ::= EagerSetter
+    SkippableSetter
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+
+    MOZ_TRY_DECL(result, parseSumSetter(start, kind, fields));
+
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumSetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    ParseNode* result;
+    switch(kind) {
+      case BinKind::EagerSetter:
+        MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
+        break;
+      case BinKind::SkippableSetter:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableSetter(start, kind, fields));
+        break;
+      default:
+        return raiseInvalidKind("Setter", kind);
+    }
+    return result;
+}
+
+/*
 SimpleAssignmentTarget ::= AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSimpleAssignmentTarget()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-    const auto start = tokenizer_->offset();
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSimpleAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::AssignmentTargetIdentifier:
         MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields));
         break;
       case BinKind::ComputedMemberAssignmentTarget:
         MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields));
@@ -1869,72 +2074,71 @@ BinASTParser::parseSumSimpleAssignmentTa
       default:
         return raiseInvalidKind("SimpleAssignmentTarget", kind);
     }
     return result;
 }
 
 /*
 SpreadElementOrExpression ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSpreadElementOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -1949,18 +2153,21 @@ BinASTParser::parseSumSpreadElementOrExp
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -1982,16 +2189,22 @@ BinASTParser::parseSumSpreadElementOrExp
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::SpreadElement:
         MOZ_TRY_VAR(result, parseInterfaceSpreadElement(start, kind, fields));
         break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
@@ -2019,52 +2232,53 @@ BinASTParser::parseSumSpreadElementOrExp
 
 /*
 Statement ::= Block
     BreakStatement
     ClassDeclaration
     ContinueStatement
     DebuggerStatement
     DoWhileStatement
+    EagerFunctionDeclaration
     EmptyStatement
     ExpressionStatement
     ForInStatement
     ForOfStatement
     ForStatement
-    FunctionDeclaration
     IfStatement
     LabelledStatement
     ReturnStatement
+    SkippableFunctionDeclaration
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::Block:
         MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
         break;
       case BinKind::BreakStatement:
         MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
@@ -2076,43 +2290,46 @@ BinASTParser::parseSumStatement(const si
         MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
         break;
       case BinKind::DebuggerStatement:
         MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
         break;
       case BinKind::DoWhileStatement:
         MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
         break;
+      case BinKind::EagerFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+        break;
       case BinKind::EmptyStatement:
         MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
         break;
       case BinKind::ExpressionStatement:
         MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields));
         break;
       case BinKind::ForInStatement:
         MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
         break;
       case BinKind::ForOfStatement:
         MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields));
         break;
       case BinKind::ForStatement:
         MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields));
         break;
-      case BinKind::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::SkippableFunctionDeclaration:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
+        break;
       case BinKind::SwitchStatement:
         MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
         break;
       case BinKind::SwitchStatementWithDefault:
         MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields));
         break;
       case BinKind::ThrowStatement:
         MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
@@ -2135,72 +2352,71 @@ BinASTParser::parseSumStatement(const si
       default:
         return raiseInvalidKind("Statement", kind);
     }
     return result;
 }
 
 /*
 VariableDeclarationOrExpression ::= ArrayExpression
-    ArrowExpression
     AssignmentExpression
     AwaitExpression
     BinaryExpression
     CallExpression
     ClassExpression
     CompoundAssignmentExpression
     ComputedMemberExpression
     ConditionalExpression
-    FunctionExpression
+    EagerArrowExpression
+    EagerFunctionExpression
     IdentifierExpression
     LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralRegExpExpression
     LiteralStringExpression
     NewExpression
     NewTargetExpression
     ObjectExpression
+    SkippableArrowExpression
+    SkippableFunctionExpression
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseVariableDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
 
     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)
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     ParseNode* result;
     switch(kind) {
       case BinKind::ArrayExpression:
         MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
         break;
-      case BinKind::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));
@@ -2215,18 +2431,21 @@ BinASTParser::parseSumVariableDeclaratio
         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));
+      case BinKind::EagerArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+        break;
+      case BinKind::EagerFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
         break;
       case BinKind::IdentifierExpression:
         MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields));
         break;
       case BinKind::LiteralBooleanExpression:
         MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
         break;
       case BinKind::LiteralInfinityExpression:
@@ -2248,16 +2467,22 @@ BinASTParser::parseSumVariableDeclaratio
         MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
         break;
       case BinKind::NewTargetExpression:
         MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields));
         break;
       case BinKind::ObjectExpression:
         MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
         break;
+      case BinKind::SkippableArrowExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+        break;
+      case BinKind::SkippableFunctionExpression:
+        MOZ_TRY_VAR(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+        break;
       case BinKind::StaticMemberExpression:
         MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields));
         break;
       case BinKind::TemplateExpression:
         MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields));
         break;
       case BinKind::ThisExpression:
         MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
@@ -2284,524 +2509,525 @@ BinASTParser::parseSumVariableDeclaratio
 }
 
 
 
 // ----- Interfaces (autogenerated, by lexicographical order)
 // When fields have a non-trivial type, implementation is deanonymized and delegated to another parser.
 
 /*
+ interface  : Node {
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseNull()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceNull(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Null)");
+}
+
+
+/*
  interface ArrayAssignmentTarget : Node {
     FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer)> elements;
     AssignmentTarget? rest;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseArrayAssignmentTarget()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArrayAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ArrayAssignmentTarget)");
 }
 
 
 /*
  interface ArrayBinding : Node {
     FrozenArray<(Binding or BindingWithInitializer)?> elements;
     Binding? rest;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseArrayBinding()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArrayBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ArrayBinding)");
 }
 
 
 /*
  interface ArrayExpression : Node {
     FrozenArray<(SpreadElement or Expression)?> elements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseArrayExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArrayExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ArrayExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Elements }));
+    MOZ_TRY(tokenizer_->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)");
+    auto result = elements;
+    return result;
 }
 
 
 /*
  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));
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseAssertedBlockScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedBlockScope);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
     MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
     MOZ_TRY(parseAndUpdateCapturedNames());
 
 
 
-    MOZ_TRY_DECL(hasDirectEval, readBool());
+    MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
 
     if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
         // In non-strict mode code, direct calls to eval can
         // add variables to the call object.
         parseContext_->functionBox()->setHasExtensibleScope();
     }
-    auto result = Ok();return result;
+    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));
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseAssertedParameterScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedParameterScope);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval }));
     MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter));
     MOZ_TRY(parseAndUpdateCapturedNames());
 
 
 
-    MOZ_TRY_DECL(hasDirectEval, readBool());
+    MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
 
     if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
         // In non-strict mode code, direct calls to eval can
         // add variables to the call object.
         parseContext_->functionBox()->setHasExtensibleScope();
     }
-    auto result = Ok();return result;
+    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));
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseAssertedVarScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedVarScope);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::VarDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
+    MOZ_TRY(tokenizer_->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());
+    MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
     if (hasDirectEval) {
         parseContext_->sc()->setHasDirectEval();
         parseContext_->sc()->setBindingsAccessedDynamically();
     }
 
     if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) {
         // In non-strict mode code, direct calls to eval can
         // add variables to the call object.
         parseContext_->functionBox()->setHasExtensibleScope();
     }
-    auto result = Ok();return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssignmentExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Expression }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
 
     RootedAtom name(cx_);
-    MOZ_TRY(readString(&name));
+    MOZ_TRY_VAR(name, tokenizer_->readAtom());
 
 
     if (!IsIdentifier(name))
         return raiseError("Invalid identifier");
-    TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetPropertyIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (AssignmentTargetPropertyIdentifier)");
 }
 
 
 /*
  interface AssignmentTargetPropertyProperty : Node {
     PropertyName name;
     (AssignmentTarget or AssignmentTargetWithInitializer) binding;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetPropertyProperty()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetPropertyProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (AssignmentTargetPropertyProperty)");
 }
 
 
 /*
  interface AssignmentTargetWithInitializer : Node {
     AssignmentTarget binding;
     Expression init;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetWithInitializer()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAssignmentTargetWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (AssignmentTargetWithInitializer)");
 }
 
 
 /*
  interface AwaitExpression : Node {
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAwaitExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAwaitExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (AwaitExpression)");
 }
 
 
 /*
  interface BinaryExpression : Node {
     BinaryOperator operator;
     Expression left;
     Expression right;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBinaryExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBinaryExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BinaryExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Left, BinField::Right }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Left, BinField::Right }));
 
 
 
     MOZ_TRY_DECL(operator_, parseBinaryOperator());
 
 
 
 
@@ -2900,171 +3126,173 @@ BinASTParser::parseInterfaceBinaryExpres
         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;
+    }
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BindingIdentifier);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
 
     RootedAtom name(cx_);
-    MOZ_TRY(readString(&name));
+    MOZ_TRY_VAR(name, tokenizer_->readAtom());
 
 
     if (!IsIdentifier(name))
         return raiseError("Invalid identifier");
-    TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingPropertyIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (BindingPropertyIdentifier)");
 }
 
 
 /*
  interface BindingPropertyProperty : Node {
     PropertyName name;
     (Binding or BindingWithInitializer) binding;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingPropertyProperty()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingPropertyProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (BindingPropertyProperty)");
 }
 
 
 /*
  interface BindingWithInitializer : Node {
     Binding binding;
     Expression init;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingWithInitializer()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (BindingWithInitializer)");
 }
 
 
 /*
  interface Block : Node {
     AssertedBlockScope? scope;
     FrozenArray<Statement> statements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBlock()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBlock()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Block);
     CheckRecursionLimit(cx_);
 
     MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Statements }));
     ParseContext::Statement stmt(parseContext_, StatementKind::Block);
     ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
     TRY(currentScope.init(parseContext_));
@@ -3084,90 +3312,91 @@ BinASTParser::parseInterfaceBlock(const 
 }
 
 
 /*
  interface BreakStatement : Node {
     Label? label;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBreakStatement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseBreakStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BreakStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Label }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Label }));
     RootedAtom label(cx_);
-    MOZ_TRY(readMaybeString(&label));
-
-    if (label && !IsIdentifier(label))
-        return raiseError("Invalid identifier");
+    MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
 
     if (label) {
+        if (!IsIdentifier(label))
+            return raiseError("Invalid identifier");
+
         auto validity = parseContext_->checkBreakStatement(label->asPropertyName());
 
         if (validity.isErr()) {
             switch (validity.unwrapErr()) {
             case ParseContext::BreakStatementError::ToughBreak:
                 return raiseError(kind, "Not in a loop");
             case ParseContext::BreakStatementError::LabelNotFound:
                 return raiseError(kind, "Label not found");
             }
         }
     }
-    TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseCallExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CallExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
 
 
 
     MOZ_TRY_DECL(callee, parseExpressionOrSuper());
 
 
 
 
@@ -3184,193 +3413,201 @@ BinASTParser::parseInterfaceCallExpressi
                 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;
+    result->setOp(op);
+    return result;
 }
 
 
 /*
  interface CatchClause : Node {
+    AssertedParameterScope? bindingScope;
     Binding binding;
     Block body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseCatchClause()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseCatchClause()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CatchClause);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Body }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::BindingScope, BinField::Binding, BinField::Body }));
     ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
     ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
     TRY(currentScope.init(parseContext_));
 
 
+    MOZ_TRY(parseOptionalAssertedParameterScope());
+
+
+
+
     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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseClassDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ClassDeclaration)");
 }
 
 
 /*
  interface ClassElement : Node {
     bool isStatic;
     MethodDefinition method;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseClassElement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseClassElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ClassElement)");
 }
 
 
 /*
  interface ClassExpression : Node {
     BindingIdentifier? name;
     Expression? super;
     FrozenArray<ClassElement> elements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseClassExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseClassExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ClassExpression)");
 }
 
 
 /*
  interface CompoundAssignmentExpression : Node {
     CompoundAssignmentOperator operator;
     SimpleAssignmentTarget binding;
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseCompoundAssignmentExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseCompoundAssignmentExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CompoundAssignmentExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Binding, BinField::Expression }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Binding, BinField::Expression }));
 
 
 
     MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());
 
 
 
 
@@ -3416,1098 +3653,510 @@ BinASTParser::parseInterfaceCompoundAssi
         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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseComputedMemberAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ComputedMemberAssignmentTarget);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseComputedMemberExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ComputedMemberExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseComputedPropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ComputedPropertyName)");
 }
 
 
 /*
  interface ConditionalExpression : Node {
     Expression test;
     Expression consequent;
     Expression alternate;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseConditionalExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseConditionalExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ConditionalExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseContinueStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ContinueStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Label }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Label }));
     RootedAtom label(cx_);
-    MOZ_TRY(readMaybeString(&label));
-
-    if (label && !IsIdentifier(label))
-        return raiseError("ContinueStatement - Label MUST be an identifier");
+    MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
 
     if (label) {
+        if (!IsIdentifier(label))
+            return raiseError("ContinueStatement - Label MUST be an identifier");
+
         auto validity = parseContext_->checkContinueStatement(label ? label->asPropertyName() : nullptr);
         if (validity.isErr()) {
             switch (validity.unwrapErr()) {
               case ParseContext::ContinueStatementError::NotInALoop:
                 return raiseError(kind, "Not in a loop");
               case ParseContext::ContinueStatementError::LabelNotFound:
                 return raiseError(kind, "Label not found");
             }
         }
     }
 
-    TRY_DECL(result, factory_.newContinueStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseDataProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::DataProperty);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Name, BinField::Expression }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseDebuggerStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (DebuggerStatement)");
 }
 
 
 /*
  interface Directive : Node {
     string rawValue;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseDirective()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseDirective()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Directive);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::RawValue }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::RawValue }));
 
 
     RootedAtom rawValue(cx_);
-    MOZ_TRY(readString(&rawValue));
+    MOZ_TRY_VAR(rawValue, tokenizer_->readAtom());
 
 
     TokenPos pos = tokenizer_->pos(start);
-    TRY_DECL(result, factory_.newStringLiteral(rawValue, pos));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseDoWhileStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::DoWhileStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body }));
+    MOZ_TRY(tokenizer_->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;
+    TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
+    return result;
+}
+
+
+/*
+ interface EagerArrowExpression : Node {
+    bool isAsync;
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    FormalParameters params;
+    (FunctionBody or Expression) body;
  }
 */
-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 {
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerArrowExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerArrowExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (EagerArrowExpression)");
+}
+
+
+/*
+ interface EagerFunctionDeclaration : Node {
     bool isAsync;
     bool isGenerator;
     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 {
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerFunctionDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (EagerFunctionDeclaration)");
+}
+
+
+/*
+ interface EagerFunctionExpression : 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);
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerFunctionExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerFunctionExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::EagerFunctionExpression);
     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(tokenizer_->checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+
+
+
+
+    MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
 
 
     MOZ_TRY_DECL(funbox, buildFunctionBox(
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction));
 
@@ -4540,598 +4189,94 @@ BinASTParser::parseInterfaceFunctionExpr
 
 
 
     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 {
+    MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));
+    return result;
+}
+
+
+/*
+ interface EagerGetter : 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 {
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerGetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerGetter(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerGetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (EagerGetter)");
+}
+
+
+/*
+ interface EagerMethod : 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);
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerMethod()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerMethod(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerMethod(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::EagerMethod);
     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(tokenizer_->checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
+
+
+
+    MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+
+
+
+
+    MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
 
 
     MOZ_TRY_DECL(funbox, buildFunctionBox(
         isGenerator ? GeneratorKind::Generator
                     : GeneratorKind::NotGenerator,
         isAsync ? FunctionAsyncKind::AsyncFunction
                 : FunctionAsyncKind::SyncFunction));
 
@@ -5163,730 +4308,1958 @@ BinASTParser::parseInterfaceMethod(const
 
 
 
 
     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;
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None));
+    return result;
+}
+
+
+/*
+ interface EagerSetter : Node {
+    AssertedParameterScope? parameterScope;
+    AssertedVarScope? bodyScope;
+    PropertyName name;
+    Parameter param;
+    FunctionBody body;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEagerSetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEagerSetter(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEagerSetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (EagerSetter)");
+}
+
+
+/*
+ interface EmptyStatement : Node {
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseEmptyStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceEmptyStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::EmptyStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields0(kind, fields));
+
+    TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));
+    return result;
+}
+
+
+/*
+ interface Export : Node {
+    (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExport()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExport(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Export)");
+}
+
+
+/*
+ interface ExportAllFrom : Node {
+    string moduleSpecifier;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportAllFrom()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportAllFrom(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportAllFrom)");
+}
+
+
+/*
+ interface ExportDefault : Node {
+    (FunctionDeclaration or ClassDeclaration or Expression) body;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportDefault(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportDefault)");
+}
+
+
+/*
+ interface ExportFrom : Node {
+    FrozenArray<ExportFromSpecifier> namedExports;
+    string moduleSpecifier;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportFrom()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportFrom(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportFrom)");
+}
+
+
+/*
+ interface ExportFromSpecifier : Node {
+    IdentifierName name;
+    IdentifierName? exportedName;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportFromSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportFromSpecifier(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportFromSpecifier)");
+}
+
+
+/*
+ interface ExportLocalSpecifier : Node {
+    IdentifierExpression name;
+    IdentifierName? exportedName;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportLocalSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportLocalSpecifier(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportLocalSpecifier)");
+}
+
+
+/*
+ interface ExportLocals : Node {
+    FrozenArray<ExportLocalSpecifier> namedExports;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExportLocals()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExportLocals(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ExportLocals)");
+}
+
+
+/*
+ interface ExpressionStatement : Node {
+    Expression expression;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseExpressionStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceExpressionStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ExpressionStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseForInOfBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForInOfBinding(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForInOfBinding);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseForInStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForInStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForInStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseForOfStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForOfStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ForOfStatement)");
+}
+
+
+/*
+ interface ForStatement : Node {
+    (VariableDeclaration or Expression)? init;
+    Expression? test;
+    Expression? update;
+    Statement body;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseForStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceForStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::ForStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFormalParameters()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFormalParameters(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FormalParameters);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionBody()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceFunctionBody(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::FunctionBody);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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 IdentifierExpression : Node {
+    Identifier name;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseIdentifierExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceIdentifierExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::IdentifierExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
+
+
+    RootedAtom name(cx_);
+    MOZ_TRY_VAR(name, tokenizer_->readAtom());
+
+
+    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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseIfStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceIfStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::IfStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseImport()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImport(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (Import)");
+}
+
+
+/*
+ interface ImportNamespace : Node {
+    string moduleSpecifier;
+    BindingIdentifier? defaultBinding;
+    BindingIdentifier namespaceBinding;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseImportNamespace()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImportNamespace(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ImportNamespace)");
+}
+
+
+/*
+ interface ImportSpecifier : Node {
+    IdentifierName? name;
+    BindingIdentifier binding;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseImportSpecifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceImportSpecifier(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (ImportSpecifier)");
+}
+
+
+/*
+ interface LabelledStatement : Node {
+    Label label;
+    Statement body;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLabelledStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLabelledStatement(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LabelledStatement);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Label, BinField::Body }));
+
+
+    RootedAtom label(cx_);
+    MOZ_TRY_VAR(label, tokenizer_->readAtom());
+    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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralBooleanExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralBooleanExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralBooleanExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
+
+
+
+    MOZ_TRY_DECL(value, tokenizer_->readBool());
+
+
+    TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start)));
+    return result;
+}
+
+
+/*
+ interface LiteralInfinityExpression : Node {
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralInfinityExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralInfinityExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (LiteralInfinityExpression)");
+}
+
+
+/*
+ interface LiteralNullExpression : Node {
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralNullExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralNullExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralNullExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields0(kind, fields));
+
+    TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));
+    return result;
+}
+
+
+/*
+ interface LiteralNumericExpression : Node {
+    number value;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralNumericExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralNumericExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralNumericExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
+
+
+
+    MOZ_TRY_DECL(value, tokenizer_->readDouble());
+
+
+    TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));
+    return result;
+}
+
+
+/*
+ interface LiteralPropertyName : Node {
+    string value;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralPropertyName()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralPropertyName(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralPropertyName);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
+
+
+    RootedAtom value(cx_);
+    MOZ_TRY_VAR(value, tokenizer_->readAtom());
+
+
+    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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralRegExpExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralRegExpExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralRegExpExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Pattern, BinField::Flags }));
+
+
+    RootedAtom pattern(cx_);
+    MOZ_TRY_VAR(pattern, tokenizer_->readAtom());
+
+    Chars flags(cx_);
+    MOZ_TRY(tokenizer_->readChars(flags));
+
+    RegExpFlag reflags = NoFlags;
+    for (auto c : flags) {
+        if (c == 'g' && !(reflags & GlobalFlag))
+            reflags = RegExpFlag(reflags | GlobalFlag);
+        else if (c == 'i' && !(reflags & IgnoreCaseFlag))
+            reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+        else if (c == 'm' && !(reflags & MultilineFlag))
+            reflags = RegExpFlag(reflags | MultilineFlag);
+        else if (c == 'y' && !(reflags & StickyFlag))
+            reflags = RegExpFlag(reflags | StickyFlag);
+        else if (c == 'u' && !(reflags & UnicodeFlag))
+            reflags = RegExpFlag(reflags | UnicodeFlag);
+        else
+            return raiseError("Invalid regexp flags");
+    }
+
+
+    Rooted<RegExpObject*> reobj(cx_);
+    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;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseLiteralStringExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceLiteralStringExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    MOZ_ASSERT(kind == BinKind::LiteralStringExpression);
+    CheckRecursionLimit(cx_);
+
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
+
+
+    RootedAtom value(cx_);
+    MOZ_TRY_VAR(value, tokenizer_->readAtom());
+
+
+    TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseModule()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseNewExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseNewTargetExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseObjectAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseObjectBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseObjectExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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(tokenizer_->checkFields(kind, fields, { BinField::Properties }));
 
 
 
     MOZ_TRY_DECL(properties, parseListOfObjectProperty());
 
 
-    auto result = properties;return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseReturnStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ReturnStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Expression }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseScript()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Script);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Directives, BinField::Statements }));
+    MOZ_TRY(tokenizer_->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;
+    MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseShorthandProperty()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ShorthandProperty);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Name }));
+    MOZ_TRY(tokenizer_->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;
+    TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, name, AccessorType::None));
+    return result;
+}
+
+
+/*
+ interface SkippableArrowExpression : Node {
+    EagerArrowExpression skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableArrowExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableArrowExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableArrowExpression)");
+}
+
+
+/*
+ interface SkippableFunctionDeclaration : Node {
+    EagerFunctionDeclaration skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableFunctionDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableFunctionDeclaration(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableFunctionDeclaration)");
+}
+
+
+/*
+ interface SkippableFunctionExpression : Node {
+    EagerFunctionExpression skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableFunctionExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableFunctionExpression(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableFunctionExpression)");
+}
+
+
+/*
+ interface SkippableGetter : Node {
+    EagerGetter skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableGetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableGetter(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableGetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableGetter)");
+}
+
+
+/*
+ interface SkippableMethod : Node {
+    EagerMethod skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableMethod()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableMethod(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableMethod(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableMethod)");
+}
+
+
+/*
+ interface SkippableSetter : Node {
+    EagerSetter skipped;
+ }
+*/
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSkippableSetter()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    const auto start = tokenizer_->offset();
+
+    MOZ_TRY_DECL(result, parseInterfaceSkippableSetter(start, kind, fields));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSkippableSetter(const size_t start, const BinKind kind, const BinFields& fields)
+{
+    return raiseError("FIXME: Not implemented yet (SkippableSetter)");
 }
 
 
 /*
  interface SpreadElement : Node {
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSpreadElement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSpreadElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseStaticMemberAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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(tokenizer_->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;
+    MOZ_TRY_VAR(property, tokenizer_->readAtom());
+
+
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseStaticMemberExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Property }));
+    MOZ_TRY(tokenizer_->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;
+    MOZ_TRY_VAR(property, tokenizer_->readAtom());
+
+
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSuper()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSwitchCase()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSwitchDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchDefault);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Consequent }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Consequent }));
 
 
 
     MOZ_TRY_DECL(consequent, parseListOfStatement());
 
 
-    TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSwitchStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::Cases }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSwitchStatementWithDefault()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchStatementWithDefault);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases }));
 
 
 
     MOZ_TRY_DECL(discriminant, parseExpression());
 
 
 
 
@@ -5908,233 +6281,237 @@ BinASTParser::parseInterfaceSwitchStatem
     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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseTemplateElement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseTemplateExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (TemplateExpression)");
 }
 
 
 /*
  interface ThisExpression : Node {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseThisExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseThisExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ThisExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields0(kind, fields));
+    MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
     if (parseContext_->isFunctionBox())
         parseContext_->functionBox()->usesThis = true;
 
     TokenPos pos = tokenizer_->pos(start);
     ParseNode* thisName(nullptr);
     if (parseContext_->sc()->thisBinding() == ThisBinding::Function)
         TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_));
 
-    TRY_DECL(result, factory_.newThisLiteral(pos, thisName));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseThrowStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ThrowStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Expression }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Expression }));
 
 
 
     MOZ_TRY_DECL(expression, parseExpression());
 
 
-    TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseTryCatchStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::TryCatchStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseTryFinallyStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::TryFinallyStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause, BinField::Finalizer }));
+    MOZ_TRY(tokenizer_->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());
 
@@ -6149,49 +6526,50 @@ BinASTParser::parseInterfaceTryFinallySt
     {
         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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseUnaryExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::UnaryExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Operand }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Operand }));
 
 
 
     MOZ_TRY_DECL(operator_, parseUnaryOperator());
 
 
 
 
@@ -6235,54 +6613,55 @@ BinASTParser::parseInterfaceUnaryExpress
             pnk = ParseNodeKind::DeleteElem;
             break;
           default:
             pnk = ParseNodeKind::DeleteExpr;
         }
         break;
       }
     }
-    TRY_DECL(result, factory_.newUnary(pnk, start, operand));return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseUpdateExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::UpdateExpression);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::IsPrefix, BinField::Operator, BinField::Operand }));
-
-
-
-    MOZ_TRY_DECL(isPrefix, readBool());
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::IsPrefix, BinField::Operator, BinField::Operand }));
+
+
+
+    MOZ_TRY_DECL(isPrefix, tokenizer_->readBool());
 
 
 
 
     MOZ_TRY_DECL(operator_, parseUpdateOperator());
 
 
 
@@ -6296,49 +6675,50 @@ BinASTParser::parseInterfaceUpdateExpres
         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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseVariableDeclaration()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::VariableDeclaration);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Kind, BinField::Declarators }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Kind, BinField::Declarators }));
     AutoVariableDeclarationKind kindGuard(this);
 
 
     MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
     // Restored by `kindGuard`.
     variableDeclarationKind_ = kind_;
 
 
@@ -6358,49 +6738,50 @@ BinASTParser::parseInterfaceVariableDecl
       case VariableDeclarationKind::Let:
         pnk = ParseNodeKind::Let;
         break;
       case VariableDeclarationKind::Const:
         pnk = ParseNodeKind::Const;
         break;
     }
     declarators->setKind(pnk);
-    auto result = declarators;return result;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseVariableDeclarator()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::VariableDeclarator);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Init }));
+    MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Binding, BinField::Init }));
 
 
 
     MOZ_TRY_DECL(binding, parseBinding());
 
 
 
 
@@ -6419,191 +6800,167 @@ BinASTParser::parseInterfaceVariableDecl
         // `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;
+    }
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseWhileStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::WhileStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseWithStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::WithStatement);
     CheckRecursionLimit(cx_);
 
-    MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Body }));
+    MOZ_TRY(tokenizer_->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;
+    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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseYieldExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseYieldStarExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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)
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (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 {
     ",",
     "||",
     "&&",
     "|",
@@ -6625,75 +6982,75 @@ enum BinaryOperator {
     "+",
     "-",
     "*",
     "/",
     "%",
     "**"
 };
 */
-JS::Result<BinASTParser::BinaryOperator>
-BinASTParser::parseBinaryOperator()
-{
-    // Unoptimized implementation.
-    Chars chars(cx_);
-    MOZ_TRY(readString(chars));
-
-    if (chars == ",")
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::BinaryOperator>
+BinASTParser<Tok>::parseBinaryOperator()
+{
+    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+
+    switch (variant) {
+    case BinVariant::BinaryOperatorComma:
         return BinaryOperator::Comma;
-    if (chars == "||")
+    case BinVariant::BinaryOperatorLogicalOr:
         return BinaryOperator::LogicalOr;
-    if (chars == "&&")
+    case BinVariant::BinaryOperatorLogicalAnd:
         return BinaryOperator::LogicalAnd;
-    if (chars == "|")
+    case BinVariant::BinaryOperatorBitOr:
         return BinaryOperator::BitOr;
-    if (chars == "^")
+    case BinVariant::BinaryOperatorBitXor:
         return BinaryOperator::BitXor;
-    if (chars == "&")
+    case BinVariant::BinaryOperatorBitAnd:
         return BinaryOperator::BitAnd;
-    if (chars == "==")
+    case BinVariant::BinaryOperatorEq:
         return BinaryOperator::Eq;
-    if (chars == "!=")
+    case BinVariant::BinaryOperatorNeq:
         return BinaryOperator::Neq;
-    if (chars == "===")
+    case BinVariant::BinaryOperatorStrictEq:
         return BinaryOperator::StrictEq;
-    if (chars == "!==")
+    case BinVariant::BinaryOperatorStrictNeq:
         return BinaryOperator::StrictNeq;
-    if (chars == "<")
+    case BinVariant::BinaryOperatorLessThan:
         return BinaryOperator::LessThan;
-    if (chars == "<=")
+    case BinVariant::BinaryOperatorLeqThan:
         return BinaryOperator::LeqThan;
-    if (chars == ">")
+    case BinVariant::BinaryOperatorGreaterThan:
         return BinaryOperator::GreaterThan;
-    if (chars == ">=")
+    case BinVariant::BinaryOperatorGeqThan:
         return BinaryOperator::GeqThan;
-    if (chars == "in")
+    case BinVariant::BinaryOperatorIn:
         return BinaryOperator::In;
-    if (chars == "instanceof")
+    case BinVariant::BinaryOperatorInstanceof:
         return BinaryOperator::Instanceof;
-    if (chars == "<<")
+    case BinVariant::BinaryOperatorLsh:
         return BinaryOperator::Lsh;
-    if (chars == ">>")
+    case BinVariant::BinaryOperatorRsh:
         return BinaryOperator::Rsh;
-    if (chars == ">>>")
+    case BinVariant::BinaryOperatorUrsh:
         return BinaryOperator::Ursh;
-    if (chars == "+")
+    case BinVariant::BinaryOperatorOrUnaryOperatorPlus:
         return BinaryOperator::Plus;
-    if (chars == "-")
+    case BinVariant::BinaryOperatorOrUnaryOperatorMinus:
         return BinaryOperator::Minus;
-    if (chars == "*")
+    case BinVariant::BinaryOperatorMul:
         return BinaryOperator::Mul;
-    if (chars == "/")
+    case BinVariant::BinaryOperatorDiv:
         return BinaryOperator::Div;
-    if (chars == "%")
+    case BinVariant::BinaryOperatorMod:
         return BinaryOperator::Mod;
-    if (chars == "**")
+    case BinVariant::BinaryOperatorPow:
         return BinaryOperator::Pow;
-
-    return raiseInvalidEnum("BinaryOperator", chars);
+      default:
+        return raiseInvalidVariant("BinaryOperator", variant);
+    }
 }
 
 /*
 enum CompoundAssignmentOperator {
     "+=",
     "-=",
     "*=",
     "/=",
@@ -6702,624 +7059,631 @@ enum CompoundAssignmentOperator {
     "<<=",
     ">>=",
     ">>>=",
     "|=",
     "^=",
     "&="
 };
 */
-JS::Result<BinASTParser::CompoundAssignmentOperator>
-BinASTParser::parseCompoundAssignmentOperator()
-{
-    // Unoptimized implementation.
-    Chars chars(cx_);
-    MOZ_TRY(readString(chars));
-
-    if (chars == "+=")
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
+BinASTParser<Tok>::parseCompoundAssignmentOperator()
+{
+    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+
+    switch (variant) {
+    case BinVariant::CompoundAssignmentOperatorPlusAssign:
         return CompoundAssignmentOperator::PlusAssign;
-    if (chars == "-=")
+    case BinVariant::CompoundAssignmentOperatorMinusAssign:
         return CompoundAssignmentOperator::MinusAssign;
-    if (chars == "*=")
+    case BinVariant::CompoundAssignmentOperatorMulAssign:
         return CompoundAssignmentOperator::MulAssign;
-    if (chars == "/=")
+    case BinVariant::CompoundAssignmentOperatorDivAssign:
         return CompoundAssignmentOperator::DivAssign;
-    if (chars == "%=")
+    case BinVariant::CompoundAssignmentOperatorModAssign:
         return CompoundAssignmentOperator::ModAssign;
-    if (chars == "**=")
+    case BinVariant::CompoundAssignmentOperatorPowAssign:
         return CompoundAssignmentOperator::PowAssign;
-    if (chars == "<<=")
+    case BinVariant::CompoundAssignmentOperatorLshAssign:
         return CompoundAssignmentOperator::LshAssign;
-    if (chars == ">>=")
+    case BinVariant::CompoundAssignmentOperatorRshAssign:
         return CompoundAssignmentOperator::RshAssign;
-    if (chars == ">>>=")
+    case BinVariant::CompoundAssignmentOperatorUrshAssign:
         return CompoundAssignmentOperator::UrshAssign;
-    if (chars == "|=")
+    case BinVariant::CompoundAssignmentOperatorBitOrAssign:
         return CompoundAssignmentOperator::BitOrAssign;
-    if (chars == "^=")
+    case BinVariant::CompoundAssignmentOperatorBitXorAssign:
         return CompoundAssignmentOperator::BitXorAssign;
-    if (chars == "&=")
+    case BinVariant::CompoundAssignmentOperatorBitAndAssign:
         return CompoundAssignmentOperator::BitAndAssign;
-
-    return raiseInvalidEnum("CompoundAssignmentOperator", chars);
+      default:
+        return raiseInvalidVariant("CompoundAssignmentOperator", variant);
+    }
 }
 
 /*
 enum UnaryOperator {
     "+",
     "-",
     "!",
     "~",
     "typeof",
     "void",
     "delete"
 };
 */
-JS::Result<BinASTParser::UnaryOperator>
-BinASTParser::parseUnaryOperator()
-{
-    // Unoptimized implementation.
-    Chars chars(cx_);
-    MOZ_TRY(readString(chars));
-
-    if (chars == "+")
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::UnaryOperator>
+BinASTParser<Tok>::parseUnaryOperator()
+{
+    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+
+    switch (variant) {
+    case BinVariant::BinaryOperatorOrUnaryOperatorPlus:
         return UnaryOperator::Plus;
-    if (chars == "-")
+    case BinVariant::BinaryOperatorOrUnaryOperatorMinus:
         return UnaryOperator::Minus;
-    if (chars == "!")
+    case BinVariant::UnaryOperatorNot:
         return UnaryOperator::Not;
-    if (chars == "~")
+    case BinVariant::UnaryOperatorBitNot:
         return UnaryOperator::BitNot;
-    if (chars == "typeof")
+    case BinVariant::UnaryOperatorTypeof:
         return UnaryOperator::Typeof;
-    if (chars == "void")
+    case BinVariant::UnaryOperatorVoid:
         return UnaryOperator::Void;
-    if (chars == "delete")
+    case BinVariant::UnaryOperatorDelete:
         return UnaryOperator::Delete;
-
-    return raiseInvalidEnum("UnaryOperator", chars);
+      default:
+        return raiseInvalidVariant("UnaryOperator", variant);
+    }
 }
 
 /*
 enum UpdateOperator {
     "++",
     "--"
 };
 */
-JS::Result<BinASTParser::UpdateOperator>
-BinASTParser::parseUpdateOperator()
-{
-    // Unoptimized implementation.
-    Chars chars(cx_);
-    MOZ_TRY(readString(chars));
-
-    if (chars == "++")
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::UpdateOperator>
+BinASTParser<Tok>::parseUpdateOperator()
+{
+    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+
+    switch (variant) {
+    case BinVariant::UpdateOperatorIncr:
         return UpdateOperator::Incr;
-    if (chars == "--")
+    case BinVariant::UpdateOperatorDecr:
         return UpdateOperator::Decr;
-
-    return raiseInvalidEnum("UpdateOperator", chars);
+      default:
+        return raiseInvalidVariant("UpdateOperator", variant);
+    }
 }
 
 /*
 enum VariableDeclarationKind {
     "var",
     "let",
     "const"
 };
 */
-JS::Result<BinASTParser::VariableDeclarationKind>
-BinASTParser::parseVariableDeclarationKind()
-{
-    // Unoptimized implementation.
-    Chars chars(cx_);
-    MOZ_TRY(readString(chars));
-
-    if (chars == "var")
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
+BinASTParser<Tok>::parseVariableDeclarationKind()
+{
+    MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+
+    switch (variant) {
+    case BinVariant::VariableDeclarationKindVar:
         return VariableDeclarationKind::Var;
-    if (chars == "let")
+    case BinVariant::VariableDeclarationKindLet:
         return VariableDeclarationKind::Let;
-    if (chars == "const")
+    case BinVariant::VariableDeclarationKindConst:
         return VariableDeclarationKind::Const;
-
-    return raiseInvalidEnum("VariableDeclarationKind", chars);
+      default:
+        return raiseInvalidVariant("VariableDeclarationKind", variant);
+    }
 }
 
 
 
 // ----- Lists (autogenerated, by lexicographical order)
 
-JS::Result<ParseNode*>
-BinASTParser::parseArguments()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArguments()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfAssignmentTargetOrAssignmentTargetWithInitializer()
 {
     return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetOrAssignmentTargetWithInitializer)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfAssignmentTargetProperty()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfAssignmentTargetProperty()
 {
     return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetProperty)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfBindingProperty()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfBindingProperty()
 {
     return raiseError("FIXME: Not implemented yet (ListOfBindingProperty)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfClassElement()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfClassElement()
 {
     return raiseError("FIXME: Not implemented yet (ListOfClassElement)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfDirective()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfDirective()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfExportFromSpecifier()
 {
     return raiseError("FIXME: Not implemented yet (ListOfExportFromSpecifier)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfExportLocalSpecifier()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfExportLocalSpecifier()
 {
     return raiseError("FIXME: Not implemented yet (ListOfExportLocalSpecifier)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfExpressionOrTemplateElement()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfExpressionOrTemplateElement()
 {
     return raiseError("FIXME: Not implemented yet (ListOfExpressionOrTemplateElement)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfIdentifierName()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfIdentifierName()
 {
     return raiseError("FIXME: Not implemented yet (ListOfIdentifierName)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfImportDeclarationOrExportDeclarationOrStatement()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfImportDeclarationOrExportDeclarationOrStatement()
 {
     return raiseError("FIXME: Not implemented yet (ListOfImportDeclarationOrExportDeclarationOrStatement)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfImportSpecifier()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfImportSpecifier()
 {
     return raiseError("FIXME: Not implemented yet (ListOfImportSpecifier)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfObjectProperty()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfObjectProperty()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfOptionalBindingOrBindingWithInitializer()
 {
     return raiseError("FIXME: Not implemented yet (ListOfOptionalBindingOrBindingWithInitializer)");
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfOptionalSpreadElementOrExpression()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfParameter()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfStatement()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfSwitchCase()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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()
+    MOZ_TRY(guard.done());
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfVariableDeclarator()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    TRY(tokenizer_->enterList(length, guard));
+    MOZ_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());
+    MOZ_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));
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseOptionalAssertedBlockScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseOptionalAssertedParameterScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseOptionalAssertedVarScope()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalAssignmentTarget()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, 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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalBinding()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
     }
-    TRY(guard.done());
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalBindingIdentifier()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalBindingIdentifier()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalBindingOrBindingWithInitializer()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, 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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalCatchClause()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, 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));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
     }
-    TRY(guard.done());
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalIdentifierName()
-{
-    RootedAtom string(cx_);
-    MOZ_TRY(readMaybeString(&string));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalIdentifierName()
+{
+    MOZ_TRY_DECL(result, tokenizer_->readMaybeAtom());
 
 
 
     return raiseError("FIXME: Not implemented yet (OptionalIdentifierName)");
 
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalLabel()
-{
-    RootedAtom string(cx_);
-    MOZ_TRY(readMaybeString(&string));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalLabel()
+{
+    MOZ_TRY_DECL(result, tokenizer_->readMaybeAtom());
 
 
 
     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));
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalSpreadElementOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
     }
-    TRY(guard.done());
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalStatement()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalStatement()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
     }
-    TRY(guard.done());
-
-    return result;
-}
-
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalVariableDeclarationOrExpression()
-{
-    BinKind kind;
-    BinFields fields(cx_);
-    AutoTaggedTuple guard(*tokenizer_);
-
-    TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression()
+{
+    BinKind kind;
+    BinFields fields(cx_);
+    AutoTaggedTuple guard(*tokenizer_);
+
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     ParseNode* result;
     if (kind == BinKind::_Null) {
         result = nullptr;
     } else {
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(start, kind, fields));
     }
-    TRY(guard.done());
-
-    return result;
-}
-
-
+    MOZ_TRY(guard.done());
+
+    return result;
+}
+
+
+
+// Force class instantiation.
+// This ensures that the symbols are built, without having to export all our
+// code (and its baggage of #include and macros) in the header.
+template class BinASTParser<BinTokenReaderMultipart>;
+template class BinASTParser<BinTokenReaderTester>;
+
+} // namespace frontend
+} // namespace js
 
 #undef TRY
 #undef TRY_VAR
 #undef TRY_DECL
+#undef TRY_EMPL
+#undef MOZ_TRY_EMPLACE
 #undef MOZ_TRY_DECL
-} // namespace frontend
-} // namespace js
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BinSource-macros.h
@@ -0,0 +1,67 @@
+/* -*- 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/. */
+
+#ifndef frontend_BinSource_macros_h
+#define frontend_BinSource_macros_h
+
+
+// Evaluate an expression EXPR, checking that the result is not falsy.
+//
+// Throw `cx->alreadyReportedError()` if it returns 0/nullptr.
+#define BINJS_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 BINJS_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 BINJS_TRY_DECL(VAR, EXPR) \
+    auto VAR = EXPR; \
+    if (!VAR) \
+        return cx_->alreadyReportedError();
+
+#define BINJS_TRY_EMPL(VAR, EXPR) \
+    do { \
+        auto _tryEmplResult = EXPR; \
+        if (!_tryEmplResult) \
+            return cx_->alreadyReportedError(); \
+        VAR.emplace(_tryEmplResult.unwrap()); \
+    } while (false)
+
+#define BINJS_MOZ_TRY_EMPLACE(VAR, EXPR) \
+    do { \
+        auto _tryEmplResult = EXPR; \
+        if (_tryEmplResult.isErr()) \
+            return ::mozilla::Err(_tryEmplResult.unwrapErr()); \
+        VAR.emplace(_tryEmplResult.unwrap()); \
+    } while (false)
+
+// 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 BINJS_MOZ_TRY_DECL(VAR, EXPR) \
+    auto _##VAR = EXPR; \
+    if (_##VAR.isErr()) \
+        return ::mozilla::Err(_##VAR.unwrapErr()); \
+    auto VAR = _##VAR.unwrap();
+
+#endif // frontend_BinSource_macros_h
--- a/js/src/frontend/BinToken.h
+++ b/js/src/frontend/BinToken.h
@@ -56,292 +56,377 @@ namespace frontend {
  * #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(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(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(Directive, Directive) \
-    F(DoWhileStatement, DoWhileStatement) \
-    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(FormalParameters, FormalParameters) \
-    F(FunctionBody, FunctionBody) \
-    F(FunctionBodyOrExpression, FunctionBodyOrExpression) \
-    F(FunctionDeclaration, FunctionDeclaration) \
-    F(FunctionDeclarationOrClassDeclarationOrExpression, FunctionDeclarationOrClassDeclarationOrExpression) \
-    F(FunctionDeclarationOrClassDeclarationOrVariableDeclaration, FunctionDeclarationOrClassDeclarationOrVariableDeclaration) \
-    F(FunctionExpression, FunctionExpression) \
-    F(Getter, Getter) \
-    F(Identifier, Identifier) \
-    F(IdentifierExpression, IdentifierExpression) \
-    F(IdentifierName, IdentifierName) \
-    F(IfStatement, IfStatement) \
-    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(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(NewTargetExpression, NewTargetExpression) \
-    F(ObjectAssignmentTarget, ObjectAssignmentTarget) \
-    F(ObjectBinding, ObjectBinding) \
-    F(ObjectExpression, ObjectExpression) \
-    F(ObjectProperty, ObjectProperty) \
-    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(PropertyName, PropertyName) \
-    F(ReturnStatement, ReturnStatement) \
-    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(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(WhileStatement, WhileStatement) \
-    F(WithStatement, WithStatement) \
-    F(YieldExpression, YieldExpression) \
-    F(YieldStarExpression, YieldStarExpression) \
-    F(_Null, _Null) \
-    F(string, string)
-
+    F(_Null, "") \
+    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(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(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(Directive, "Directive") \
+    F(DoWhileStatement, "DoWhileStatement") \
+    F(EagerArrowExpression, "EagerArrowExpression") \
+    F(EagerFunctionDeclaration, "EagerFunctionDeclaration") \
+    F(EagerFunctionExpression, "EagerFunctionExpression") \
+    F(EagerGetter, "EagerGetter") \
+    F(EagerMethod, "EagerMethod") \
+    F(EagerSetter, "EagerSetter") \
+    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(FormalParameters, "FormalParameters") \
+    F(FunctionBody, "FunctionBody") \
+    F(FunctionBodyOrExpression, "FunctionBodyOrExpression") \
+    F(FunctionDeclaration, "FunctionDeclaration") \
+    F(FunctionDeclarationOrClassDeclarationOrExpression, "FunctionDeclarationOrClassDeclarationOrExpression") \
+    F(FunctionDeclarationOrClassDeclarationOrVariableDeclaration, "FunctionDeclarationOrClassDeclarationOrVariableDeclaration") \
+    F(FunctionExpression, "FunctionExpression") \
+    F(Getter, "Getter") \
+    F(Identifier, "Identifier") \
+    F(IdentifierExpression, "IdentifierExpression") \
+    F(IdentifierName, "IdentifierName") \
+    F(IfStatement, "IfStatement") \
+    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(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(NewTargetExpression, "NewTargetExpression") \
+    F(ObjectAssignmentTarget, "ObjectAssignmentTarget") \
+    F(ObjectBinding, "ObjectBinding") \
+    F(ObjectExpression, "ObjectExpression") \
+    F(ObjectProperty, "ObjectProperty") \
+    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(PropertyName, "PropertyName") \
+    F(ReturnStatement, "ReturnStatement") \
+    F(Script, "Script") \
+    F(Setter, "Setter") \
+    F(ShorthandProperty, "ShorthandProperty") \
+    F(SimpleAssignmentTarget, "SimpleAssignmentTarget") \
+    F(SkippableArrowExpression, "SkippableArrowExpression") \
+    F(SkippableFunctionDeclaration, "SkippableFunctionDeclaration") \
+    F(SkippableFunctionExpression, "SkippableFunctionExpression") \
+    F(SkippableGetter, "SkippableGetter") \
+    F(SkippableMethod, "SkippableMethod") \
+    F(SkippableSetter, "SkippableSetter") \
+    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(TryCatchStatement, "TryCatchStatement") \
+    F(TryFinallyStatement, "TryFinallyStatement") \
+    F(UnaryExpression, "UnaryExpression") \
+    F(UnaryOperator, "UnaryOperator") \