Bug 1439855 - Multipart tokenizer, templatized (WIP) draft
authorDavid Teller <dteller@mozilla.com>
Wed, 21 Mar 2018 13:27:07 +0100
changeset 770494 dd72c50cfee322b56cc9119dc66a4f90e90806fc
parent 770493 d33de9846c0bca184d7ed2c3d7b4e0da5eb717e5
child 770864 ee9e9eff9b5aae0d22ff63f911d75411c4030648
push id103417
push userdteller@mozilla.com
push dateWed, 21 Mar 2018 12:27:46 +0000
bugs1439855
milestone61.0a1
Bug 1439855 - Multipart tokenizer, templatized (WIP) MozReview-Commit-ID: GKrZZnTgnFm
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource-auto.h
js/src/frontend/BinSource.cpp
js/src/frontend/BinSource.h
js/src/frontend/BinSource.yaml
js/src/jsapi-tests/testBinASTReader.cpp
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -31,80 +31,51 @@
 #include "vm/RegExpObject.h"
 
 #include "frontend/ParseContext-inl.h"
 #include "frontend/ParseNode-inl.h"
 
 namespace js {
 namespace frontend {
 
-// FIXME: Check whether we are using all these aliases.
-using AutoList = BinASTParser::Tokenizer::AutoList;
-using AutoTaggedTuple = BinASTParser::Tokenizer::AutoTaggedTuple;
-using AutoTuple = BinASTParser::Tokenizer::AutoTuple;
-using BinFields = BinASTParser::Tokenizer::BinFields;
-using Chars = BinASTParser::Tokenizer::Chars;
-using NameBag = GCHashSet<JSString*>;
-using Names = GCVector<JSString*, 8>;
-using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
-
 // 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.
 /*
 AssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTarget()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -127,34 +98,34 @@ BinASTParser::parseSumAssignmentTarget(c
 /*
 AssignmentTargetOrAssignmentTargetWithInitializer ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     AssignmentTargetWithInitializer
     ComputedMemberAssignmentTarget
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetOrAssignmentTargetWithInitializer()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -176,34 +147,34 @@ BinASTParser::parseSumAssignmentTargetOr
     }
     return result;
 }
 
 /*
 AssignmentTargetPattern ::= ArrayAssignmentTarget
     ObjectAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetPattern()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumAssignmentTargetPattern(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -213,34 +184,34 @@ BinASTParser::parseSumAssignmentTargetPa
     }
     return result;
 }
 
 /*
 AssignmentTargetProperty ::= AssignmentTargetPropertyIdentifier
     AssignmentTargetPropertyProperty
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetProperty()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -251,34 +222,34 @@ BinASTParser::parseSumAssignmentTargetPr
     return result;
 }
 
 /*
 Binding ::= ArrayBinding
     BindingIdentifier
     ObjectBinding
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBinding()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -293,34 +264,34 @@ BinASTParser::parseSumBinding(const size
 }
 
 /*
 BindingOrBindingWithInitializer ::= ArrayBinding
     BindingIdentifier
     BindingWithInitializer
     ObjectBinding
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingOrBindingWithInitializer()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -336,34 +307,34 @@ BinASTParser::parseSumBindingOrBindingWi
     }
     return result;
 }
 
 /*
 BindingPattern ::= ArrayBinding
     ObjectBinding
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingPattern()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumBindingPattern(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -373,34 +344,34 @@ BinASTParser::parseSumBindingPattern(con
     }
     return result;
 }
 
 /*
 BindingProperty ::= BindingPropertyIdentifier
     BindingPropertyProperty
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingProperty()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -413,34 +384,34 @@ BinASTParser::parseSumBindingProperty(co
 
 /*
 ExportDeclaration ::= Export
     ExportAllFrom
     ExportDefault
     ExportFrom
     ExportLocals
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportDeclaration()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -485,34 +456,34 @@ Expression ::= ArrayExpression
     StaticMemberExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExpression()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -627,34 +598,34 @@ ExpressionOrSuper ::= ArrayExpression
     Super
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionOrSuper()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -772,34 +743,34 @@ ExpressionOrTemplateElement ::= ArrayExp
     TemplateElement
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionOrTemplateElement()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -894,34 +865,34 @@ BinASTParser::parseSumExpressionOrTempla
 /*
 ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ForInOfBinding
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseForInOfBindingOrAssignmentTarget()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -970,34 +941,34 @@ FunctionBodyOrExpression ::= ArrayExpres
     StaticMemberExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionBodyOrExpression()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumFunctionBodyOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1116,34 +1087,34 @@ FunctionDeclarationOrClassDeclarationOrE
     StaticMemberExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionDeclarationOrClassDeclarationOrExpression()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1238,34 +1209,34 @@ BinASTParser::parseSumFunctionDeclaratio
     return result;
 }
 
 /*
 FunctionDeclarationOrClassDeclarationOrVariableDeclaration ::= ClassDeclaration
     FunctionDeclaration
     VariableDeclaration
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1278,34 +1249,34 @@ BinASTParser::parseSumFunctionDeclaratio
     }
     return result;
 }
 
 /*
 ImportDeclaration ::= Import
     ImportNamespace
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImportDeclaration()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1343,34 +1314,34 @@ ImportDeclarationOrExportDeclarationOrSt
     SwitchStatementWithDefault
     ThrowStatement
     TryCatchStatement
     TryFinallyStatement
     VariableDeclaration
     WhileStatement
     WithStatement
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImportDeclarationOrExportDeclarationOrStatement()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1467,34 +1438,34 @@ BinASTParser::parseSumImportDeclarationO
 
 /*
 IterationStatement ::= DoWhileStatement
     ForInStatement
     ForOfStatement
     ForStatement
     WhileStatement
 */
-JS::Result<ParseNode*>
-BinASTParser::parseIterationStatement()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1516,34 +1487,34 @@ BinASTParser::parseSumIterationStatement
 
 /*
 Literal ::= LiteralBooleanExpression
     LiteralInfinityExpression
     LiteralNullExpression
     LiteralNumericExpression
     LiteralStringExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteral()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1563,34 +1534,34 @@ BinASTParser::parseSumLiteral(const size
     return result;
 }
 
 /*
 MethodDefinition ::= Getter
     Method
     Setter
 */
-JS::Result<ParseNode*>
-BinASTParser::parseMethodDefinition()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields)
+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::Getter:
         MOZ_TRY_VAR(result, parseInterfaceGetter(start, kind, fields));
         break;
       case BinKind::Method:
         MOZ_TRY_VAR(result, parseInterfaceMethod(start, kind, fields));
@@ -1606,34 +1577,34 @@ BinASTParser::parseSumMethodDefinition(c
 
 /*
 ObjectProperty ::= DataProperty
     Getter
     Method
     Setter
     ShorthandProperty
 */
-JS::Result<ParseNode*>
-BinASTParser::parseObjectProperty()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1654,34 +1625,34 @@ BinASTParser::parseSumObjectProperty(con
 }
 
 /*
 Parameter ::= ArrayBinding
     BindingIdentifier
     BindingWithInitializer
     ObjectBinding
 */
-JS::Result<ParseNode*>
-BinASTParser::parseParameter()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1697,34 +1668,34 @@ BinASTParser::parseSumParameter(const si
     }
     return result;
 }
 
 /*
 Program ::= Module
     Script
 */
-JS::Result<ParseNode*>
-BinASTParser::parseProgram()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1734,34 +1705,34 @@ BinASTParser::parseSumProgram(const size
     }
     return result;
 }
 
 /*
 PropertyName ::= ComputedPropertyName
     LiteralPropertyName
 */
-JS::Result<ParseNode*>
-BinASTParser::parsePropertyName()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1772,34 +1743,34 @@ BinASTParser::parseSumPropertyName(const
     return result;
 }
 
 /*
 SimpleAssignmentTarget ::= AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     StaticMemberAssignmentTarget
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSimpleAssignmentTarget()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1839,34 +1810,34 @@ SpreadElementOrExpression ::= ArrayExpre
     StaticMemberExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSpreadElementOrExpression()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -1978,34 +1949,34 @@ Statement ::= Block
     SwitchStatementWithDefault
     ThrowStatement
     TryCatchStatement
     TryFinallyStatement
     VariableDeclaration
     WhileStatement
     WithStatement
 */
-JS::Result<ParseNode*>
-BinASTParser::parseStatement()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -2105,34 +2076,34 @@ VariableDeclarationOrExpression ::= Arra
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     VariableDeclaration
     YieldExpression
     YieldStarExpression
 */
-JS::Result<ParseNode*>
-BinASTParser::parseVariableDeclarationOrExpression()
+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));
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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));
@@ -2230,91 +2201,91 @@ BinASTParser::parseSumVariableDeclaratio
 // When fields have a non-trivial type, implementation is deanonymized and delegated to another parser.
 
 /*
  interface ArrayAssignmentTarget : Node {
     FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer)> elements;
     AssignmentTarget? rest;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseArrayAssignmentTarget()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ArrayExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Elements }));
 
 
     MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
 
     auto result = elements;return result;
@@ -2325,64 +2296,64 @@ BinASTParser::parseInterfaceArrayExpress
  interface ArrowExpression : Node {
     bool isAsync;
     AssertedParameterScope? parameterScope;
     AssertedVarScope? bodyScope;
     FormalParameters params;
     (FunctionBody or Expression) body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseArrowExpression()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseArrowExpression()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceArrowExpression(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     return raiseError("FIXME: Not implemented yet (ArrowExpression)");
 }
 
 
 /*
  interface AssertedBlockScope : Node {
     FrozenArray<IdentifierName> lexicallyDeclaredNames;
     FrozenArray<IdentifierName> capturedNames;
     bool hasDirectEval;
  }
 */
-JS::Result<Ok>
-BinASTParser::parseAssertedBlockScope()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedBlockScope);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval }));
     MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let));
     MOZ_TRY(parseAndUpdateCapturedNames());
 
 
 
@@ -2403,34 +2374,34 @@ BinASTParser::parseInterfaceAssertedBloc
 
 /*
  interface AssertedParameterScope : Node {
     FrozenArray<IdentifierName> parameterNames;
     FrozenArray<IdentifierName> capturedNames;
     bool hasDirectEval;
  }
 */
-JS::Result<Ok>
-BinASTParser::parseAssertedParameterScope()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedParameterScope);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval }));
     MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter));
     MOZ_TRY(parseAndUpdateCapturedNames());
 
 
 
@@ -2452,34 +2423,34 @@ BinASTParser::parseInterfaceAssertedPara
 /*
  interface AssertedVarScope : Node {
     FrozenArray<IdentifierName> lexicallyDeclaredNames;
     FrozenArray<IdentifierName> varDeclaredNames;
     FrozenArray<IdentifierName> capturedNames;
     bool hasDirectEval;
  }
 */
-JS::Result<Ok>
-BinASTParser::parseAssertedVarScope()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssertedVarScope);
     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());
 
 
@@ -2500,34 +2471,34 @@ BinASTParser::parseInterfaceAssertedVarS
 
 
 /*
  interface AssignmentExpression : Node {
     AssignmentTarget binding;
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssignmentExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Binding, BinField::Expression }));
 
 
     MOZ_TRY_DECL(binding, parseAssignmentTarget());
 
 
@@ -2537,34 +2508,34 @@ BinASTParser::parseInterfaceAssignmentEx
 }
 
 
 /*
  interface AssignmentTargetIdentifier : Node {
     Identifier name;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetIdentifier()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
     RootedAtom name((cx_));
     MOZ_TRY(readString(&name));
 
     if (!IsIdentifier(name))
@@ -2574,150 +2545,150 @@ BinASTParser::parseInterfaceAssignmentTa
 
 
 /*
  interface AssignmentTargetPropertyIdentifier : Node {
     AssignmentTargetIdentifier binding;
     Expression? init;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseAssignmentTargetPropertyIdentifier()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BinaryExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Left, BinField::Right }));
 
 
     MOZ_TRY_DECL(operator_, parseBinaryOperator());
 
 
@@ -2822,34 +2793,34 @@ BinASTParser::parseInterfaceBinaryExpres
 }
 
 
 /*
  interface BindingIdentifier : Node {
     Identifier name;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingIdentifier()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BindingIdentifier);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
     RootedAtom name((cx_));
     MOZ_TRY(readString(&name));
 
     if (!IsIdentifier(name))
@@ -2859,121 +2830,121 @@ BinASTParser::parseInterfaceBindingIdent
 
 
 /*
  interface BindingPropertyIdentifier : Node {
     BindingIdentifier binding;
     Expression? init;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBindingPropertyIdentifier()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Block);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Scope, BinField::Statements }));
     fprintf(stderr, "Block: PUSH parse context\n");
     ParseContext::Statement stmt(parseContext_, StatementKind::Block);
     ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
     TRY(currentScope.init(parseContext_));
 
@@ -2988,34 +2959,34 @@ BinASTParser::parseInterfaceBlock(const 
 }
 
 
 /*
  interface BreakStatement : Node {
     Label? label;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseBreakStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::BreakStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Label }));
     RootedAtom label(cx_);
     MOZ_TRY(readMaybeString(&label));
 
     if (label && !IsIdentifier(label))
         return raiseError("Invalid identifier");
@@ -3037,34 +3008,34 @@ BinASTParser::parseInterfaceBreakStateme
 
 
 /*
  interface CallExpression : Node {
     (Expression or Super) callee;
     Arguments arguments;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseCallExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CallExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
 
 
     MOZ_TRY_DECL(callee, parseExpressionOrSuper());
 
 
@@ -3090,34 +3061,34 @@ BinASTParser::parseInterfaceCallExpressi
 
 
 /*
  interface CatchClause : Node {
     Binding binding;
     Block body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseCatchClause()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CatchClause);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Binding, BinField::Body }));
     ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
     ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
     TRY(currentScope.init(parseContext_));
 
     MOZ_TRY_DECL(binding, parseBinding());
@@ -3139,123 +3110,123 @@ BinASTParser::parseInterfaceCatchClause(
 
 /*
  interface ClassDeclaration : Node {
     BindingIdentifier name;
     Expression? super;
     FrozenArray<ClassElement> elements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseClassDeclaration()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::CompoundAssignmentExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Binding, BinField::Expression }));
 
 
     MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());
 
 
@@ -3308,34 +3279,34 @@ BinASTParser::parseInterfaceCompoundAssi
 
 
 /*
  interface ComputedMemberAssignmentTarget : Node {
     (Expression or Super) object;
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseComputedMemberAssignmentTarget()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ComputedMemberAssignmentTarget);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Object, BinField::Expression }));
 
 
     MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
 
@@ -3346,34 +3317,34 @@ BinASTParser::parseInterfaceComputedMemb
 
 
 /*
  interface ComputedMemberExpression : Node {
     (Expression or Super) object;
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseComputedMemberExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ComputedMemberExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Object, BinField::Expression }));
 
 
     MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
 
@@ -3383,64 +3354,64 @@ BinASTParser::parseInterfaceComputedMemb
 }
 
 
 /*
  interface ComputedPropertyName : Node {
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseComputedPropertyName()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ConditionalExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate }));
 
 
     MOZ_TRY_DECL(test, parseExpression());
 
 
@@ -3453,34 +3424,34 @@ BinASTParser::parseInterfaceConditionalE
 }
 
 
 /*
  interface ContinueStatement : Node {
     Label? label;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseContinueStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ContinueStatement);
     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");
@@ -3502,34 +3473,34 @@ BinASTParser::parseInterfaceContinueStat
 
 
 /*
  interface DataProperty : Node {
     PropertyName name;
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseDataProperty()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::DataProperty);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name, BinField::Expression }));
 
 
     MOZ_TRY_DECL(name, parsePropertyName());
 
 
@@ -3541,62 +3512,62 @@ BinASTParser::parseInterfaceDataProperty
     TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));return result;
 }
 
 
 /*
  interface DebuggerStatement : Node {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseDebuggerStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Directive);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::RawValue }));
 
     RootedAtom rawValue((cx_));
     MOZ_TRY(readString(&rawValue));
 
     TokenPos pos = tokenizer_->pos(start);
@@ -3605,34 +3576,34 @@ BinASTParser::parseInterfaceDirective(co
 
 
 /*
  interface DoWhileStatement : Node {
     Expression test;
     Statement body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseDoWhileStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::DoWhileStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Test, BinField::Body }));
     ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop);
 
     MOZ_TRY_DECL(test, parseExpression());
 
 
@@ -3641,264 +3612,264 @@ BinASTParser::parseInterfaceDoWhileState
     TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));return result;
 }
 
 
 /*
  interface EmptyStatement : Node {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseEmptyStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::EmptyStatement);
     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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExport()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportAllFrom()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportDefault()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportFrom()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportFromSpecifier()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportLocalSpecifier()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExportLocals()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseExpressionStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ExpressionStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Expression }));
 
 
     MOZ_TRY_DECL(expression, parseExpression());
 
     TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset()));return result;
@@ -3906,34 +3877,34 @@ BinASTParser::parseInterfaceExpressionSt
 
 
 /*
  interface ForInOfBinding : Node {
     VariableDeclarationKind kind;
     Binding binding;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseForInOfBinding()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ForInOfBinding);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Kind, BinField::Binding }));
     AutoVariableDeclarationKind kindGuard(this);
 
     MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
 
 
@@ -3953,34 +3924,34 @@ BinASTParser::parseInterfaceForInOfBindi
 
 /*
  interface ForInStatement : Node {
     (ForInOfBinding or AssignmentTarget) left;
     Expression right;
     Statement body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseForInStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ForInStatement);
     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`.
@@ -4007,65 +3978,65 @@ BinASTParser::parseInterfaceForInStateme
 
 /*
  interface ForOfStatement : Node {
     (ForInOfBinding or AssignmentTarget) left;
     Expression right;
     Statement body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseForOfStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseForStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ForStatement);
     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`.
@@ -4094,34 +4065,34 @@ BinASTParser::parseInterfaceForStatement
 
 
 /*
  interface FormalParameters : Node {
     FrozenArray<Parameter> items;
     Binding? rest;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFormalParameters()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::FormalParameters);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Items, BinField::Rest }));
 
 
     MOZ_TRY_DECL(items, parseListOfParameter());
 
 
@@ -4136,34 +4107,34 @@ BinASTParser::parseInterfaceFormalParame
 
 
 /*
  interface FunctionBody : Node {
     FrozenArray<Directive> directives;
     FrozenArray<Statement> statements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionBody()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::FunctionBody);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Directives, BinField::Statements }));
 
 
     MOZ_TRY_DECL(directives, parseListOfDirective());
 
 
@@ -4179,34 +4150,34 @@ BinASTParser::parseInterfaceFunctionBody
     bool isGenerator;
     AssertedParameterScope? parameterScope;
     AssertedVarScope? bodyScope;
     BindingIdentifier name;
     FormalParameters params;
     FunctionBody body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionDeclaration()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionDeclaration()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceFunctionDeclaration(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::FunctionDeclaration);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
 
 
     MOZ_TRY_DECL(isAsync, readBool());
 
 
@@ -4254,34 +4225,34 @@ BinASTParser::parseInterfaceFunctionDecl
     bool isGenerator;
     AssertedParameterScope? parameterScope;
     AssertedVarScope? bodyScope;
     BindingIdentifier? name;
     FormalParameters params;
     FunctionBody body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseFunctionExpression()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseFunctionExpression()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceFunctionExpression(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::FunctionExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
 
 
     MOZ_TRY_DECL(isAsync, readBool());
 
 
@@ -4325,62 +4296,62 @@ BinASTParser::parseInterfaceFunctionExpr
 
 /*
  interface Getter : Node {
     AssertedVarScope? bodyScope;
     PropertyName name;
     FunctionBody body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseGetter()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseGetter()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceGetter(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceGetter(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::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()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::IdentifierExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
     RootedAtom name((cx_));
     MOZ_TRY(readString(&name));
 
     if (!IsIdentifier(name))
@@ -4391,34 +4362,34 @@ BinASTParser::parseInterfaceIdentifierEx
 
 /*
  interface IfStatement : Node {
     Expression test;
     Statement consequent;
     Statement? alternate;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseIfStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::IfStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate }));
 
 
     MOZ_TRY_DECL(test, parseExpression());
 
 
@@ -4433,122 +4404,122 @@ BinASTParser::parseInterfaceIfStatement(
 
 /*
  interface Import : Node {
     string moduleSpecifier;
     BindingIdentifier? defaultBinding;
     FrozenArray<ImportSpecifier> namedImports;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImport()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImportNamespace()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseImportSpecifier()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields)
+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;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLabelledStatement()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LabelledStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Label, BinField::Body }));
 
 
     RootedAtom label((cx_));
     MOZ_TRY(readString(&label));
     if (!IsIdentifier(label))
@@ -4562,159 +4533,159 @@ BinASTParser::parseInterfaceLabelledStat
 }
 
 
 /*
  interface LiteralBooleanExpression : Node {
     bool value;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteralBooleanExpression()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralBooleanExpression);
     MOZ_TRY(tokenizer_->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()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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 {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteralNullExpression()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralNullExpression);
     MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
     TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));return result;
 }
 
 
 /*
  interface LiteralNumericExpression : Node {
     number value;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteralNumericExpression()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralNumericExpression);
     MOZ_TRY(tokenizer_->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()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralPropertyName);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
 
     RootedAtom value((cx_));
     MOZ_TRY(readString(&value));
 
     ParseNode* result;
@@ -4727,34 +4698,34 @@ BinASTParser::parseInterfaceLiteralPrope
 
 
 /*
  interface LiteralRegExpExpression : Node {
     string pattern;
     string flags;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteralRegExpExpression()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralRegExpExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Pattern, BinField::Flags }));
 
     RootedAtom pattern((cx_));
     MOZ_TRY(readString(&pattern));
     Chars flags(cx_);
     MOZ_TRY(readString(flags));
@@ -4787,34 +4758,34 @@ BinASTParser::parseInterfaceLiteralRegEx
 }
 
 
 /*
  interface LiteralStringExpression : Node {
     string value;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseLiteralStringExpression()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::LiteralStringExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Value }));
 
     RootedAtom value((cx_));
     MOZ_TRY(readString(&value));
 
     TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));return result;
@@ -4827,34 +4798,34 @@ BinASTParser::parseInterfaceLiteralStrin
     bool isGenerator;
     AssertedParameterScope? parameterScope;
     AssertedVarScope? bodyScope;
     PropertyName name;
     FormalParameters params;
     FunctionBody body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseMethod()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseMethod()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceMethod(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Method);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body }));
 
 
     MOZ_TRY_DECL(isAsync, readBool());
 
 
@@ -4897,63 +4868,63 @@ BinASTParser::parseInterfaceMethod(const
 
 /*
  interface Module : Node {
     AssertedVarScope? scope;
     FrozenArray<Directive> directives;
     FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseModule()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::NewExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Callee, BinField::Arguments }));
 
 
     MOZ_TRY_DECL(callee, parseExpression());
 
 
@@ -4964,152 +4935,152 @@ BinASTParser::parseInterfaceNewExpressio
     result->prepend(callee);return result;
 }
 
 
 /*
  interface NewTargetExpression : Node {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseNewTargetExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ObjectExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Properties }));
 
 
     MOZ_TRY_DECL(properties, parseListOfObjectProperty());
 
     auto result = properties;return result;
 }
 
 
 /*
  interface ReturnStatement : Node {
     Expression? expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseReturnStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ReturnStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Expression }));
     if (!parseContext_->isFunctionBox()) {
         // Return statements are permitted only inside functions.
         return raiseInvalidKind("Toplevel Statement", kind);
     }
 
@@ -5123,34 +5094,34 @@ BinASTParser::parseInterfaceReturnStatem
 
 /*
  interface Script : Node {
     AssertedVarScope? scope;
     FrozenArray<Directive> directives;
     FrozenArray<Statement> statements;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseScript()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Script);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Scope, BinField::Directives, BinField::Statements }));
 
 
     MOZ_TRY(parseOptionalAssertedVarScope());
 
 
@@ -5167,34 +5138,34 @@ BinASTParser::parseInterfaceScript(const
  interface Setter : Node {
     AssertedParameterScope? parameterScope;
     AssertedVarScope? bodyScope;
     PropertyName name;
     Parameter param;
     FunctionBody body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSetter()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseSetter()
 {
     BinKind kind;
     BinFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
     MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
     const auto start = tokenizer_->offset();
 
     MOZ_TRY_DECL(result, parseInterfaceSetter(start, kind, fields));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::Setter);
     MOZ_TRY(tokenizer_->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,
@@ -5231,34 +5202,34 @@ BinASTParser::parseInterfaceSetter(const
 }
 
 
 /*
  interface ShorthandProperty : Node {
     IdentifierExpression name;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseShorthandProperty()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ShorthandProperty);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Name }));
 
 
     MOZ_TRY_DECL(name, parseIdentifierExpression());
 
     if (!factory_.isUsableAsObjectPropertyName(name))
@@ -5268,63 +5239,63 @@ BinASTParser::parseInterfaceShorthandPro
 }
 
 
 /*
  interface SpreadElement : Node {
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSpreadElement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Object, BinField::Property }));
 
 
     MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     RootedAtom property((cx_));
@@ -5335,34 +5306,34 @@ BinASTParser::parseInterfaceStaticMember
 
 
 /*
  interface StaticMemberExpression : Node {
     (Expression or Super) object;
     IdentifierName property;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseStaticMemberExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Object, BinField::Property }));
 
 
     MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     RootedAtom property((cx_));
@@ -5371,63 +5342,63 @@ BinASTParser::parseInterfaceStaticMember
     TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));return result;
 }
 
 
 /*
  interface Super : Node {
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSuper()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchCase);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Test, BinField::Consequent }));
 
 
     MOZ_TRY_DECL(test, parseExpression());
 
 
@@ -5437,34 +5408,34 @@ BinASTParser::parseInterfaceSwitchCase(c
 }
 
 
 /*
  interface SwitchDefault : Node {
     FrozenArray<Statement> consequent;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSwitchDefault()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchDefault);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Consequent }));
 
 
     MOZ_TRY_DECL(consequent, parseListOfStatement());
 
     TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));return result;
@@ -5472,34 +5443,34 @@ BinASTParser::parseInterfaceSwitchDefaul
 
 
 /*
  interface SwitchStatement : Node {
     Expression discriminant;
     FrozenArray<SwitchCase> cases;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSwitchStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Discriminant, BinField::Cases }));
 
 
     MOZ_TRY_DECL(discriminant, parseExpression());
 
 
@@ -5513,34 +5484,34 @@ BinASTParser::parseInterfaceSwitchStatem
 /*
  interface SwitchStatementWithDefault : Node {
     Expression discriminant;
     FrozenArray<SwitchCase> preDefaultCases;
     SwitchDefault defaultCase;
     FrozenArray<SwitchCase> postDefaultCases;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseSwitchStatementWithDefault()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::SwitchStatementWithDefault);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases }));
 
 
     MOZ_TRY_DECL(discriminant, parseExpression());
 
 
@@ -5566,90 +5537,90 @@ BinASTParser::parseInterfaceSwitchStatem
 }
 
 
 /*
  interface TemplateElement : Node {
     string rawValue;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseTemplateElement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ThisExpression);
     MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
     if (parseContext_->isFunctionBox())
         parseContext_->functionBox()->usesThis = true;
 
     TokenPos pos = tokenizer_->pos(start);
@@ -5661,34 +5632,34 @@ BinASTParser::parseInterfaceThisExpressi
 }
 
 
 /*
  interface ThrowStatement : Node {
     Expression expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseThrowStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::ThrowStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Expression }));
 
 
     MOZ_TRY_DECL(expression, parseExpression());
 
     TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));return result;
@@ -5696,34 +5667,34 @@ BinASTParser::parseInterfaceThrowStateme
 
 
 /*
  interface TryCatchStatement : Node {
     Block body;
     CatchClause catchClause;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseTryCatchStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::TryCatchStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Body, BinField::CatchClause }));
 
     ParseNode* body;
     {
         ParseContext::Statement stmt(parseContext_, StatementKind::Try);
         ParseContext::Scope scope(cx_, parseContext_, usedNames_);
@@ -5741,34 +5712,34 @@ BinASTParser::parseInterfaceTryCatchStat
 
 /*
  interface TryFinallyStatement : Node {
     Block body;
     CatchClause? catchClause;
     Block finalizer;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseTryFinallyStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::TryFinallyStatement);
     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_);
@@ -5794,34 +5765,34 @@ BinASTParser::parseInterfaceTryFinallySt
 
 
 /*
  interface UnaryExpression : Node {
     UnaryOperator operator;
     Expression operand;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseUnaryExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::UnaryExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Operator, BinField::Operand }));
 
 
     MOZ_TRY_DECL(operator_, parseUnaryOperator());
 
 
@@ -5875,34 +5846,34 @@ BinASTParser::parseInterfaceUnaryExpress
 
 /*
  interface UpdateExpression : Node {
     bool isPrefix;
     UpdateOperator operator;
     SimpleAssignmentTarget operand;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseUpdateExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::UpdateExpression);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::IsPrefix, BinField::Operator, BinField::Operand }));
 
 
     MOZ_TRY_DECL(isPrefix, readBool());
 
 
@@ -5927,34 +5898,34 @@ BinASTParser::parseInterfaceUpdateExpres
 
 
 /*
  interface VariableDeclaration : Node {
     VariableDeclarationKind kind;
     FrozenArray<VariableDeclarator> declarators;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseVariableDeclaration()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::VariableDeclaration);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Kind, BinField::Declarators }));
     AutoVariableDeclarationKind kindGuard(this);
 
 
     MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
     // Restored by `kindGuard`.
@@ -5985,34 +5956,34 @@ BinASTParser::parseInterfaceVariableDecl
 
 
 /*
  interface VariableDeclarator : Node {
     Binding binding;
     Expression? init;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseVariableDeclarator()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::VariableDeclarator);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Binding, BinField::Init }));
 
 
     MOZ_TRY_DECL(binding, parseBinding());
 
 
@@ -6040,34 +6011,34 @@ BinASTParser::parseInterfaceVariableDecl
 
 
 /*
  interface WhileStatement : Node {
     Expression test;
     Statement body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseWhileStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::WhileStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Test, BinField::Body }));
     ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop);
 
     MOZ_TRY_DECL(test, parseExpression());
 
 
@@ -6078,34 +6049,34 @@ BinASTParser::parseInterfaceWhileStateme
 
 
 /*
  interface WithStatement : Node {
     Expression object;
     Statement body;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseWithStatement()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields)
 {
     MOZ_ASSERT(kind == BinKind::WithStatement);
     MOZ_TRY(tokenizer_->checkFields(kind, fields, { BinField::Object, BinField::Body }));
 
 
     MOZ_TRY_DECL(object, parseExpression());
 
 
@@ -6115,89 +6086,89 @@ BinASTParser::parseInterfaceWithStatemen
 }
 
 
 /*
  interface YieldExpression : Node {
     Expression? expression;
  }
 */
-JS::Result<ParseNode*>
-BinASTParser::parseYieldExpression()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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));
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields)
+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()
+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;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields)
+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)");
 }
 
 
 
 // ----- String enums (autogenerated, by lexicographical order)
 /*
@@ -6224,18 +6195,18 @@ enum BinaryOperator {
     "+",
     "-",
     "*",
     "/",
     "%",
     "**"
 };
 */
-JS::Result<BinASTParser::BinaryOperator>
-BinASTParser::parseBinaryOperator()
+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;
       case BinVariant::BinaryOperatorLogicalOr:
         return BinaryOperator::LogicalOr;
@@ -6301,18 +6272,18 @@ enum CompoundAssignmentOperator {
     "<<=",
     ">>=",
     ">>>=",
     "|=",
     "^=",
     "&="
 };
 */
-JS::Result<BinASTParser::CompoundAssignmentOperator>
-BinASTParser::parseCompoundAssignmentOperator()
+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;
       case BinVariant::CompoundAssignmentOperatorMinusAssign:
         return CompoundAssignmentOperator::MinusAssign;
@@ -6347,18 +6318,18 @@ enum UnaryOperator {
     "-",
     "!",
     "~",
     "typeof",
     "void",
     "delete"
 };
 */
-JS::Result<BinASTParser::UnaryOperator>
-BinASTParser::parseUnaryOperator()
+template<typename Tok> JS::Result<typename BinASTParser<Tok>::UnaryOperator>
+BinASTParser<Tok>::parseUnaryOperator()
 {
     MOZ_TRY_DECL(variant, tokenizer_->readVariant());
 
     switch (variant) {
       case BinVariant::UnaryOperatorPlus:
         return UnaryOperator::Plus;
       case BinVariant::UnaryOperatorMinus:
         return UnaryOperator::Minus;
@@ -6378,18 +6349,18 @@ BinASTParser::parseUnaryOperator()
 }
 
 /*
 enum UpdateOperator {
     "++",
     "--"
 };
 */
-JS::Result<BinASTParser::UpdateOperator>
-BinASTParser::parseUpdateOperator()
+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;
       case BinVariant::UpdateOperatorDecr:
         return UpdateOperator::Decr;
@@ -6400,18 +6371,18 @@ BinASTParser::parseUpdateOperator()
 
 /*
 enum VariableDeclarationKind {
     "var",
     "let",
     "const"
 };
 */
-JS::Result<BinASTParser::VariableDeclarationKind>
-BinASTParser::parseVariableDeclarationKind()
+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;
       case BinVariant::VariableDeclarationKindLet:
         return VariableDeclarationKind::Let;
@@ -6421,18 +6392,18 @@ BinASTParser::parseVariableDeclarationKi
         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();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
 
@@ -6440,42 +6411,42 @@ BinASTParser::parseArguments()
         MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
         factory_.addList(/* list = */ result, /* child = */ item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfAssignmentTargetOrAssignmentTargetWithInitializer()
+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();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
 
@@ -6483,54 +6454,54 @@ BinASTParser::parseListOfDirective()
         MOZ_TRY_DECL(item, parseDirective());
         factory_.addStatementToList(result, item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfExportFromSpecifier()
+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();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newObjectLiteral(start));
 
@@ -6538,24 +6509,24 @@ BinASTParser::parseListOfObjectProperty(
         MOZ_TRY_DECL(item, parseObjectProperty());
         result->appendWithoutOrderAssumption(item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfOptionalBindingOrBindingWithInitializer()
+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();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newArrayLiteral(start));
 
@@ -6566,18 +6537,18 @@ BinASTParser::parseListOfOptionalSpreadE
         else
             TRY(factory_.addElision(result, tokenizer_->pos(start)));
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfParameter()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfParameter()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     ParseNode* result = new_<ListNode>(ParseNodeKind::ParamsBody, tokenizer_->pos(start));
 
@@ -6585,18 +6556,18 @@ BinASTParser::parseListOfParameter()
         MOZ_TRY_DECL(item, parseParameter());
         factory_.addList(/* list = */ result, /* item = */ item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfStatement()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfStatement()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
 
@@ -6604,18 +6575,18 @@ BinASTParser::parseListOfStatement()
         MOZ_TRY_DECL(item, parseStatement());
         factory_.addStatementToList(result, item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfSwitchCase()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfSwitchCase()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start)));
 
@@ -6623,18 +6594,18 @@ BinASTParser::parseListOfSwitchCase()
         MOZ_TRY_DECL(item, parseSwitchCase());
         factory_.addCaseStatementToList(result, item);
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseListOfVariableDeclarator()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseListOfVariableDeclarator()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
     TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/,
         tokenizer_->pos(start)));
@@ -6645,18 +6616,18 @@ BinASTParser::parseListOfVariableDeclara
     }
 
     MOZ_TRY(guard.done());
     return result;
 }
 
 
     // ----- Default values (by lexicographical order)
-JS::Result<Ok>
-BinASTParser::parseOptionalAssertedBlockScope()
+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) {
@@ -6665,18 +6636,18 @@ BinASTParser::parseOptionalAssertedBlock
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterfaceAssertedBlockScope(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseOptionalAssertedParameterScope()
+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) {
@@ -6685,18 +6656,18 @@ BinASTParser::parseOptionalAssertedParam
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterfaceAssertedParameterScope(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseOptionalAssertedVarScope()
+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) {
@@ -6705,18 +6676,18 @@ BinASTParser::parseOptionalAssertedVarSc
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterfaceAssertedVarScope(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalAssignmentTarget()
+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) {
@@ -6725,18 +6696,18 @@ BinASTParser::parseOptionalAssignmentTar
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumAssignmentTarget(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalBinding()
+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) {
@@ -6745,18 +6716,18 @@ BinASTParser::parseOptionalBinding()
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalBindingIdentifier()
+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) {
@@ -6765,18 +6736,18 @@ BinASTParser::parseOptionalBindingIdenti
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalBindingOrBindingWithInitializer()
+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) {
@@ -6785,18 +6756,18 @@ BinASTParser::parseOptionalBindingOrBind
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumBindingOrBindingWithInitializer(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalCatchClause()
+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) {
@@ -6805,18 +6776,18 @@ BinASTParser::parseOptionalCatchClause()
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalExpression()
+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) {
@@ -6825,42 +6796,42 @@ BinASTParser::parseOptionalExpression()
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalIdentifierName()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalIdentifierName()
 {
     RootedAtom string((cx_));
     MOZ_TRY(readMaybeString(&string));
 
 
 
     return raiseError("FIXME: Not implemented yet (OptionalIdentifierName)");
 
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalLabel()
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseOptionalLabel()
 {
     RootedAtom string((cx_));
     MOZ_TRY(readMaybeString(&string));
 
 
 
     return raiseError("FIXME: Not implemented yet (OptionalLabel)");
 
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalSpreadElementOrExpression()
+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) {
@@ -6869,18 +6840,18 @@ BinASTParser::parseOptionalSpreadElement
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalStatement()
+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) {
@@ -6889,18 +6860,18 @@ BinASTParser::parseOptionalStatement()
         const auto start = tokenizer_->offset();
         MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
     }
     MOZ_TRY(guard.done());
 
     return result;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parseOptionalVariableDeclarationOrExpression()
+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) {
--- a/js/src/frontend/BinSource-auto.h
+++ b/js/src/frontend/BinSource-auto.h
@@ -350,21 +350,21 @@ JS::Result<ParseNode*> parseInterfaceWhi
 JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields);
 JS::Result<ParseNode*> parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields);
 
 
 // ----- String enums (by lexicographical order)
 // Implementations are autogenerated
-JS::Result<BinASTParser::BinaryOperator> parseBinaryOperator();
-JS::Result<BinASTParser::CompoundAssignmentOperator> parseCompoundAssignmentOperator();
-JS::Result<BinASTParser::UnaryOperator> parseUnaryOperator();
-JS::Result<BinASTParser::UpdateOperator> parseUpdateOperator();
-JS::Result<BinASTParser::VariableDeclarationKind> parseVariableDeclarationKind();
+JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator();
+JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator> parseCompoundAssignmentOperator();
+JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator();
+JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator();
+JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind> parseVariableDeclarationKind();
 
 
 // ----- Lists (by lexicographical order)
 // Implementations are autogenerated
 JS::Result<ParseNode*> parseArguments();
 JS::Result<ParseNode*> parseListOfAssignmentTargetOrAssignmentTargetWithInitializer();
 JS::Result<ParseNode*> parseListOfAssignmentTargetProperty();
 JS::Result<ParseNode*> parseListOfBindingProperty();
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -69,44 +69,37 @@
 //
 // They should be treated lazily (whenever we open a subscope), like bindings.
 
 using namespace mozilla;
 
 namespace js {
 namespace frontend {
 
-using AutoList = BinASTParser::Tokenizer::AutoList;
-using AutoTaggedTuple = BinASTParser::Tokenizer::AutoTaggedTuple;
-using AutoTuple = BinASTParser::Tokenizer::AutoTuple;
-using BinFields = BinASTParser::Tokenizer::BinFields;
-using Chars = BinASTParser::Tokenizer::Chars;
-using NameBag = GCHashSet<JSString*>;
-using Names = GCVector<JSString*, 8>;
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
 
 // ------------- Toplevel constructions
 
-JS::Result<ParseNode*>
-BinASTParser::parse(const Vector<uint8_t>& data)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parse(const Vector<uint8_t>& data)
 {
     return parse(data.begin(), data.length());
 }
 
-JS::Result<ParseNode*>
-BinASTParser::parse(const uint8_t* start, const size_t length)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parse(const uint8_t* start, const size_t length)
 {
     auto result = parseAux(start, length);
     poison(); // Make sure that the parser is never used again accidentally.
     return result;
 }
 
 
-JS::Result<ParseNode*>
-BinASTParser::parseAux(const uint8_t* start, const size_t length)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::parseAux(const uint8_t* start, const size_t length)
 {
     tokenizer_.emplace(cx_, start, length);
 
     Directives directives(options().strictOption);
     GlobalSharedContext globalsc(cx_, ScopeKind::Global,
                                  directives, options().extraWarningsOption);
     BinParseContext globalpc(cx_, this, &globalsc, /* newDirectives = */ nullptr);
     if (!globalpc.init())
@@ -124,18 +117,18 @@ BinASTParser::parseAux(const uint8_t* st
     Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_, parseContext_);
     if (!bindings)
         return cx_->alreadyReportedError();
     globalsc.bindings = *bindings;
 
     return result; // Magic conversion to Ok.
 }
 
-JS::Result<FunctionBox*>
-BinASTParser::buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind)
+template<typename Tok> JS::Result<FunctionBox*>
+BinASTParser<Tok>::buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind)
 {
     // Allocate the function before walking down the tree.
     RootedFunction fun(cx_);
     TRY_VAR(fun, NewFunctionWithProto(cx_,
             /* native = */ nullptr,
             /* nargs placeholder = */ 0,
             JSFunction::INTERPRETED_NORMAL,
             /* enclosingEnv = */ nullptr,
@@ -156,18 +149,18 @@ BinASTParser::buildFunctionBox(Generator
     traceListHead_ = funbox;
     FunctionSyntaxKind syntax = PrimaryExpression; // FIXME - What if we're assigning?
     // FIXME: The only thing we need to know is whether this is a
     // ClassConstructor/DerivedClassConstructor
     funbox->initWithEnclosingParseContext(parseContext_, syntax);
     return funbox;
 }
 
-JS::Result<ParseNode*>
-BinASTParser::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::buildFunction(const size_t start, const BinKind kind, ParseNode* name,
                             ParseNode* params, ParseNode* body, FunctionBox* funbox)
 {
     TokenPos pos = tokenizer_->pos(start);
 
     RootedAtom atom((cx_));
     if (name)
         atom = name->name();
 
@@ -203,36 +196,36 @@ BinASTParser::buildFunction(const size_t
              NewFunctionScopeData(cx_, parseContext_->functionScope(),
                                   /* hasParameterExprs = */ false, alloc_, parseContext_));
 
     funbox->functionScopeBindings().set(*bindings);
 
     return result;
 }
 
-JS::Result<Ok>
-BinASTParser::parseAndUpdateCapturedNames()
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseAndUpdateCapturedNames()
 {
     // For the moment, we do not attempt to validate the list of captured names.
     AutoList guard(*tokenizer_);
     uint32_t length = 0;
 
     MOZ_TRY(tokenizer_->enterList(length, guard));
     RootedAtom name(cx_);
     for (uint32_t i = 0; i < length; ++i) {
         name = nullptr;
 
         MOZ_TRY(readString(&name));
     }
     MOZ_TRY(guard.done());
     return Ok();
 }
 
-JS::Result<Ok>
-BinASTParser::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind)
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind)
 {
     AutoList guard(*tokenizer_);
     uint32_t length = 0;
 
     MOZ_TRY(tokenizer_->enterList(length, guard));
     RootedAtom name(cx_);
     for (uint32_t i = 0; i < length; ++i) {
         name = nullptr;
@@ -243,34 +236,34 @@ BinASTParser::parseAndUpdateScopeNames(P
             return raiseError("Variable redeclaration");
 
         TRY(scope.addDeclaredName(parseContext_, ptr, name.get(), kind, tokenizer_->offset()));
     }
     MOZ_TRY(guard.done());
     return Ok();
 }
 
-JS::Result<Ok>
-BinASTParser::checkBinding(JSAtom* name)
+template<typename Tok> JS::Result<Ok>
+BinASTParser<Tok>::checkBinding(JSAtom* name)
 {
     // Check that the variable appears in the corresponding scope.
     ParseContext::Scope& scope =
         variableDeclarationKind == VariableDeclarationKind::Var
         ? parseContext_->varScope()
         : *parseContext_->innermostScope();
 
     auto ptr = scope.lookupDeclaredName(name->asPropertyName());
     if (!ptr)
         return raiseMissingVariableInAssertedScope(name);
 
     return Ok();
 }
 
-JS::Result<ParseNode*>
-BinASTParser::appendDirectivesToBody(ParseNode* body, ParseNode* directives)
+template<typename Tok> JS::Result<ParseNode*>
+BinASTParser<Tok>::appendDirectivesToBody(ParseNode* body, ParseNode* directives)
 {
     ParseNode* result = body;
     if (directives && directives->pn_count >= 1) {
         MOZ_ASSERT(directives->isArity(PN_LIST));
 
         // Convert directive list to a list of strings.
         TRY_DECL(prefix, factory_.newStatementList(directives->pn_head->pn_pos));
         for (ParseNode* iter = directives->pn_head; iter != nullptr; iter = iter->pn_next) {
@@ -291,120 +284,120 @@ BinASTParser::appendDirectivesToBody(Par
 #if defined(DEBUG)
         result->checkListConsistency();
 #endif // defined(DEBUG)
     }
 
     return result;
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseMissingVariableInAssertedScope(JSAtom* name)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseMissingVariableInAssertedScope(JSAtom* name)
 {
     // For the moment, we don't trust inputs sufficiently to put the name
     // in an error message.
     return raiseError("Missing variable in AssertedScope");
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseMissingDirectEvalInAssertedScope()
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseMissingDirectEvalInAssertedScope()
 {
     return raiseError("Direct call to `eval` was not declared in AssertedScope");
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseInvalidKind(const char* superKind, const BinKind kind)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseInvalidKind(const char* superKind, const BinKind kind)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, invalid kind %s", superKind, describeBinKind(kind)));
     return raiseError(out.string());
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseInvalidVariant(const char* kind, const BinVariant value)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseInvalidVariant(const char* kind, const BinVariant value)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, invalid variant '%s'", kind, describeBinVariant(value)));
 
     return raiseError(out.string());
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseMissingField(const char* kind, const BinField field)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseMissingField(const char* kind, const BinField field)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, missing field '%s'", kind, describeBinField(field)));
 
     return raiseError(out.string());
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseEmpty(const char* description)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseEmpty(const char* description)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("Empty %s", description));
 
     return raiseError(out.string());
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseOOM()
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseOOM()
 {
     ReportOutOfMemory(cx_);
     return cx_->alreadyReportedError();
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseError(BinKind kind, const char* description)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseError(BinKind kind, const char* description)
 {
     Sprinter out(cx_);
     TRY(out.init());
     TRY(out.printf("In %s, ", description));
     return tokenizer_->raiseError(out.string());
 }
 
-mozilla::GenericErrorResult<JS::Error&>
-BinASTParser::raiseError(const char* description)
+template<typename Tok> mozilla::GenericErrorResult<JS::Error&>
+BinASTParser<Tok>::raiseError(const char* description)
 {
     return tokenizer_->raiseError(description);
 }
 
-void
-BinASTParser::poison()
+template<typename Tok> void
+BinASTParser<Tok>::poison()
 {
     tokenizer_.reset();
 }
 
-void
-BinASTParser::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
+template<typename Tok> void
+BinASTParser<Tok>::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
 {
     ErrorMetadata metadata;
     metadata.filename = getFilename();
     metadata.lineNumber = 0;
     metadata.columnNumber = offset();
     ReportCompileError(cx_, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
 }
 
 bool
-BinASTParser::hasUsedName(HandlePropertyName name)
+BinASTParserBase::hasUsedName(HandlePropertyName name)
 {
     if (UsedNamePtr p = usedNames_.lookup(name))
         return p->value().isUsedInScript(parseContext_->scriptId());
 
     return false;
 }
 
 void
 TraceBinParser(JSTracer* trc, AutoGCRooter* parser)
 {
-    static_cast<BinASTParser*>(parser)->trace(trc);
+    static_cast<BinASTParserBase*>(parser)->trace(trc);
 }
 
 } // namespace frontend
 } // namespace js
 
 
 // #undef everything, to avoid collisions with unified builds.
 
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -26,61 +26,143 @@
 
 #include "js/GCHashTable.h"
 #include "js/GCVector.h"
 #include "js/Result.h"
 
 namespace js {
 namespace frontend {
 
-class BinASTParser;
-
-/**
- * The parser for a Binary AST.
- *
- * By design, this parser never needs to backtrack or look ahead. Errors are not
- * recoverable.
- */
-class BinASTParser : private JS::AutoGCRooter, public ErrorReporter
+class BinASTParserBase: private JS::AutoGCRooter
 {
   public:
-    using Tokenizer = BinTokenReaderMultipart;
-    using BinFields = Tokenizer::BinFields;
-    using Chars = Tokenizer::Chars;
-    using Names = JS::GCVector<JSString*, 8>;
-
-  public:
-    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
+    BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames)
         : AutoGCRooter(cx, BINPARSER)
-        , traceListHead_(nullptr)
-        , options_(options)
         , cx_(cx)
         , alloc_(alloc)
+        , traceListHead_(nullptr)
         , nodeAlloc_(cx, alloc)
+        , usedNames_(usedNames)
         , keepAtoms_(cx)
         , parseContext_(nullptr)
-        , usedNames_(usedNames)
         , factory_(cx, alloc, nullptr, SourceKind::Binary)
     {
-         cx_->frontendCollectionPool().addActiveCompilation();
+         cx->frontendCollectionPool().addActiveCompilation();
          tempPoolMark_ = alloc.mark();
     }
-    ~BinASTParser()
+    ~BinASTParserBase()
     {
         alloc_.release(tempPoolMark_);
 
         /*
          * The parser can allocate enormous amounts of memory for large functions.
          * Eagerly free the memory now (which otherwise won't be freed until the
          * next GC) to avoid unnecessary OOMs.
          */
         alloc_.freeAllIfHugeAndUnused();
 
         cx_->frontendCollectionPool().removeActiveCompilation();
     }
+  public:
+    // Names
+
+
+    bool hasUsedName(HandlePropertyName name);
+
+    // --- GC.
+
+    void trace(JSTracer* trc) {
+        ObjectBox::TraceList(trc, traceListHead_);
+    }
+
+
+  public:
+    ObjectBox* newObjectBox(JSObject* obj) {
+        MOZ_ASSERT(obj);
+
+        /*
+         * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
+         * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
+         * arenas containing the entries must be alive until we are done with
+         * scanning, parsing and code generation for the whole script or top-level
+         * function.
+         */
+
+         ObjectBox* objbox = alloc_.new_<ObjectBox>(obj, traceListHead_);
+         if (!objbox) {
+             ReportOutOfMemory(cx_);
+             return nullptr;
+        }
+
+        traceListHead_ = objbox;
+
+        return objbox;
+    }
+
+    ParseNode* allocParseNode(size_t size) {
+        MOZ_ASSERT(size == sizeof(ParseNode));
+        return static_cast<ParseNode*>(nodeAlloc_.allocNode());
+    }
+
+    JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
+
+    // Needs access to AutoGCRooter.
+    friend void TraceBinParser(JSTracer* trc, AutoGCRooter* parser);
+
+  protected:
+    JSContext* cx_;
+
+// ---- Memory-related stuff
+  protected:
+    LifoAlloc& alloc_;
+    ObjectBox* traceListHead_;
+    UsedNameTracker& usedNames_;
+  private:
+    LifoAlloc::Mark tempPoolMark_;
+    ParseNodeAllocator nodeAlloc_;
+
+    // Root atoms and objects allocated for the parse tree.
+    AutoKeepAtoms keepAtoms_;
+
+// ---- Parsing-related stuff
+  protected:
+    ParseContext* parseContext_;
+    FullParseHandler factory_;
+
+    friend class BinParseContext;
+
+};
+
+/**
+ * The parser for a Binary AST.
+ *
+ * By design, this parser never needs to backtrack or look ahead. Errors are not
+ * recoverable.
+ */
+template<typename Tok>
+class BinASTParser : public BinASTParserBase, public ErrorReporter
+{
+  public:
+    using Tokenizer = Tok;
+
+    using AutoList = typename Tokenizer::AutoList;
+    using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
+    using AutoTuple = typename Tokenizer::AutoTuple;
+    using BinFields = typename Tokenizer::BinFields;
+    using Chars = typename Tokenizer::Chars;
+
+  public:
+    BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options)
+        : BinASTParserBase(cx, alloc, usedNames)
+        , options_(options)
+    {
+    }
+    ~BinASTParser()
+    {
+    }
 
     /**
      * Parse a buffer, returning a node (which may be nullptr) in case of success
      * or Nothing() in case of error.
      *
      * The instance of `ParseNode` MAY NOT survive the `BinASTParser`. Indeed,
      * destruction of the `BinASTParser` will also destroy the `ParseNode`.
      *
@@ -141,64 +223,23 @@ class BinASTParser : private JS::AutoGCR
     // Read a string
     MOZ_MUST_USE JS::Result<Ok> readString(Chars& out);
     MOZ_MUST_USE JS::Result<Ok> readMaybeString(Maybe<Chars>& out);
     MOZ_MUST_USE JS::Result<Ok> readString(MutableHandleAtom out);
     MOZ_MUST_USE JS::Result<Ok> readMaybeString(MutableHandleAtom out);
     MOZ_MUST_USE JS::Result<bool> readBool();
     MOZ_MUST_USE JS::Result<double> readNumber();
 
+  private: // Implement ErrorReporter
+    const ReadOnlyCompileOptions& options_;
+
     const ReadOnlyCompileOptions& options() const override {
         return this->options_;
     }
 
-    // Names
-
-
-    bool hasUsedName(HandlePropertyName name);
-
-    // --- GC.
-
-    void trace(JSTracer* trc) {
-        ObjectBox::TraceList(trc, traceListHead_);
-    }
-
-
-  public:
-    ObjectBox* newObjectBox(JSObject* obj) {
-        MOZ_ASSERT(obj);
-
-        /*
-         * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
-         * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
-         * arenas containing the entries must be alive until we are done with
-         * scanning, parsing and code generation for the whole script or top-level
-         * function.
-         */
-
-         ObjectBox* objbox = alloc_.new_<ObjectBox>(obj, traceListHead_);
-         if (!objbox) {
-             ReportOutOfMemory(cx_);
-             return nullptr;
-        }
-
-        traceListHead_ = objbox;
-
-        return objbox;
-    }
-
-    ParseNode* allocParseNode(size_t size) {
-        MOZ_ASSERT(size == sizeof(ParseNode));
-        return static_cast<ParseNode*>(nodeAlloc_.allocNode());
-    }
-
-    JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
-
-  private: // Implement ErrorReporter
-
     virtual void lineAndColumnAt(size_t offset, uint32_t* line, uint32_t* column) const override {
         *line = 0;
         *column = offset;
     }
     virtual void currentLineAndColumn(uint32_t* line, uint32_t* column) const override {
         *line = 0;
         *column = offset();
     }
@@ -211,44 +252,45 @@ class BinASTParser : private JS::AutoGCR
     virtual bool hasTokenizationStarted() const override {
         return tokenizer_.isSome();
     }
     virtual void reportErrorNoOffsetVA(unsigned errorNumber, va_list args) override;
     virtual const char* getFilename() const override {
         return this->options_.filename();
     }
 
-    ObjectBox* traceListHead_;
-    const ReadOnlyCompileOptions& options_;
-    JSContext* cx_;
-    LifoAlloc& alloc_;
-    LifoAlloc::Mark tempPoolMark_;
-    ParseNodeAllocator nodeAlloc_;
-
-    // Root atoms and objects allocated for the parse tree.
-    AutoKeepAtoms keepAtoms_;
-
-    // The current ParseContext, holding directives, etc.
-    ParseContext* parseContext_;
-    UsedNameTracker& usedNames_;
     Maybe<Tokenizer> tokenizer_;
-    FullParseHandler factory_;
     VariableDeclarationKind variableDeclarationKind;
-
-    friend class BinParseContext;
     friend class AutoVariableDeclarationKind;
 
-    // Needs access to AutoGCRooter.
-    friend void TraceBinParser(JSTracer* trc, AutoGCRooter* parser);
+    // Helper class: Restore field `variableDeclarationKind` upon leaving a scope.
+    class MOZ_RAII AutoVariableDeclarationKind {
+        public:
+        explicit AutoVariableDeclarationKind(BinASTParser<Tok>* parser
+                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
+            parser_(parser),
+            kind(parser->variableDeclarationKind)
+        {
+            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        }
+        ~AutoVariableDeclarationKind() {
+            parser_->variableDeclarationKind = kind;
+        }
+        private:
+        BinASTParser<Tok>* parser_;
+        BinASTParser<Tok>::VariableDeclarationKind kind;
+        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+    };
 };
 
 class BinParseContext : public ParseContext
 {
   public:
-    BinParseContext(JSContext* cx, BinASTParser* parser, SharedContext* sc,
+    template<typename Tok>
+    BinParseContext(JSContext* cx, BinASTParser<Tok>* parser, SharedContext* sc,
         Directives* newDirectives)
         : ParseContext(cx, parser->parseContext_, sc, *parser,
                        parser->usedNames_, newDirectives, /* isFull = */ true)
     { }
 };
 
 
 } // namespace frontend
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -36,52 +36,23 @@ cpp:
         #include "vm/RegExpObject.h"
 
         #include "frontend/ParseContext-inl.h"
         #include "frontend/ParseNode-inl.h"
 
         namespace js {
         namespace frontend {
 
-        // FIXME: Check whether we are using all these aliases.
-        using AutoList = BinASTParser::Tokenizer::AutoList;
-        using AutoTaggedTuple = BinASTParser::Tokenizer::AutoTaggedTuple;
-        using AutoTuple = BinASTParser::Tokenizer::AutoTuple;
-        using BinFields = BinASTParser::Tokenizer::BinFields;
-        using Chars = BinASTParser::Tokenizer::Chars;
-        using NameBag = GCHashSet<JSString*>;
-        using Names = GCVector<JSString*, 8>;
-        using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
-
         // 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);
+        template<typename Tok, size_t N>
+        bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
+            return Tok::equals(left, right);
         }
 
-        // Helper class: Restore field `variableDeclarationKind` upon leaving a scope.
-        class MOZ_RAII AutoVariableDeclarationKind {
-          public:
-            explicit AutoVariableDeclarationKind(BinASTParser* parser
-                                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
-              parser_(parser),
-              kind(parser->variableDeclarationKind)
-            {
-                MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-            }
-            ~AutoVariableDeclarationKind() {
-                parser_->variableDeclarationKind = kind;
-            }
-          private:
-            BinASTParser* parser_;
-            BinASTParser::VariableDeclarationKind kind;
-            MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-        };
-
     footer: |
 
         } // namespace frontend
         } // namespace js
 
 hpp:
     # Rules for generating BinSource-class.h
     class:
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -49,18 +49,18 @@ readFull(JSContext* cx, const char* path
     js::Vector<uint8_t> intermediate(cx);
     readFull(path, intermediate);
 
     if (!buf.appendAll(intermediate))
         MOZ_CRASH("Couldn't read data");
 }
 
 // Invariant: `path` must end with directory separator.
-void
-runTestFromPath(JSContext* cx, const char* path)
+template<typename Tok> void
+runTestFromPath<Tok>(JSContext* cx, const char* path)
 {
     const char BIN_SUFFIX[] = ".binjs";
     const char TXT_SUFFIX[] = ".js";
     fprintf(stderr, "runTestFromPath: entering directory '%s'\n", path);
     const size_t pathlen = strlen(path);
 
 #if defined(XP_UNIX)
     MOZ_ASSERT(path[pathlen - 1] == '/');
@@ -111,17 +111,17 @@ runTestFromPath(JSContext* cx, const cha
                 MOZ_CRASH();
             if (!subPath.append(d_name, namlen))
                 MOZ_CRASH();
             // Append same directory separator.
             if (!subPath.append(path[pathlen - 1]))
                 MOZ_CRASH();
             if (!subPath.append(0))
                 MOZ_CRASH();
-            runTestFromPath(cx, subPath.begin());
+            runTestFromPath<Tok>(cx, subPath.begin());
             continue;
         }
 
         {
             // Make sure that we run GC between two tests. Otherwise, since we're running
             // everything from the same cx and without returning to JS, there is nothing
             // to deallocate the ASTs.
             JS::PrepareForFullGC(cx);
@@ -191,17 +191,17 @@ runTestFromPath(JSContext* cx, const cha
         // Parse binary file.
         CompileOptions binOptions(cx);
         binOptions.setFileAndLine(binPath.begin(), 0);
 
         js::frontend::UsedNameTracker binUsedNames(cx);
         if (!binUsedNames.init())
             MOZ_CRASH("Couldn't initialized binUsedNames");
 
-        js::frontend::BinASTParser binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
+        js::frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
 
         auto binParsed = binParser.parse(binSource); // Will be deallocated once `reader` goes out of scope.
         RootedValue binExn(cx);
         if (binParsed.isErr()) {
             // Save exception for more detailed error message, if necessary.
             if (!js::GetAndClearException(cx, &binExn))
                 MOZ_CRASH("Couldn't clear binExn");
         }
@@ -287,15 +287,15 @@ runTestFromPath(JSContext* cx, const cha
 #elif defined(XP_UNIX)
     if (closedir(dir) != 0)
         MOZ_CRASH("Could not close dir");
 #endif // defined(XP_WIN)
 }
 
 BEGIN_TEST(testBinASTReaderECMAScript2)
 {
-//    runTestFromPath(cx, "jsapi-tests/binast/parser/tester/");
-    runTestFromPath(cx, "jsapi-tests/binast/parser/multipart/");
+    runTestFromPath<BinTokenReaderTester>(cx, "jsapi-tests/binast/parser/tester/");
+    runTestFromPath<BinTokenReaderMultipart>(cx, "jsapi-tests/binast/parser/multipart/");
 
     return true;
 }
 END_TEST(testBinASTReaderECMAScript2)