Bug 1545751 - In BinAST, pass Context while parsing;r=arai
☠☠ backed out by 29be14061be5 ☠ ☠
authorDavid Teller <dteller@mozilla.com>
Wed, 24 Apr 2019 09:27:00 +0000
changeset 470623 a4847e3f634ec14d42e78cbf0be98314080726d4
parent 470622 792827e182fc7061261ecbe63c80e9cb490dae2c
child 470624 9d97144e67e9d2927c277ce81d25a009c44c4d70
push id83867
push userdteller@mozilla.com
push dateWed, 24 Apr 2019 09:29:31 +0000
treeherderautoland@a4847e3f634e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1545751
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1545751 - In BinAST, pass Context while parsing;r=arai The Context 0.1 format specifies that the (de)compression of nodes is determined by: - its node type; - its parent type; - the index in the parent node; - whether the node is an element of an array. This patch modifies the parser generator to pass the information during parsing. Differential Revision: https://phabricator.services.mozilla.com/D28534
js/src/frontend/BinAST.yaml
js/src/frontend/BinASTParser.cpp
js/src/frontend/BinASTParser.h
js/src/frontend/BinASTParserPerTokenizer.cpp
js/src/frontend/BinASTParserPerTokenizer.h
js/src/frontend/BinASTToken.h
js/src/frontend/BinASTTokenReaderBase.h
js/src/frontend/BinASTTokenReaderMultipart.cpp
js/src/frontend/BinASTTokenReaderMultipart.h
js/src/frontend/binast/src/main.rs
--- a/js/src/frontend/BinAST.yaml
+++ b/js/src/frontend/BinAST.yaml
@@ -113,16 +113,17 @@ hpp:
         using Base = BinASTParserPerTokenizer<Tok>;
 
         using Tokenizer = Tok;
 
         using BinASTFields = typename Tokenizer::BinASTFields;
         using AutoList = typename Tokenizer::AutoList;
         using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
         using Chars = typename Tokenizer::Chars;
+        using Context = typename BinASTTokenReaderBase::Context;
 
        public:
         // Auto-generated types.
         using AssertedDeclaredKind = binast::AssertedDeclaredKind;
         using BinaryOperator = binast::BinaryOperator;
         using CompoundAssignmentOperator = binast::CompoundAssignmentOperator;
         using UnaryOperator = binast::UnaryOperator;
         using UpdateOperator = binast::UpdateOperator;
@@ -292,16 +293,18 @@ hpp:
       // To generate this file, see the documentation in
       // js/src/frontend/binast/README.md.
 
       #ifndef frontend_BinASTToken_h
       #define frontend_BinASTToken_h
 
       #include <stddef.h>
 
+      #include "jstypes.h"
+
       /**
        * Definition of Binary AST tokens.
        *
        * In the Binary AST world, an AST is composed of nodes, where a node is
        * defined by:
        * - a Kind (see `BinASTKind`);
        * - a list of fields, where each field is:
        *    - a Name (see `BinASTField`);
@@ -620,17 +623,17 @@ Block:
     BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, statements));
 
 BreakStatement:
   fields:
     label:
       block:
         replace: |
           RootedAtom label(cx_);
-          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
+          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext));
 
   build: |
     if (label) {
       if (!IsIdentifier(label)) {
         return raiseError("Invalid identifier");
       }
     }
 
@@ -764,17 +767,17 @@ ConditionalExpression:
                    handler_.newConditional(test, consequent, alternate));
 
 ContinueStatement:
   fields:
     label:
       block:
         replace: |
           RootedAtom label(cx_);
-          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
+          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext));
 
   build: |
     if (label) {
       if (!IsIdentifier(label)) {
         return raiseError("ContinueStatement - Label MUST be an identifier");
       }
     }
 
@@ -1277,17 +1280,17 @@ LiteralPropertyName:
     }
 
 LiteralRegExpExpression:
   fields:
     flags:
       block:
         replace: |
           Chars flags(cx_);
-          MOZ_TRY(tokenizer_->readChars(flags));
+          MOZ_TRY(tokenizer_->readChars(flags, fieldContext));
   build: |
     RegExpFlags reflags = RegExpFlag::NoFlags;
     for (auto c : flags) {
       if (c == 'g' && !reflags.global()) {
         reflags |= RegExpFlag::Global;
       } else if (c == 'i' && !reflags.ignoreCase()) {
         reflags |= RegExpFlag::IgnoreCase;
       } else if (c == 'm' && !reflags.multiline()) {
--- a/js/src/frontend/BinASTParser.cpp
+++ b/js/src/frontend/BinASTParser.cpp
@@ -19,17 +19,17 @@
 #include "mozilla/Vector.h"
 
 #include "frontend/BinAST-macros.h"
 #include "frontend/BinASTTokenReaderMultipart.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseNode.h"
 #include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
+#include "js/RegExpFlags.h"  //  JS::RegExpFlag, JS::RegExpFlags
 #include "vm/RegExpObject.h"
 
 #include "frontend/ParseContext-inl.h"
 
 using JS::RegExpFlag;
 using JS::RegExpFlags;
 
 namespace js {
@@ -47,47 +47,47 @@ bool operator==(const typename Tok::Char
 /*
 AssertedMaybePositionalParameterName ::= AssertedParameterName
     AssertedPositionalParameterName
     AssertedRestParameterName
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result,
-                     parseSumAssertedMaybePositionalParameterName(
-                         start, kind, fields, scopeKind, positionalParams));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(
+      result, parseSumAssertedMaybePositionalParameterName(
+                  start, kind, fields, scopeKind, positionalParams, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseSumAssertedMaybePositionalParameterName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   Ok result;
   switch (kind) {
     case BinASTKind::AssertedParameterName:
       return raiseError(
           "FIXME: Not implemented yet in this preview release "
           "(AssertedParameterName)");
     case BinASTKind::AssertedPositionalParameterName:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAssertedPositionalParameterName(
-                      start, kind, fields, scopeKind, positionalParams));
+      MOZ_TRY_VAR(result, parseInterfaceAssertedPositionalParameterName(
+                              start, kind, fields, scopeKind, positionalParams,
+                              context));
       break;
     case BinASTKind::AssertedRestParameterName:
       return raiseError(
           "FIXME: Not implemented yet in this preview release "
           "(AssertedRestParameterName)");
     default:
       return raiseInvalidKind("AssertedMaybePositionalParameterName", kind);
   }
@@ -97,94 +97,101 @@ JS::Result<Ok> BinASTParser<Tok>::parseS
 /*
 AssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTarget() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTarget(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTarget(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result,
+                     parseSumAssignmentTarget(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayAssignmentTarget:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayAssignmentTarget(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::AssignmentTargetIdentifier:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
-                                                                   fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ObjectAssignmentTarget:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectAssignmentTarget(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(
+                              start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("AssignmentTarget", kind);
   }
   return result;
 }
 
 /*
 Binding ::= ArrayBinding
     BindingIdentifier
     ObjectBinding
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding(const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumBinding(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayBinding:
-      MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayBinding(start, kind, fields, context));
       break;
     case BinASTKind::BindingIdentifier:
-      MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
+                                                          context));
       break;
     case BinASTKind::ObjectBinding:
-      MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectBinding(start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("Binding", kind);
   }
   return result;
 }
 
 /*
@@ -217,151 +224,164 @@ Expression ::= ArrayExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseExpression() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayExpression(start, kind, fields, context));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAssignmentExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceAwaitExpression(start, kind, fields, context));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceBinaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceCallExpression(start, kind, fields, context));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceClassExpression(start, kind, fields, context));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceComputedMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceConditionalExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceEagerFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceIdentifierExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLazyFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralBooleanExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralBooleanExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralInfinityExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralInfinityExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNullExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::LiteralNumericExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNumericExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralRegExpExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralRegExpExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralStringExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralStringExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceNewExpression(start, kind, fields, context));
       break;
     case BinASTKind::NewTargetExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewTargetExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectExpression(start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceStaticMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::TemplateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceTemplateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
+                                                           context));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceThisExpression(start, kind, fields, context));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUnaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUpdateExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceYieldExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldStarExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldStarExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
+                                                            context));
       break;
     default:
       return raiseInvalidKind("Expression", kind);
   }
   return result;
 }
 
 /*
@@ -395,214 +415,230 @@ ExpressionOrSuper ::= ArrayExpression
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSuper() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSuper(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumExpressionOrSuper(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result,
+                     parseSumExpressionOrSuper(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpressionOrSuper(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayExpression(start, kind, fields, context));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAssignmentExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceAwaitExpression(start, kind, fields, context));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceBinaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceCallExpression(start, kind, fields, context));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceClassExpression(start, kind, fields, context));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceComputedMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceConditionalExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceEagerFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceIdentifierExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLazyFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralBooleanExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralBooleanExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralInfinityExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralInfinityExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNullExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::LiteralNumericExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNumericExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralRegExpExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralRegExpExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralStringExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralStringExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceNewExpression(start, kind, fields, context));
       break;
     case BinASTKind::NewTargetExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewTargetExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectExpression(start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceStaticMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::Super:
-      MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields, context));
       break;
     case BinASTKind::TemplateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceTemplateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
+                                                           context));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceThisExpression(start, kind, fields, context));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUnaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUpdateExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceYieldExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldStarExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldStarExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
+                                                            context));
       break;
     default:
       return raiseInvalidKind("ExpressionOrSuper", kind);
   }
   return result;
 }
 
 /*
 ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ForInOfBinding
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
-JS::Result<ParseNode*>
-BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(
-      result, parseSumForInOfBindingOrAssignmentTarget(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumForInOfBindingOrAssignmentTarget(
+                                 start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseSumForInOfBindingOrAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayAssignmentTarget:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayAssignmentTarget(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::AssignmentTargetIdentifier:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
-                                                                   fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ForInOfBinding:
-      MOZ_TRY_VAR(result, parseInterfaceForInOfBinding(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceForInOfBinding(start, kind, fields, context));
       break;
     case BinASTKind::ObjectAssignmentTarget:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectAssignmentTarget(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(
+                              start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
   }
   return result;
 }
 
 /*
@@ -611,228 +647,250 @@ ObjectProperty ::= DataProperty
     EagerMethod
     EagerSetter
     LazyGetter
     LazyMethod
     LazySetter
     ShorthandProperty
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseObjectProperty() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseObjectProperty(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumObjectProperty(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result,
+                     parseSumObjectProperty(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumObjectProperty(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::DataProperty:
-      MOZ_TRY_VAR(result, parseInterfaceDataProperty(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceDataProperty(start, kind, fields, context));
       break;
     case BinASTKind::EagerGetter:
-      MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceEagerGetter(start, kind, fields, context));
       break;
     case BinASTKind::EagerMethod:
-      MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceEagerMethod(start, kind, fields, context));
       break;
     case BinASTKind::EagerSetter:
-      MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceEagerSetter(start, kind, fields, context));
       break;
     case BinASTKind::LazyGetter:
-      MOZ_TRY_VAR(result, parseInterfaceLazyGetter(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceLazyGetter(start, kind, fields, context));
       break;
     case BinASTKind::LazyMethod:
-      MOZ_TRY_VAR(result, parseInterfaceLazyMethod(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceLazyMethod(start, kind, fields, context));
       break;
     case BinASTKind::LazySetter:
-      MOZ_TRY_VAR(result, parseInterfaceLazySetter(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceLazySetter(start, kind, fields, context));
       break;
     case BinASTKind::ShorthandProperty:
-      MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields,
+                                                          context));
       break;
     default:
       return raiseInvalidKind("ObjectProperty", kind);
   }
   return result;
 }
 
 /*
 Parameter ::= ArrayBinding
     BindingIdentifier
     BindingWithInitializer
     ObjectBinding
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseParameter() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseParameter(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumParameter(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayBinding:
-      MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayBinding(start, kind, fields, context));
       break;
     case BinASTKind::BindingIdentifier:
-      MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
+                                                          context));
       if (!pc_->positionalFormalParameterNames().append(
               result->template as<NameNode>().atom())) {
         return raiseOOM();
       }
       if (pc_->isFunctionBox()) {
         pc_->functionBox()->length++;
       }
       break;
     case BinASTKind::BindingWithInitializer:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceBindingWithInitializer(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceBindingWithInitializer(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ObjectBinding:
-      MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectBinding(start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("Parameter", kind);
   }
   return result;
 }
 
 /*
 Program ::= Module
     Script
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram(const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumProgram(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::Module:
-      MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields, context));
       break;
     case BinASTKind::Script:
-      MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("Program", kind);
   }
   return result;
 }
 
 /*
 PropertyName ::= ComputedPropertyName
     LiteralPropertyName
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parsePropertyName() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parsePropertyName(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumPropertyName(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result,
+                     parseSumPropertyName(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumPropertyName(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ComputedPropertyName:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceComputedPropertyName(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::LiteralPropertyName:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralPropertyName(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields,
+                                                            context));
       break;
     default:
       return raiseInvalidKind("PropertyName", kind);
   }
   return result;
 }
 
 /*
 SimpleAssignmentTarget ::= AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseSimpleAssignmentTarget() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseSimpleAssignmentTarget(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result,
-                     parseSumSimpleAssignmentTarget(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(
+      result, parseSumSimpleAssignmentTarget(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumSimpleAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::AssignmentTargetIdentifier:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
-                                                                   fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("SimpleAssignmentTarget", kind);
   }
   return result;
 }
 
 /*
@@ -866,155 +924,169 @@ SpreadElementOrExpression ::= ArrayExpre
     TemplateExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseSpreadElementOrExpression() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseSpreadElementOrExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result,
-                     parseSumSpreadElementOrExpression(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(
+      result, parseSumSpreadElementOrExpression(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumSpreadElementOrExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayExpression(start, kind, fields, context));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAssignmentExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceAwaitExpression(start, kind, fields, context));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceBinaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceCallExpression(start, kind, fields, context));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceClassExpression(start, kind, fields, context));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceComputedMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceConditionalExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceEagerFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceIdentifierExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLazyFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralBooleanExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralBooleanExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralInfinityExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralInfinityExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNullExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::LiteralNumericExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNumericExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralRegExpExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralRegExpExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralStringExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralStringExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceNewExpression(start, kind, fields, context));
       break;
     case BinASTKind::NewTargetExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewTargetExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectExpression(start, kind, fields, context));
       break;
     case BinASTKind::SpreadElement:
-      MOZ_TRY_VAR(result, parseInterfaceSpreadElement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceSpreadElement(start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceStaticMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::TemplateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceTemplateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
+                                                           context));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceThisExpression(start, kind, fields, context));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUnaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUpdateExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceYieldExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldStarExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldStarExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
+                                                            context));
       break;
     default:
       return raiseInvalidKind("SpreadElementOrExpression", kind);
   }
   return result;
 }
 
 /*
@@ -1039,330 +1111,369 @@ Statement ::= Block
     ThrowStatement
     TryCatchStatement
     TryFinallyStatement
     VariableDeclaration
     WhileStatement
     WithStatement
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseStatement() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseStatement(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
-
-  BINJS_MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
+
+  BINJS_MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::Block:
-      MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields, context));
       break;
     case BinASTKind::BreakStatement:
-      MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceBreakStatement(start, kind, fields, context));
       break;
     case BinASTKind::ClassDeclaration:
-      MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceClassDeclaration(start, kind, fields, context));
       break;
     case BinASTKind::ContinueStatement:
-      MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields,
+                                                          context));
       break;
     case BinASTKind::DebuggerStatement:
-      MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields,
+                                                          context));
       break;
     case BinASTKind::DoWhileStatement:
-      MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceDoWhileStatement(start, kind, fields, context));
       break;
     case BinASTKind::EagerFunctionDeclaration:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceEagerFunctionDeclaration(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(
+                              start, kind, fields, context));
       break;
     case BinASTKind::EmptyStatement:
-      MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceEmptyStatement(start, kind, fields, context));
       break;
     case BinASTKind::ExpressionStatement:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceExpressionStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::ForInStatement:
-      MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceForInStatement(start, kind, fields, context));
       break;
     case BinASTKind::ForOfStatement:
-      MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceForOfStatement(start, kind, fields, context));
       break;
     case BinASTKind::ForStatement:
-      MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceForStatement(start, kind, fields, context));
       break;
     case BinASTKind::IfStatement:
-      MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceIfStatement(start, kind, fields, context));
       break;
     case BinASTKind::LabelledStatement:
-      MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields,
+                                                          context));
       break;
     case BinASTKind::LazyFunctionDeclaration:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLazyFunctionDeclaration(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ReturnStatement:
-      MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceReturnStatement(start, kind, fields, context));
       break;
     case BinASTKind::SwitchStatement:
-      MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceSwitchStatement(start, kind, fields, context));
       break;
     case BinASTKind::SwitchStatementWithDefault:
-      MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind,
-                                                                   fields));
+      MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ThrowStatement:
-      MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceThrowStatement(start, kind, fields, context));
       break;
     case BinASTKind::TryCatchStatement:
-      MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields,
+                                                          context));
       break;
     case BinASTKind::TryFinallyStatement:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceTryFinallyStatement(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::VariableDeclaration:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceVariableDeclaration(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::WhileStatement:
-      MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceWhileStatement(start, kind, fields, context));
       break;
     case BinASTKind::WithStatement:
-      MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceWithStatement(start, kind, fields, context));
       break;
     default:
       return raiseInvalidKind("Statement", kind);
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseSumVariableDeclarationOrExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceArrayExpression(start, kind, fields, context));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAssignmentExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceAwaitExpression(start, kind, fields, context));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceBinaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceCallExpression(start, kind, fields, context));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceClassExpression(start, kind, fields, context));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceComputedMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceConditionalExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::EagerFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceEagerFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceIdentifierExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
+                                                             fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields));
+                              start, kind, fields, context));
       break;
     case BinASTKind::LazyFunctionExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLazyFunctionExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralBooleanExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralBooleanExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralInfinityExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralInfinityExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNullExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
+                                                              fields, context));
       break;
     case BinASTKind::LiteralNumericExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralNumericExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralRegExpExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralRegExpExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::LiteralStringExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceLiteralStringExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceNewExpression(start, kind, fields, context));
       break;
     case BinASTKind::NewTargetExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewTargetExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceObjectExpression(start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceStaticMemberExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
+                              start, kind, fields, context));
       break;
     case BinASTKind::TemplateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceTemplateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
+                                                           context));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceThisExpression(start, kind, fields, context));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUnaryExpression(start, kind, fields, context));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceUpdateExpression(start, kind, fields, context));
       break;
     case BinASTKind::VariableDeclaration:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceVariableDeclaration(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields,
+                                                            context));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
+      MOZ_TRY_VAR(result,
+                  parseInterfaceYieldExpression(start, kind, fields, context));
       break;
     case BinASTKind::YieldStarExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldStarExpression(start, kind, fields));
+      MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
+                                                            context));
       break;
     default:
       return raiseInvalidKind("VariableDeclarationOrExpression", kind);
   }
   return result;
 }
 
 // ----- Interfaces (autogenerated, by lexicographical order)
 // When fields have a non-trivial type, implementation is deanonymized and
 // delegated to another parser.
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ArrayAssignmentTarget)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayBinding(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (ArrayBinding)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ArrayExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Elements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
+  BINJS_MOZ_TRY_DECL(
+      elements, parseListOfOptionalSpreadElementOrExpression(fieldContext++));
 
   if (elements->empty()) {
     elements->setHasNonConstInitializer();
   }
   auto result = elements;
   return result;
 }
 
 /*
  interface AssertedBlockScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseAssertedBlockScope() {
+JS::Result<Ok> BinASTParser<Tok>::parseAssertedBlockScope(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBlockScope) {
     return raiseInvalidKind("AssertedBlockScope", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceAssertedBlockScope(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceAssertedBlockScope(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBlockScope(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBlockScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Block;
 
-  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
-
-  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
+  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1374,100 +1485,104 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 /*
  interface AssertedBoundName : Node {
     [IdentifierName] string name;
     bool isCaptured;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundName(
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBoundName) {
     return raiseInvalidKind("AssertedBoundName", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(
-      result, parseInterfaceAssertedBoundName(start, kind, fields, scopeKind));
+  BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundName(
+                                 start, kind, fields, scopeKind, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBoundName);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Name,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const bool allowDuplicateName = false;
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
-
-  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool(fieldContext++));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
 
 /*
  interface AssertedBoundNamesScope : Node {
     FrozenArray<AssertedBoundName> boundNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundNamesScope() {
+JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundNamesScope(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBoundNamesScope) {
     return raiseInvalidKind("AssertedBoundNamesScope", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(
-      result, parseInterfaceAssertedBoundNamesScope(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundNamesScope(
+                                 start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundNamesScope(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBoundNamesScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::BoundNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Catch;
 
-  MOZ_TRY(parseListOfAssertedBoundName(scopeKind));
-
-  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
+  MOZ_TRY(parseListOfAssertedBoundName(scopeKind, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1480,58 +1595,59 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
  interface AssertedDeclaredName : Node {
     [IdentifierName] string name;
     AssertedDeclaredKind kind;
     bool isCaptured;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedDeclaredName(
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedDeclaredName) {
     return raiseInvalidKind("AssertedDeclaredName", kind);
   }
   const auto start = tokenizer_->offset();
   BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedDeclaredName(
-                                 start, kind, fields, scopeKind));
+                                 start, kind, fields, scopeKind, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedDeclaredName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedDeclaredName);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::Name, BinASTField::Kind,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const bool allowDuplicateName = false;
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
-
-  BINJS_MOZ_TRY_DECL(kind_, parseAssertedDeclaredKind());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(kind_, parseAssertedDeclaredKind(fieldContext++));
   if (kind_ == AssertedDeclaredKind::NonConstLexical) {
     return raiseError("Let is not supported in this preview release");
   }
   if (kind_ == AssertedDeclaredKind::ConstLexical) {
     return raiseError("Const is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool(fieldContext++));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getDeclaredScope(scopeKind, kind_, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
@@ -1540,86 +1656,90 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
  interface AssertedParameterScope : Node {
     FrozenArray<AssertedMaybePositionalParameterName> paramNames;
     bool hasDirectEval;
     bool isSimpleParameterList;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedParameterScope(
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedParameterScope) {
     return raiseInvalidKind("AssertedParameterScope", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedParameterScope(
-                                 start, kind, fields, positionalParams));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceAssertedParameterScope(start, kind, fields,
+                                                   positionalParams, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedParameterScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedParameterScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::ParamNames,
                                           BinASTField::HasDirectEval,
                                           BinASTField::IsSimpleParameterList};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Parameter;
 
-  MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(scopeKind,
-                                                          positionalParams));
-
-  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
+  MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(
+      scopeKind, positionalParams, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
-  BINJS_MOZ_TRY_DECL(isSimpleParameterList, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isSimpleParameterList,
+                     tokenizer_->readBool(fieldContext++));
   (void)isSimpleParameterList;
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
   }
   auto result = Ok();
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedPositionalParameterName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedPositionalParameterName);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::Index, BinASTField::Name,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   bool allowDuplicateName = !pc_->sc()->strict();
 
-  BINJS_MOZ_TRY_DECL(index, tokenizer_->readUnsignedLong());
+  BINJS_MOZ_TRY_DECL(index, tokenizer_->readUnsignedLong(fieldContext++));
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
   // `positionalParams` vector can be shorter than the actual
   // parameter length. Resize on demand.
   // (see also ListOfAssertedMaybePositionalParameterName)
   size_t prevLength = positionalParams.get().length();
   if (index >= prevLength) {
     // This is implementation limit, which is not in the spec.
     if (index >= ARGNO_LIMIT - 1) {
       return raiseError("AssertedPositionalParameterName.index is too big");
@@ -1632,66 +1752,69 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
   }
 
   if (positionalParams.get()[index]) {
     return raiseError(
         "AssertedPositionalParameterName has duplicate entry for the same "
         "index");
   }
   positionalParams.get()[index] = name;
-  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool(fieldContext++));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
 
 /*
  interface AssertedScriptGlobalScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseAssertedScriptGlobalScope() {
+JS::Result<Ok> BinASTParser<Tok>::parseAssertedScriptGlobalScope(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedScriptGlobalScope) {
     return raiseInvalidKind("AssertedScriptGlobalScope", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(
-      result, parseInterfaceAssertedScriptGlobalScope(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedScriptGlobalScope(
+                                 start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedScriptGlobalScope(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedScriptGlobalScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Global;
 
-  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
-
-  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
+  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1702,129 +1825,139 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 
 /*
  interface AssertedVarScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseAssertedVarScope() {
+JS::Result<Ok> BinASTParser<Tok>::parseAssertedVarScope(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedVarScope) {
     return raiseInvalidKind("AssertedVarScope", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceAssertedVarScope(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceAssertedVarScope(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedVarScope(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedVarScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Var;
 
-  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
-
-  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
+  MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
   }
   auto result = Ok();
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceAssignmentExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssignmentExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Binding,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget());
-
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newAssignment(ParseNodeKind::AssignExpr,
                                                 binding, expression));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::AssignmentTargetIdentifier);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
 
   BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
                                pc_->innermostScope()->id()));
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceAwaitExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (AwaitExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBinaryExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::BinaryExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Operator, BinASTField::Left, BinASTField::Right};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(operator_, parseBinaryOperator());
-
-  BINJS_MOZ_TRY_DECL(left, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(right, parseExpression());
+  BINJS_MOZ_TRY_DECL(operator_, parseBinaryOperator(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(left, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(right, parseExpression(fieldContext++));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case BinaryOperator::Comma:
       pnk = ParseNodeKind::CommaExpr;
       break;
     case BinaryOperator::LogicalOr:
       pnk = ParseNodeKind::OrExpr;
@@ -1917,120 +2050,128 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 }
 
 /*
  interface BindingIdentifier : Node {
     [IdentifierName] string name;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseBindingIdentifier() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseBindingIdentifier(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::BindingIdentifier) {
     return raiseInvalidKind("BindingIdentifier", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceBindingIdentifier(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceBindingIdentifier(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBindingIdentifier(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::BindingIdentifier);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBindingWithInitializer(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(BindingWithInitializer)");
 }
 
 /*
  interface Block : Node {
     AssertedBlockScope scope;
     FrozenArray<Statement> statements;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseBlock() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseBlock(const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::Block) {
     return raiseInvalidKind("Block", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBlock(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::Block);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Scope,
                                           BinASTField::Statements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::Block);
   ParseContext::Scope currentScope(cx_, pc_, usedNames_);
   BINJS_TRY(currentScope.init(pc_));
 
-  MOZ_TRY(parseAssertedBlockScope());
-
-  BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());
+  MOZ_TRY(parseAssertedBlockScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(statements, parseListOfStatement(fieldContext++));
 
   MOZ_TRY(checkClosedVars(currentScope));
   BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, pc_));
   BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, statements));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBreakStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::BreakStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Label};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
+  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext));
 
   if (label) {
     if (!IsIdentifier(label)) {
       return raiseError("Invalid identifier");
     }
   }
 
   auto validity =
@@ -2049,29 +2190,31 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY_DECL(result, handler_.newBreakStatement(
                              label ? label->asPropertyName() : nullptr,
                              tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceCallExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::CallExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Callee,
                                           BinASTField::Arguments};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper());
-
-  BINJS_MOZ_TRY_DECL(arguments, parseArguments());
+  BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(arguments, parseArguments(fieldContext++));
 
   auto op = JSOP_CALL;
 
   // Try to optimize funcall and funapply at the bytecode level
   if (PropertyName* prop = handler_.maybeDottedProperty(callee)) {
     if (prop == cx_->names().apply) {
       op = JSOP_FUNAPPLY;
       if (pc_->isFunctionBox()) {
@@ -2102,95 +2245,104 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 /*
  interface CatchClause : Node {
     AssertedBoundNamesScope bindingScope;
     Binding binding;
     Block body;
  }
 */
 template <typename Tok>
-JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseCatchClause() {
+JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseCatchClause(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::CatchClause) {
     return raiseInvalidKind("CatchClause", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceCatchClause(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result,
+                     parseInterfaceCatchClause(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseInterfaceCatchClause(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::CatchClause);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::BindingScope, BinASTField::Binding, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::Catch);
   ParseContext::Scope currentScope(cx_, pc_, usedNames_);
   BINJS_TRY(currentScope.init(pc_));
 
-  MOZ_TRY(parseAssertedBoundNamesScope());
-
-  BINJS_MOZ_TRY_DECL(binding, parseBinding());
+  MOZ_TRY(parseAssertedBoundNamesScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
   if (!currentScope.lookupDeclaredName(
           binding->template as<NameNode>().atom())) {
     return raiseError("Missing catch variable in scope");
   }
-  BINJS_MOZ_TRY_DECL(body, parseBlock());
+  BINJS_MOZ_TRY_DECL(body, parseBlock(fieldContext++));
 
   MOZ_TRY(checkClosedVars(currentScope));
   BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, pc_));
   BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, body));
   BINJS_TRY(handler_.setupCatchScope(result, binding, body));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceClassDeclaration(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (ClassDeclaration)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceClassExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (ClassExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::CompoundAssignmentExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Operator, BinASTField::Binding, BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());
-
-  BINJS_MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget());
-
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(operator_,
+                     parseCompoundAssignmentOperator(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case CompoundAssignmentOperator::PlusAssign:
       pnk = ParseNodeKind::AddAssignExpr;
       break;
     case CompoundAssignmentOperator::MinusAssign:
       pnk = ParseNodeKind::SubAssignExpr;
@@ -2228,99 +2380,108 @@ BinASTParser<Tok>::parseInterfaceCompoun
   }
   BINJS_TRY_DECL(result, handler_.newAssignment(pnk, binding, expression));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ComputedMemberAssignmentTarget);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
-
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
                                                      tokenizer_->offset()));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceComputedMemberExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ComputedMemberExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
-
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
                                                      tokenizer_->offset()));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceComputedPropertyName(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ComputedPropertyName)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceConditionalExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ConditionalExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(consequent, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(alternate, parseExpression());
+  BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(consequent, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(alternate, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newConditional(test, consequent, alternate));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceContinueStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ContinueStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Label};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
+  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext));
 
   if (label) {
     if (!IsIdentifier(label)) {
       return raiseError("ContinueStatement - Label MUST be an identifier");
     }
   }
 
   auto validity =
@@ -2339,29 +2500,31 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY_DECL(result, handler_.newContinueStatement(
                              label ? label->asPropertyName() : nullptr,
                              tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDataProperty(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::DataProperty);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Name,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName());
-
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   if (!handler_.isUsableAsObjectPropertyName(name)) {
     return raiseError("DataProperty key kind");
   }
 
   ParseNode* result;
   if (name->template is<NameNode>() &&
       name->template as<NameNode>().atom() == cx_->names().proto) {
@@ -2371,130 +2534,141 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     BINJS_TRY_VAR(result, handler_.newObjectMethodOrPropertyDefinition(
                               name, expression, AccessorType::None));
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDebuggerStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (DebuggerStatement)");
 }
 
 /*
  interface Directive : Node {
     string rawValue;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseDirective() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseDirective(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::Directive) {
     return raiseInvalidKind("Directive", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceDirective(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result,
+                     parseInterfaceDirective(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDirective(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::Directive);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::RawValue};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom rawValue(cx_);
-  MOZ_TRY_VAR(rawValue, tokenizer_->readAtom());
+  MOZ_TRY_VAR(rawValue, tokenizer_->readAtom(fieldContext++));
 
   TokenPos pos = tokenizer_->pos(start);
   BINJS_TRY_DECL(result, handler_.newStringLiteral(rawValue, pos));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDoWhileStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::DoWhileStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   BINJS_TRY_DECL(
       result, handler_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(EagerArrowExpressionWithExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithFunctionBody(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(EagerArrowExpressionWithFunctionBody)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceEagerFunctionDeclaration(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerFunctionDeclaration);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[6] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Statement;
 
-  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2510,54 +2684,57 @@ BinASTParser<Tok>::parseInterfaceEagerFu
   BINJS_TRY(funpc.init());
   pc_->functionScope().useAsVarScope(pc_);
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
-  MOZ_TRY(parseFunctionOrMethodContents(length, &params, &body));
+  MOZ_TRY(
+      parseFunctionOrMethodContents(length, &params, &body, fieldContext++));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(result,
                      buildFunction(start, kind, name, params, bodyScope));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerFunctionExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerFunctionExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[6] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Expression;
 
-  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2573,46 +2750,49 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(funpc.init());
   pc_->functionScope().useAsVarScope(pc_);
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
-  MOZ_TRY(parseFunctionExpressionContents(length, &params, &body));
+  MOZ_TRY(
+      parseFunctionExpressionContents(length, &params, &body, fieldContext++));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(result,
                      buildFunction(start, kind, name, params, bodyScope));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerGetter);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Name, BinASTField::Directives, BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Setter;
   const bool isGenerator = false;
   const bool isAsync = false;
   const auto accessorType = AccessorType::Getter;
   const uint32_t length = 0;
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2628,57 +2808,59 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(funpc.init());
   pc_->functionScope().useAsVarScope(pc_);
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
-  MOZ_TRY(parseGetterContents(length, &params, &body));
+  MOZ_TRY(parseGetterContents(length, &params, &body, fieldContext++));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(method,
                      buildFunction(start, kind, name, params, bodyScope));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerMethod);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[6] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Method;
   const auto accessorType = AccessorType::None;
 
-  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2694,50 +2876,53 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(funpc.init());
   pc_->functionScope().useAsVarScope(pc_);
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
-  MOZ_TRY(parseFunctionOrMethodContents(length, &params, &body));
+  MOZ_TRY(
+      parseFunctionOrMethodContents(length, &params, &body, fieldContext++));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(method,
                      buildFunction(start, kind, name, params, bodyScope));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerSetter);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[4] = {
       BinASTField::Name, BinASTField::Length, BinASTField::Directives,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Setter;
   const bool isGenerator = false;
   const bool isAsync = false;
   const auto accessorType = AccessorType::Setter;
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2753,73 +2938,78 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(funpc.init());
   pc_->functionScope().useAsVarScope(pc_);
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
-  MOZ_TRY(parseSetterContents(length, &params, &body));
+  MOZ_TRY(parseSetterContents(length, &params, &body, fieldContext++));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(method,
                      buildFunction(start, kind, name, params, bodyScope));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEmptyStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::EmptyStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
   MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
   BINJS_TRY_DECL(result, handler_.newEmptyStatement(tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceExpressionStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ExpressionStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newExprStatement(expression, tokenizer_->offset()));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForInOfBinding(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ForInOfBinding);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Kind,
                                           BinASTField::Binding};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   AutoVariableDeclarationKind kindGuard(this);
 
-  BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
-
-  BINJS_MOZ_TRY_DECL(binding, parseBinding());
+  BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
 
   // Restored by `kindGuard`.
   variableDeclarationKind_ = kind_;
   MOZ_TRY(
       checkBinding(binding->template as<NameNode>().atom()->asPropertyName()));
   ParseNodeKind pnk;
   switch (kind_) {
     case VariableDeclarationKind::Var:
@@ -2833,38 +3023,41 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY_DECL(result,
                  handler_.newDeclarationList(pnk, tokenizer_->pos(start)));
   handler_.addList(result, binding);
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForInStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ForInStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::Left, BinASTField::Right,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::ForInLoop);
 
   // Implicit scope around the `for`, used to store `for (let x in  ...)`
   // or `for (const x in ...)`-style declarations. Detail on the
   // declaration is stored as part of `scope`.
   ParseContext::Scope scope(cx_, pc_, usedNames_);
   BINJS_TRY(scope.init(pc_));
 
-  BINJS_MOZ_TRY_DECL(left, parseForInOfBindingOrAssignmentTarget());
-
-  BINJS_MOZ_TRY_DECL(right, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(left,
+                     parseForInOfBindingOrAssignmentTarget(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(right, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   BINJS_TRY_DECL(forHead,
                  handler_.newForInOrOfHead(ParseNodeKind::ForIn, left, right,
                                            tokenizer_->pos(start)));
   ParseNode* result;
   BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
                                                  /* iflags = */ 0));
 
@@ -2872,48 +3065,52 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, pc_));
     BINJS_TRY_VAR(result, handler_.newLexicalScope(*bindings, result));
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForOfStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (ForOfStatement)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ForStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[4] = {BinASTField::Init, BinASTField::Test,
                                           BinASTField::Update,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::ForLoop);
 
   // Implicit scope around the `for`, used to store `for (let x; ...; ...)`
   // or `for (const x; ...; ...)`-style declarations. Detail on the
   // declaration is stored as part of `BINJS_Scope`.
   ParseContext::Scope scope(cx_, pc_, usedNames_);
   BINJS_TRY(scope.init(pc_));
 
-  BINJS_MOZ_TRY_DECL(init, parseOptionalVariableDeclarationOrExpression());
-
-  BINJS_MOZ_TRY_DECL(test, parseOptionalExpression());
-
-  BINJS_MOZ_TRY_DECL(update, parseOptionalExpression());
-
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(
+      init, parseOptionalVariableDeclarationOrExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(test, parseOptionalExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(update, parseOptionalExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   BINJS_TRY_DECL(
       forHead, handler_.newForHead(init, test, update, tokenizer_->pos(start)));
   ParseNode* result;
   BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
                                                  /* iflags = */ 0));
 
   if (!scope.isEmpty()) {
@@ -2925,48 +3122,51 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 /*
  interface FormalParameters : Node {
     FrozenArray<Parameter> items;
     Binding? rest;
  }
 */
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseFormalParameters() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseFormalParameters(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::FormalParameters) {
     return raiseInvalidKind("FormalParameters", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceFormalParameters(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceFormalParameters(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseInterfaceFormalParameters(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::FormalParameters);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Items,
                                           BinASTField::Rest};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(items, parseListOfParameter());
-
-  BINJS_MOZ_TRY_DECL(rest, parseOptionalBinding());
+  BINJS_MOZ_TRY_DECL(items, parseListOfParameter(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(rest, parseOptionalBinding(fieldContext++));
 
   auto result = items;
   if (rest) {
     return raiseError(
         "Rest parameter is not supported in this preview release");
   }
   return result;
 }
@@ -2978,71 +3178,75 @@ JS::Result<ListNode*> BinASTParser<Tok>:
     AssertedParameterScope parameterScope;
     FormalParameters params;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseFunctionExpressionContents(
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::FunctionExpressionContents) {
     return raiseInvalidKind("FunctionExpressionContents", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceFunctionExpressionContents(
-                         start, kind, fields, funLength, paramsOut, bodyOut));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceFunctionExpressionContents(
+                  start, kind, fields, funLength, paramsOut, bodyOut, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceFunctionExpressionContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::FunctionExpressionContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[6] = {BinASTField::IsFunctionNameCaptured,
                                           BinASTField::IsThisCaptured,
                                           BinASTField::ParameterScope,
                                           BinASTField::Params,
                                           BinASTField::BodyScope,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(isFunctionNameCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isFunctionNameCaptured,
+                     tokenizer_->readBool(fieldContext++));
   // Per spec, isFunctionNameCaptured can be true for anonymous
   // function.  Check isFunctionNameCaptured only for named
   // function.
   if (pc_->functionBox()->function()->isNamedLambda() &&
       isFunctionNameCaptured) {
     captureFunctionName();
   }
-  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
-  MOZ_TRY(parseAssertedParameterScope(&positionalParams));
-
-  BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
+  MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(params, parseFormalParameters(fieldContext++));
   MOZ_TRY(checkFunctionLength(funLength));
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope());
-
-  BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
+  MOZ_TRY(parseAssertedVarScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
@@ -3051,60 +3255,63 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
     AssertedParameterScope parameterScope;
     FormalParameters params;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseFunctionOrMethodContents(
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::FunctionOrMethodContents) {
     return raiseInvalidKind("FunctionOrMethodContents", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceFunctionOrMethodContents(
-                         start, kind, fields, funLength, paramsOut, bodyOut));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceFunctionOrMethodContents(
+                  start, kind, fields, funLength, paramsOut, bodyOut, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceFunctionOrMethodContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::FunctionOrMethodContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[5] = {
       BinASTField::IsThisCaptured, BinASTField::ParameterScope,
       BinASTField::Params, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
-  MOZ_TRY(parseAssertedParameterScope(&positionalParams));
-
-  BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
+  MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(params, parseFormalParameters(fieldContext++));
   MOZ_TRY(checkFunctionLength(funLength));
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope());
-
-  BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
+  MOZ_TRY(parseAssertedVarScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
@@ -3112,202 +3319,217 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
     bool isThisCaptured;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseGetterContents(uint32_t funLength,
                                                       ListNode** paramsOut,
-                                                      ListNode** bodyOut) {
+                                                      ListNode** bodyOut,
+                                                      const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::GetterContents) {
     return raiseInvalidKind("GetterContents", kind);
   }
   const auto start = tokenizer_->offset();
   BINJS_MOZ_TRY_DECL(
       result, parseInterfaceGetterContents(start, kind, fields, funLength,
-                                           paramsOut, bodyOut));
+                                           paramsOut, bodyOut, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceGetterContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::GetterContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::IsThisCaptured, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
-  MOZ_TRY(parseAssertedVarScope());
+  MOZ_TRY(parseAssertedVarScope(fieldContext++));
 
   BINJS_TRY_DECL(params, handler_.newParamsBody(tokenizer_->pos(start)));
-  BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
  interface IdentifierExpression : Node {
     [IdentifierName] string name;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseIdentifierExpression() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseIdentifierExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::IdentifierExpression) {
     return raiseInvalidKind("IdentifierExpression", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceIdentifierExpression(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceIdentifierExpression(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceIdentifierExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::IdentifierExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
 
   BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
                                pc_->innermostScope()->id()));
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceIfStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::IfStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(consequent, parseStatement());
-
-  BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement());
+  BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(consequent, parseStatement(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newIfStatement(start, test, consequent, alternate));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLabelledStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LabelledStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Label,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readAtom());
+  MOZ_TRY_VAR(label, tokenizer_->readAtom(fieldContext++));
   if (!IsIdentifier(label)) {
     return raiseError("Invalid identifier");
   }
   ParseContext::LabelStatement stmt(pc_, label);
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newLabeledStatement(label->asPropertyName(),
                                                       body, start));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(LazyArrowExpressionWithExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithFunctionBody(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(LazyArrowExpressionWithFunctionBody)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyFunctionDeclaration(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LazyFunctionDeclaration);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[7] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::ContentsSkip,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Statement;
 
-  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
-
-  BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
+  BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(contentsSkip,
+                     tokenizer_->readSkippableSubTree(fieldContext++));
   // Don't parse the contents until we delazify.
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax, name));
@@ -3334,45 +3556,48 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   funbox->function()->initLazyScript(lazy);
 
   BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyFunctionExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LazyFunctionExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[7] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::ContentsSkip,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Expression;
 
-  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
-
-  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
-
-  BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
+  BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(contentsSkip,
+                     tokenizer_->readSkippableSubTree(fieldContext++));
   // Don't parse the contents until we delazify.
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax, name));
@@ -3399,136 +3624,149 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   funbox->function()->initLazyScript(lazy);
 
   BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyGetter(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazyGetter)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyMethod(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazyMethod)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazySetter(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazySetter)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralBooleanExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(value, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(value, tokenizer_->readBool(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newBooleanLiteral(value, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLiteralInfinityExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(LiteralInfinityExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralNullExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralNullExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
   MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
   BINJS_TRY_DECL(result, handler_.newNullLiteral(tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLiteralNumericExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralNumericExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(value, tokenizer_->readDouble());
+  BINJS_MOZ_TRY_DECL(value, tokenizer_->readDouble(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newNumber(value, DecimalPoint::HasDecimal,
                                             tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralPropertyName(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralPropertyName);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom value(cx_);
-  MOZ_TRY_VAR(value, tokenizer_->readAtom());
+  MOZ_TRY_VAR(value, tokenizer_->readAtom(fieldContext++));
 
   ParseNode* result;
   uint32_t index;
   if (value->isIndex(&index)) {
     BINJS_TRY_VAR(result,
                   handler_.newNumber(index, NoDecimal,
                                      TokenPos(start, tokenizer_->offset())));
   } else {
     BINJS_TRY_VAR(result, handler_.newObjectLiteralPropertyName(
                               value, tokenizer_->pos(start)));
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralRegExpExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralRegExpExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Pattern,
                                           BinASTField::Flags};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom pattern(cx_);
-  MOZ_TRY_VAR(pattern, tokenizer_->readAtom());
+  MOZ_TRY_VAR(pattern, tokenizer_->readAtom(fieldContext++));
   Chars flags(cx_);
-  MOZ_TRY(tokenizer_->readChars(flags));
+  MOZ_TRY(tokenizer_->readChars(flags, fieldContext));
 
   RegExpFlags reflags = RegExpFlag::NoFlags;
   for (auto c : flags) {
     if (c == 'g' && !reflags.global()) {
       reflags |= RegExpFlag::Global;
     } else if (c == 'i' && !reflags.ignoreCase()) {
       reflags |= RegExpFlag::IgnoreCase;
     } else if (c == 'm' && !reflags.multiline()) {
@@ -3548,143 +3786,157 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   BINJS_TRY_DECL(result,
                  handler_.newRegExp(reobj, tokenizer_->pos(start), *this));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralStringExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralStringExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom value(cx_);
-  MOZ_TRY_VAR(value, tokenizer_->readAtom());
+  MOZ_TRY_VAR(value, tokenizer_->readAtom(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newStringLiteral(value, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceModule(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (Module)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::NewExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Callee,
                                           BinASTField::Arguments};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(callee, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(arguments, parseArguments());
+  BINJS_MOZ_TRY_DECL(callee, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(arguments, parseArguments(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newNewExpression(tokenizer_->pos(start).begin, callee,
                                            arguments, /* isSpread = */ false));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewTargetExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(NewTargetExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ObjectAssignmentTarget)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectBinding(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (ObjectBinding)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ObjectExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Properties};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(properties, parseListOfObjectProperty());
+  BINJS_MOZ_TRY_DECL(properties, parseListOfObjectProperty(fieldContext++));
 
   auto result = properties;
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceReturnStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ReturnStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   if (!pc_->isFunctionBox()) {
     // Return statements are permitted only inside functions.
     return raiseInvalidKind("Toplevel Statement", kind);
   }
 
   pc_->functionBox()->usesReturn = true;
 
-  BINJS_MOZ_TRY_DECL(expression, parseOptionalExpression());
+  BINJS_MOZ_TRY_DECL(expression, parseOptionalExpression(fieldContext++));
 
   BINJS_TRY_DECL(
       result, handler_.newReturnStatement(expression, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceScript(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::Script);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Scope, BinASTField::Directives, BinASTField::Statements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  MOZ_TRY(parseAssertedScriptGlobalScope());
-
-  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
+  MOZ_TRY(parseAssertedScriptGlobalScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
   forceStrictIfNecessary(pc_->sc(), directives);
-  BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());
+  BINJS_MOZ_TRY_DECL(statements, parseListOfStatement(fieldContext++));
 
   MOZ_TRY(checkClosedVars(pc_->varScope()));
   MOZ_TRY(prependDirectivesToBody(/* body = */ statements, directives));
   auto result = statements;
   return result;
 }
 
 /*
@@ -3694,284 +3946,309 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     Parameter param;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseSetterContents(uint32_t funLength,
                                                       ListNode** paramsOut,
-                                                      ListNode** bodyOut) {
+                                                      ListNode** bodyOut,
+                                                      const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SetterContents) {
     return raiseInvalidKind("SetterContents", kind);
   }
   const auto start = tokenizer_->offset();
   BINJS_MOZ_TRY_DECL(
       result, parseInterfaceSetterContents(start, kind, fields, funLength,
-                                           paramsOut, bodyOut));
+                                           paramsOut, bodyOut, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceSetterContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::SetterContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[5] = {
       BinASTField::IsThisCaptured, BinASTField::ParameterScope,
       BinASTField::Param, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
+  BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
-  MOZ_TRY(parseAssertedParameterScope(&positionalParams));
-
-  BINJS_MOZ_TRY_DECL(param, parseParameter());
+  MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(param, parseParameter(fieldContext++));
   BINJS_TRY_DECL(params, handler_.newParamsBody(param->pn_pos));
   handler_.addList(params, param);
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope());
-
-  BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
+  MOZ_TRY(parseAssertedVarScope(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceShorthandProperty(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ShorthandProperty);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(name, parseIdentifierExpression());
+  BINJS_MOZ_TRY_DECL(name, parseIdentifierExpression(fieldContext++));
 
   MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
   MOZ_ASSERT(!handler_.isUsableAsObjectPropertyName(name));
   BINJS_TRY_DECL(propName, handler_.newObjectLiteralPropertyName(
                                name->template as<NameNode>().name(),
                                tokenizer_->pos(start)));
 
   BINJS_TRY_DECL(result,
                  handler_.newShorthandPropertyDefinition(propName, name));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSpreadElement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (SpreadElement)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::StaticMemberAssignmentTarget);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Property};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   size_t nameStart;
 
-  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
+  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
+
   RootedAtom property(cx_);
   {
     nameStart = tokenizer_->offset();
-    MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());
+    MOZ_TRY_VAR(property, tokenizer_->readPropertyKey(fieldContext++));
   }
 
   BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
                                                 tokenizer_->pos(nameStart)));
   BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceStaticMemberExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::StaticMemberExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Property};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   size_t nameStart;
 
-  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
+  BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
+
   RootedAtom property(cx_);
   {
     nameStart = tokenizer_->offset();
-    MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());
+    MOZ_TRY_VAR(property, tokenizer_->readPropertyKey(fieldContext++));
   }
 
   BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
                                                 tokenizer_->pos(nameStart)));
   BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSuper(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (Super)");
 }
 
 /*
  interface SwitchCase : Node {
     Expression test;
     FrozenArray<Statement> consequent;
  }
 */
 template <typename Tok>
-JS::Result<CaseClause*> BinASTParser<Tok>::parseSwitchCase() {
+JS::Result<CaseClause*> BinASTParser<Tok>::parseSwitchCase(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SwitchCase) {
     return raiseInvalidKind("SwitchCase", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchCase(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result,
+                     parseInterfaceSwitchCase(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<CaseClause*> BinASTParser<Tok>::parseInterfaceSwitchCase(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchCase);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test,
                                           BinASTField::Consequent};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());
+  BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, test, consequent));
   return result;
 }
 
 /*
  interface SwitchDefault : Node {
     FrozenArray<Statement> consequent;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseSwitchDefault() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseSwitchDefault(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SwitchDefault) {
     return raiseInvalidKind("SwitchDefault", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchDefault(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(result,
+                     parseInterfaceSwitchDefault(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchDefault(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchDefault);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Consequent};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());
+  BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, nullptr, consequent));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Discriminant,
                                           BinASTField::Cases};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(discriminant, parseExpression());
+  BINJS_MOZ_TRY_DECL(discriminant, parseExpression(fieldContext++));
   ParseContext::Statement stmt(pc_, StatementKind::Switch);
-  BINJS_MOZ_TRY_DECL(cases, parseListOfSwitchCase());
+  BINJS_MOZ_TRY_DECL(cases, parseListOfSwitchCase(fieldContext++));
 
   BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
   BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
                                                      /* hasDefault = */ false));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchStatementWithDefault);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[4] = {
       BinASTField::Discriminant, BinASTField::PreDefaultCases,
       BinASTField::DefaultCase, BinASTField::PostDefaultCases};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(discriminant, parseExpression());
+  BINJS_MOZ_TRY_DECL(discriminant, parseExpression(fieldContext++));
   ParseContext::Statement stmt(pc_, StatementKind::Switch);
-  BINJS_MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase());
-
-  BINJS_MOZ_TRY_DECL(defaultCase, parseSwitchDefault());
-
-  BINJS_MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase());
+  BINJS_MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(defaultCase, parseSwitchDefault(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase(fieldContext++));
 
   // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase`
   auto cases = preDefaultCases;
   handler_.addList(cases, defaultCase);
   ParseNode* iter = postDefaultCases->head();
   while (iter) {
     ParseNode* next = iter->pn_next;
     handler_.addList(cases, iter);
@@ -3980,25 +4257,27 @@ BinASTParser<Tok>::parseInterfaceSwitchS
   BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
   BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
                                                      /* hasDefault = */ true));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTemplateExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(TemplateExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceThisExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ThisExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
   MOZ_TRY(tokenizer_->checkFields0(kind, fields));
 
   if (pc_->isFunctionBox()) {
     pc_->functionBox()->usesThis = true;
   }
 
@@ -4012,107 +4291,118 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   }
 
   BINJS_TRY_DECL(result, handler_.newThisLiteral(pos, thisName));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceThrowStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::ThrowStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(expression, parseExpression());
+  BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
 
   BINJS_TRY_DECL(
       result, handler_.newThrowStatement(expression, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryCatchStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::TryCatchStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Body,
                                           BinASTField::CatchClause};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
+
   ParseNode* body;
   {
     ParseContext::Statement stmt(pc_, StatementKind::Try);
     ParseContext::Scope scope(cx_, pc_, usedNames_);
     BINJS_TRY(scope.init(pc_));
-    MOZ_TRY_VAR(body, parseBlock());
+    MOZ_TRY_VAR(body, parseBlock(fieldContext++));
   }
 
-  BINJS_MOZ_TRY_DECL(catchClause, parseCatchClause());
+  BINJS_MOZ_TRY_DECL(catchClause, parseCatchClause(fieldContext++));
 
   BINJS_TRY_DECL(result,
                  handler_.newTryStatement(start, body, catchClause,
                                           /* finallyBlock = */ nullptr));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryFinallyStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::TryFinallyStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Body, BinASTField::CatchClause, BinASTField::Finalizer};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
+
   ParseNode* body;
   {
     ParseContext::Statement stmt(pc_, StatementKind::Try);
     ParseContext::Scope scope(cx_, pc_, usedNames_);
     BINJS_TRY(scope.init(pc_));
-    MOZ_TRY_VAR(body, parseBlock());
+    MOZ_TRY_VAR(body, parseBlock(fieldContext++));
   }
 
-  BINJS_MOZ_TRY_DECL(catchClause, parseOptionalCatchClause());
+  BINJS_MOZ_TRY_DECL(catchClause, parseOptionalCatchClause(fieldContext++));
+
   ParseNode* finalizer;
   {
     ParseContext::Statement stmt(pc_, StatementKind::Finally);
     ParseContext::Scope scope(cx_, pc_, usedNames_);
     BINJS_TRY(scope.init(pc_));
-    MOZ_TRY_VAR(finalizer, parseBlock());
+    MOZ_TRY_VAR(finalizer, parseBlock(fieldContext++));
   }
 
   BINJS_TRY_DECL(result,
                  handler_.newTryStatement(start, body, catchClause, finalizer));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceUnaryExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::UnaryExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Operator,
                                           BinASTField::Operand};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(operator_, parseUnaryOperator());
-
-  BINJS_MOZ_TRY_DECL(operand, parseExpression());
+  BINJS_MOZ_TRY_DECL(operator_, parseUnaryOperator(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(operand, parseExpression(fieldContext++));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case UnaryOperator::Minus:
       pnk = ParseNodeKind::NegExpr;
       break;
     case UnaryOperator::Plus:
       pnk = ParseNodeKind::PosExpr;
@@ -4154,31 +4444,33 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     }
   }
   BINJS_TRY_DECL(result, handler_.newUnary(pnk, start, operand));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceUpdateExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::UpdateExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::IsPrefix, BinASTField::Operator, BinASTField::Operand};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(isPrefix, tokenizer_->readBool());
-
-  BINJS_MOZ_TRY_DECL(operator_, parseUpdateOperator());
-
-  BINJS_MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget());
+  BINJS_MOZ_TRY_DECL(isPrefix, tokenizer_->readBool(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(operator_, parseUpdateOperator(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget(fieldContext++));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case UpdateOperator::Incr:
       pnk = isPrefix ? ParseNodeKind::PreIncrementExpr
                      : ParseNodeKind::PostIncrementExpr;
       break;
     case UpdateOperator::Decr:
@@ -4187,42 +4479,44 @@ JS::Result<ParseNode*> BinASTParser<Tok>
       break;
   }
   BINJS_TRY_DECL(result, handler_.newUnary(pnk, start, operand));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclaration(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::VariableDeclaration);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Kind,
                                           BinASTField::Declarators};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   AutoVariableDeclarationKind kindGuard(this);
 
-  BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
+  BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind(fieldContext++));
   // Restored by `kindGuard`.
   variableDeclarationKind_ = kind_;
   ParseNodeKind declarationListKind;
   switch (kind_) {
     case VariableDeclarationKind::Var:
       declarationListKind = ParseNodeKind::VarStmt;
       break;
     case VariableDeclarationKind::Let:
       return raiseError("Let is not supported in this preview release");
     case VariableDeclarationKind::Const:
       return raiseError("Const is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(declarators,
-                     parseListOfVariableDeclarator(declarationListKind));
+  BINJS_MOZ_TRY_DECL(declarators, parseListOfVariableDeclarator(
+                                      declarationListKind, fieldContext++));
 
   // By specification, the list may not be empty.
   if (declarators->empty()) {
     return raiseEmpty("VariableDeclaration");
   }
 
   auto result = declarators;
   return result;
@@ -4230,48 +4524,51 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 /*
  interface VariableDeclarator : Node {
     Binding binding;
     Expression? init;
  }
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseVariableDeclarator() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseVariableDeclarator(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::VariableDeclarator) {
     return raiseInvalidKind("VariableDeclarator", kind);
   }
   const auto start = tokenizer_->offset();
-  BINJS_MOZ_TRY_DECL(result,
-                     parseInterfaceVariableDeclarator(start, kind, fields));
+  BINJS_MOZ_TRY_DECL(
+      result, parseInterfaceVariableDeclarator(start, kind, fields, context));
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclarator(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::VariableDeclarator);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Binding,
                                           BinASTField::Init};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(binding, parseBinding());
-
-  BINJS_MOZ_TRY_DECL(init, parseOptionalExpression());
+  BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(init, parseOptionalExpression(fieldContext++));
 
   ParseNode* result;
   if (binding->isKind(ParseNodeKind::Name)) {
     // `var foo [= bar]``
     NameNode* bindingNameNode = &binding->template as<NameNode>();
     MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
     if (init) {
       BINJS_TRY_VAR(
@@ -4293,83 +4590,89 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     BINJS_TRY_VAR(result, handler_.newAssignment(ParseNodeKind::AssignExpr,
                                                  binding, init));
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceWhileStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::WhileStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression());
-
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
+
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   BINJS_TRY_DECL(result, handler_.newWhileStatement(start, test, body));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceWithStatement(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   MOZ_ASSERT(kind == BinASTKind::WithStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
+  Context fieldContext = Context::firstField(kind);
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(object, parseExpression());
+  BINJS_MOZ_TRY_DECL(object, parseExpression(fieldContext++));
 
   ParseContext::Statement stmt(pc_, StatementKind::With);
-  BINJS_MOZ_TRY_DECL(body, parseStatement());
+  BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
 
   pc_->sc()->setBindingsAccessedDynamically();
   BINJS_TRY_DECL(result, handler_.newWithStatement(start, object, body));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceYieldExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (YieldExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceYieldStarExpression(
-    const size_t start, const BinASTKind kind, const BinASTFields& fields) {
+    const size_t start, const BinASTKind kind, const BinASTFields& fields,
+    const Context& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(YieldStarExpression)");
 }
 
 // ----- String enums (autogenerated, by lexicographical order)
 /*
 enum AssertedDeclaredKind {
     "var",
     "non-const lexical",
     "const lexical"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
-BinASTParser<Tok>::parseAssertedDeclaredKind() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseAssertedDeclaredKind(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
       return AssertedDeclaredKind::Var;
     case BinASTVariant::AssertedDeclaredKindNonConstLexical:
       return AssertedDeclaredKind::NonConstLexical;
     case BinASTVariant::AssertedDeclaredKindConstLexical:
       return AssertedDeclaredKind::ConstLexical;
@@ -4404,18 +4707,18 @@ enum BinaryOperator {
     "*",
     "/",
     "%",
     "**"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::BinaryOperator>
-BinASTParser<Tok>::parseBinaryOperator() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseBinaryOperator(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::BinaryOperatorComma:
       return BinaryOperator::Comma;
     case BinASTVariant::BinaryOperatorLogicalOr:
       return BinaryOperator::LogicalOr;
     case BinASTVariant::BinaryOperatorLogicalAnd:
       return BinaryOperator::LogicalAnd;
@@ -4481,18 +4784,18 @@ enum CompoundAssignmentOperator {
     ">>>=",
     "|=",
     "^=",
     "&="
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
-BinASTParser<Tok>::parseCompoundAssignmentOperator() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseCompoundAssignmentOperator(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::CompoundAssignmentOperatorPlusAssign:
       return CompoundAssignmentOperator::PlusAssign;
     case BinASTVariant::CompoundAssignmentOperatorMinusAssign:
       return CompoundAssignmentOperator::MinusAssign;
     case BinASTVariant::CompoundAssignmentOperatorMulAssign:
       return CompoundAssignmentOperator::MulAssign;
@@ -4527,18 +4830,18 @@ enum UnaryOperator {
     "~",
     "typeof",
     "void",
     "delete"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::UnaryOperator>
-BinASTParser<Tok>::parseUnaryOperator() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseUnaryOperator(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::BinaryOperatorOrUnaryOperatorPlus:
       return UnaryOperator::Plus;
     case BinASTVariant::BinaryOperatorOrUnaryOperatorMinus:
       return UnaryOperator::Minus;
     case BinASTVariant::UnaryOperatorNot:
       return UnaryOperator::Not;
@@ -4558,18 +4861,18 @@ BinASTParser<Tok>::parseUnaryOperator() 
 /*
 enum UpdateOperator {
     "++",
     "--"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::UpdateOperator>
-BinASTParser<Tok>::parseUpdateOperator() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseUpdateOperator(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::UpdateOperatorIncr:
       return UpdateOperator::Incr;
     case BinASTVariant::UpdateOperatorDecr:
       return UpdateOperator::Decr;
     default:
       return raiseInvalidVariant("UpdateOperator", variant);
@@ -4580,410 +4883,441 @@ BinASTParser<Tok>::parseUpdateOperator()
 enum VariableDeclarationKind {
     "var",
     "let",
     "const"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
-BinASTParser<Tok>::parseVariableDeclarationKind() {
-  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+BinASTParser<Tok>::parseVariableDeclarationKind(const Context& context) {
+  BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
       return VariableDeclarationKind::Var;
     case BinASTVariant::VariableDeclarationKindLet:
       return VariableDeclarationKind::Let;
     case BinASTVariant::VariableDeclarationKindConst:
       return VariableDeclarationKind::Const;
     default:
       return raiseInvalidVariant("VariableDeclarationKind", variant);
   }
 }
 
 // ----- Lists (autogenerated, by lexicographical order)
 
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseArguments() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseArguments(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newList(ParseNodeKind::Arguments,
                                           tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression(childContext));
     handler_.addList(/* list = */ result, /* kid = */ item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseFunctionBody() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseFunctionBody(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseStatement());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedBoundName(
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   (void)start;
   auto result = Ok();
 
-  for (uint32_t i = 0; i < length; ++i) {
-    MOZ_TRY(parseAssertedBoundName(scopeKind));
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    MOZ_TRY(parseAssertedBoundName(scopeKind, childContext));
     // Nothing to do here.
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedDeclaredName(
-    AssertedScopeKind scopeKind) {
+    AssertedScopeKind scopeKind, const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   (void)start;
   auto result = Ok();
 
-  for (uint32_t i = 0; i < length; ++i) {
-    MOZ_TRY(parseAssertedDeclaredName(scopeKind));
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    MOZ_TRY(parseAssertedDeclaredName(scopeKind, childContext));
     // Nothing to do here.
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok>
 BinASTParser<Tok>::parseListOfAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   (void)start;
   auto result = Ok();
   // This list contains also destructuring parameters, and the number of
   // list items can be greater than the actual parameters, or more than
   // ARGNO_LIMIT even if the number of parameters fits into ARGNO_LIMIT.
   // Also, the number of parameters can be greater than this list's length
   // if one of destructuring parameter is empty.
   //
   // We resize `positionalParams` vector on demand, to keep the vector
   // length match to the known maximum positional parameter index + 1.
 
-  for (uint32_t i = 0; i < length; ++i) {
-    MOZ_TRY(
-        parseAssertedMaybePositionalParameterName(scopeKind, positionalParams));
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    MOZ_TRY(parseAssertedMaybePositionalParameterName(
+        scopeKind, positionalParams, childContext));
     // Nothing to do here.
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseListOfDirective() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseListOfDirective(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseDirective());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseDirective(childContext));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseListOfObjectProperty() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseListOfObjectProperty(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newObjectLiteral(start));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseObjectProperty());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseObjectProperty(childContext));
     if (!item->isConstant()) result->setHasNonConstInitializer();
     result->appendWithoutOrderAssumption(item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*>
-BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression() {
+BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newArrayLiteral(start));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseOptionalSpreadElementOrExpression());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item,
+                       parseOptionalSpreadElementOrExpression(childContext));
     if (item) {
       handler_.addArrayElement(result, item);  // Infallible.
     } else {
       BINJS_TRY(handler_.addElision(result, tokenizer_->pos(start)));
     }
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseListOfParameter() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseListOfParameter(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newParamsBody(tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseParameter());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseParameter(childContext));
     handler_.addList(/* list = */ result, /* kid = */ item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseListOfStatement() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseListOfStatement(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseStatement());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
-JS::Result<ListNode*> BinASTParser<Tok>::parseListOfSwitchCase() {
+JS::Result<ListNode*> BinASTParser<Tok>::parseListOfSwitchCase(
+    const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseSwitchCase());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseSwitchCase(childContext));
     handler_.addCaseStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfVariableDeclarator(
-    ParseNodeKind declarationListKind) {
+    ParseNodeKind declarationListKind, const Context& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  MOZ_TRY(tokenizer_->enterList(length, guard));
+  MOZ_TRY(tokenizer_->enterList(length, context, guard));
   BINJS_TRY_DECL(result, handler_.newDeclarationList(declarationListKind,
                                                      tokenizer_->pos(start)));
 
-  for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator());
+  const Context childContext(context.arrayElement());
+  for (uint8_t i = 0; i < length; ++i) {
+    BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator(childContext));
     result->appendWithoutOrderAssumption(item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 // ----- Default values (by lexicographical order)
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBinding() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBinding(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
+    MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields, context));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBindingIdentifier() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBindingIdentifier(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else if (kind == BinASTKind::BindingIdentifier) {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
+    MOZ_TRY_VAR(result,
+                parseInterfaceBindingIdentifier(start, kind, fields, context));
   } else {
     return raiseInvalidKind("BindingIdentifier", kind);
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
-JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseOptionalCatchClause() {
+JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseOptionalCatchClause(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   LexicalScopeNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else if (kind == BinASTKind::CatchClause) {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields));
+    MOZ_TRY_VAR(result,
+                parseInterfaceCatchClause(start, kind, fields, context));
   } else {
     return raiseInvalidKind("CatchClause", kind);
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalExpression() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
+    MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields, context));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
-BinASTParser<Tok>::parseOptionalSpreadElementOrExpression() {
+BinASTParser<Tok>::parseOptionalSpreadElementOrExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
+    MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields,
+                                                          context));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalStatement() {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalStatement(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
+    MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields, context));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
-BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression() {
+BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression(
+    const Context& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
-  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+  MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result,
-                parseSumVariableDeclarationOrExpression(start, kind, fields));
+    MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(
+                            start, kind, fields, context));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 // Force class instantiation.
 // This ensures that the symbols are built, without having to export all our
--- a/js/src/frontend/BinASTParser.h
+++ b/js/src/frontend/BinASTParser.h
@@ -37,16 +37,17 @@ class BinASTParser : public BinASTParser
   using Base = BinASTParserPerTokenizer<Tok>;
 
   using Tokenizer = Tok;
 
   using BinASTFields = typename Tokenizer::BinASTFields;
   using AutoList = typename Tokenizer::AutoList;
   using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
   using Chars = typename Tokenizer::Chars;
+  using Context = typename BinASTTokenReaderBase::Context;
 
  public:
   // Auto-generated types.
   using AssertedDeclaredKind = binast::AssertedDeclaredKind;
   using BinaryOperator = binast::BinaryOperator;
   using CompoundAssignmentOperator = binast::CompoundAssignmentOperator;
   using UnaryOperator = binast::UnaryOperator;
   using UpdateOperator = binast::UpdateOperator;
@@ -116,359 +117,496 @@ class BinASTParser : public BinASTParser
 
   using Base::forceStrictIfNecessary;
 
  public:
   // ----- Sums of interfaces (by lexicographical order)
   // `ParseNode*` may never be nullptr
   JS::Result<Ok> parseAssertedMaybePositionalParameterName(
       AssertedScopeKind scopeKind,
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
-  JS::Result<ParseNode*> parseAssignmentTarget();
-  JS::Result<ParseNode*> parseBinding();
-  JS::Result<ParseNode*> parseExpression();
-  JS::Result<ParseNode*> parseExpressionOrSuper();
-  JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget();
-  JS::Result<ParseNode*> parseObjectProperty();
-  JS::Result<ParseNode*> parseParameter();
-  JS::Result<ParseNode*> parseProgram();
-  JS::Result<ParseNode*> parsePropertyName();
-  JS::Result<ParseNode*> parseSimpleAssignmentTarget();
-  JS::Result<ParseNode*> parseSpreadElementOrExpression();
-  JS::Result<ParseNode*> parseStatement();
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
+  JS::Result<ParseNode*> parseAssignmentTarget(const Context& context);
+  JS::Result<ParseNode*> parseBinding(const Context& context);
+  JS::Result<ParseNode*> parseExpression(const Context& context);
+  JS::Result<ParseNode*> parseExpressionOrSuper(const Context& context);
+  JS::Result<ParseNode*> parseForInOfBindingOrAssignmentTarget(
+      const Context& context);
+  JS::Result<ParseNode*> parseObjectProperty(const Context& context);
+  JS::Result<ParseNode*> parseParameter(const Context& context);
+  JS::Result<ParseNode*> parseProgram(const Context& context);
+  JS::Result<ParseNode*> parsePropertyName(const Context& context);
+  JS::Result<ParseNode*> parseSimpleAssignmentTarget(const Context& context);
+  JS::Result<ParseNode*> parseSpreadElementOrExpression(const Context& context);
+  JS::Result<ParseNode*> parseStatement(const Context& context);
   JS::Result<Ok> parseSumAssertedMaybePositionalParameterName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       AssertedScopeKind scopeKind,
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
   JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start,
                                                   const BinASTKind kind,
-                                                  const BinASTFields& fields);
+                                                  const BinASTFields& fields,
+                                                  const Context& context);
   JS::Result<ParseNode*> parseSumBinding(const size_t start,
                                          const BinASTKind kind,
-                                         const BinASTFields& fields);
+                                         const BinASTFields& fields,
+                                         const Context& context);
   JS::Result<ParseNode*> parseSumExpression(const size_t start,
                                             const BinASTKind kind,
-                                            const BinASTFields& fields);
+                                            const BinASTFields& fields,
+                                            const Context& context);
   JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
   JS::Result<ParseNode*> parseSumForInOfBindingOrAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseSumObjectProperty(const size_t start,
                                                 const BinASTKind kind,
-                                                const BinASTFields& fields);
+                                                const BinASTFields& fields,
+                                                const Context& context);
   JS::Result<ParseNode*> parseSumParameter(const size_t start,
                                            const BinASTKind kind,
-                                           const BinASTFields& fields);
+                                           const BinASTFields& fields,
+                                           const Context& context);
   JS::Result<ParseNode*> parseSumProgram(const size_t start,
                                          const BinASTKind kind,
-                                         const BinASTFields& fields);
+                                         const BinASTFields& fields,
+                                         const Context& context);
   JS::Result<ParseNode*> parseSumPropertyName(const size_t start,
                                               const BinASTKind kind,
-                                              const BinASTFields& fields);
+                                              const BinASTFields& fields,
+                                              const Context& context);
   JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseSumSpreadElementOrExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseSumStatement(const size_t start,
                                            const BinASTKind kind,
-                                           const BinASTFields& fields);
+                                           const BinASTFields& fields,
+                                           const Context& context);
   JS::Result<ParseNode*> parseSumVariableDeclarationOrExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
 
   // ----- Interfaces (by lexicographical order)
   // `ParseNode*` may never be nullptr
-  JS::Result<Ok> parseAssertedBlockScope();
-  JS::Result<Ok> parseAssertedBoundName(AssertedScopeKind scopeKind);
-  JS::Result<Ok> parseAssertedBoundNamesScope();
-  JS::Result<Ok> parseAssertedDeclaredName(AssertedScopeKind scopeKind);
+  JS::Result<Ok> parseAssertedBlockScope(const Context& context);
+  JS::Result<Ok> parseAssertedBoundName(AssertedScopeKind scopeKind,
+                                        const Context& context);
+  JS::Result<Ok> parseAssertedBoundNamesScope(const Context& context);
+  JS::Result<Ok> parseAssertedDeclaredName(AssertedScopeKind scopeKind,
+                                           const Context& context);
   JS::Result<Ok> parseAssertedParameterScope(
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
-  JS::Result<Ok> parseAssertedScriptGlobalScope();
-  JS::Result<Ok> parseAssertedVarScope();
-  JS::Result<ParseNode*> parseBindingIdentifier();
-  JS::Result<ParseNode*> parseBlock();
-  JS::Result<LexicalScopeNode*> parseCatchClause();
-  JS::Result<ParseNode*> parseDirective();
-  JS::Result<ListNode*> parseFormalParameters();
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
+  JS::Result<Ok> parseAssertedScriptGlobalScope(const Context& context);
+  JS::Result<Ok> parseAssertedVarScope(const Context& context);
+  JS::Result<ParseNode*> parseBindingIdentifier(const Context& context);
+  JS::Result<ParseNode*> parseBlock(const Context& context);
+  JS::Result<LexicalScopeNode*> parseCatchClause(const Context& context);
+  JS::Result<ParseNode*> parseDirective(const Context& context);
+  JS::Result<ListNode*> parseFormalParameters(const Context& context);
   JS::Result<Ok> parseFunctionExpressionContents(uint32_t funLength,
                                                  ListNode** paramsOut,
-                                                 ListNode** bodyOut);
+                                                 ListNode** bodyOut,
+                                                 const Context& context);
   JS::Result<Ok> parseFunctionOrMethodContents(uint32_t funLength,
                                                ListNode** paramsOut,
-                                               ListNode** bodyOut);
+                                               ListNode** bodyOut,
+                                               const Context& context);
   JS::Result<Ok> parseGetterContents(uint32_t funLength, ListNode** paramsOut,
-                                     ListNode** bodyOut);
-  JS::Result<ParseNode*> parseIdentifierExpression();
+                                     ListNode** bodyOut,
+                                     const Context& context);
+  JS::Result<ParseNode*> parseIdentifierExpression(const Context& context);
   JS::Result<Ok> parseSetterContents(uint32_t funLength, ListNode** paramsOut,
-                                     ListNode** bodyOut);
-  JS::Result<CaseClause*> parseSwitchCase();
-  JS::Result<ParseNode*> parseSwitchDefault();
-  JS::Result<ParseNode*> parseVariableDeclarator();
+                                     ListNode** bodyOut,
+                                     const Context& context);
+  JS::Result<CaseClause*> parseSwitchCase(const Context& context);
+  JS::Result<ParseNode*> parseSwitchDefault(const Context& context);
+  JS::Result<ParseNode*> parseVariableDeclarator(const Context& context);
   JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start,
                                                     const BinASTKind kind,
-                                                    const BinASTFields& fields);
+                                                    const BinASTFields& fields,
+                                                    const Context& context);
   JS::Result<ParseNode*> parseInterfaceArrayExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start,
                                                   const BinASTKind kind,
-                                                  const BinASTFields& fields);
+                                                  const BinASTFields& fields,
+                                                  const Context& context);
   JS::Result<Ok> parseInterfaceAssertedBoundName(const size_t start,
                                                  const BinASTKind kind,
                                                  const BinASTFields& fields,
-                                                 AssertedScopeKind scopeKind);
+                                                 AssertedScopeKind scopeKind,
+                                                 const Context& context);
   JS::Result<Ok> parseInterfaceAssertedBoundNamesScope(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
-  JS::Result<Ok> parseInterfaceAssertedDeclaredName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      AssertedScopeKind scopeKind);
+      const Context& context);
+  JS::Result<Ok> parseInterfaceAssertedDeclaredName(const size_t start,
+                                                    const BinASTKind kind,
+                                                    const BinASTFields& fields,
+                                                    AssertedScopeKind scopeKind,
+                                                    const Context& context);
   JS::Result<Ok> parseInterfaceAssertedParameterScope(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
   JS::Result<Ok> parseInterfaceAssertedPositionalParameterName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       AssertedScopeKind scopeKind,
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
   JS::Result<Ok> parseInterfaceAssertedScriptGlobalScope(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start,
                                                 const BinASTKind kind,
-                                                const BinASTFields& fields);
+                                                const BinASTFields& fields,
+                                                const Context& context);
   JS::Result<ParseNode*> parseInterfaceAssignmentExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceAwaitExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceBinaryExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceBindingIdentifier(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceBindingWithInitializer(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceBlock(const size_t start,
                                              const BinASTKind kind,
-                                             const BinASTFields& fields);
+                                             const BinASTFields& fields,
+                                             const Context& context);
   JS::Result<ParseNode*> parseInterfaceBreakStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceCallExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<LexicalScopeNode*> parseInterfaceCatchClause(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceClassDeclaration(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceClassExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceComputedPropertyName(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceConditionalExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceContinueStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start,
                                                     const BinASTKind kind,
-                                                    const BinASTFields& fields);
+                                                    const BinASTFields& fields,
+                                                    const Context& context);
   JS::Result<ParseNode*> parseInterfaceDebuggerStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceDirective(const size_t start,
                                                  const BinASTKind kind,
-                                                 const BinASTFields& fields);
+                                                 const BinASTFields& fields,
+                                                 const Context& context);
   JS::Result<ParseNode*> parseInterfaceDoWhileStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithFunctionBody(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerFunctionDeclaration(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerFunctionExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerGetter(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerMethod(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerSetter(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
   JS::Result<ParseNode*> parseInterfaceEmptyStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceExpressionStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceForInOfBinding(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceForInStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceForOfStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start,
                                                     const BinASTKind kind,
-                                                    const BinASTFields& fields);
+                                                    const BinASTFields& fields,
+                                                    const Context& context);
   JS::Result<ListNode*> parseInterfaceFormalParameters(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<Ok> parseInterfaceFunctionExpressionContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut);
+      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+      const Context& context);
   JS::Result<Ok> parseInterfaceFunctionOrMethodContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut);
+      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+      const Context& context);
   JS::Result<Ok> parseInterfaceGetterContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut);
+      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceIdentifierExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
   JS::Result<ParseNode*> parseInterfaceLabelledStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyArrowExpressionWithFunctionBody(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyFunctionDeclaration(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyFunctionExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyGetter(const size_t start,
                                                   const BinASTKind kind,
-                                                  const BinASTFields& fields);
+                                                  const BinASTFields& fields,
+                                                  const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyMethod(const size_t start,
                                                   const BinASTKind kind,
-                                                  const BinASTFields& fields);
+                                                  const BinASTFields& fields,
+                                                  const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazySetter(const size_t start,
                                                   const BinASTKind kind,
-                                                  const BinASTFields& fields);
+                                                  const BinASTFields& fields,
+                                                  const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralBooleanExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralInfinityExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralNullExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralNumericExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralPropertyName(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralRegExpExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralStringExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceModule(const size_t start,
                                               const BinASTKind kind,
-                                              const BinASTFields& fields);
-  JS::Result<ParseNode*> parseInterfaceNewExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+                                              const BinASTFields& fields,
+                                              const Context& context);
+  JS::Result<ParseNode*> parseInterfaceNewExpression(const size_t start,
+                                                     const BinASTKind kind,
+                                                     const BinASTFields& fields,
+                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceNewTargetExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceObjectAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
-  JS::Result<ParseNode*> parseInterfaceObjectBinding(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
+  JS::Result<ParseNode*> parseInterfaceObjectBinding(const size_t start,
+                                                     const BinASTKind kind,
+                                                     const BinASTFields& fields,
+                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceObjectExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceReturnStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceScript(const size_t start,
                                               const BinASTKind kind,
-                                              const BinASTFields& fields);
+                                              const BinASTFields& fields,
+                                              const Context& context);
   JS::Result<Ok> parseInterfaceSetterContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut);
+      uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceShorthandProperty(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
-  JS::Result<ParseNode*> parseInterfaceSpreadElement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
+  JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start,
+                                                     const BinASTKind kind,
+                                                     const BinASTFields& fields,
+                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceSuper(const size_t start,
                                              const BinASTKind kind,
-                                             const BinASTFields& fields);
+                                             const BinASTFields& fields,
+                                             const Context& context);
   JS::Result<CaseClause*> parseInterfaceSwitchCase(const size_t start,
                                                    const BinASTKind kind,
-                                                   const BinASTFields& fields);
-  JS::Result<ParseNode*> parseInterfaceSwitchDefault(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+                                                   const BinASTFields& fields,
+                                                   const Context& context);
+  JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start,
+                                                     const BinASTKind kind,
+                                                     const BinASTFields& fields,
+                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceSwitchStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceTemplateExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceThisExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceThrowStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceTryCatchStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceTryFinallyStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceUnaryExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceUpdateExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceVariableDeclaration(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceVariableDeclarator(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceWhileStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
-  JS::Result<ParseNode*> parseInterfaceWithStatement(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
+  JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start,
+                                                     const BinASTKind kind,
+                                                     const BinASTFields& fields,
+                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceYieldExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
   JS::Result<ParseNode*> parseInterfaceYieldStarExpression(
-      const size_t start, const BinASTKind kind, const BinASTFields& fields);
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const Context& context);
 
   // ----- String enums (by lexicographical order)
   JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
-  parseAssertedDeclaredKind();
-  JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator();
+  parseAssertedDeclaredKind(const Context& context);
+  JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator(
+      const Context& context);
   JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
-  parseCompoundAssignmentOperator();
-  JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator();
-  JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator();
+  parseCompoundAssignmentOperator(const Context& context);
+  JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator(
+      const Context& context);
+  JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator(
+      const Context& context);
   JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
-  parseVariableDeclarationKind();
+  parseVariableDeclarationKind(const Context& context);
 
   // ----- Lists (by lexicographical order)
-  JS::Result<ParseNode*> parseArguments();
-  JS::Result<ListNode*> parseFunctionBody();
-  JS::Result<Ok> parseListOfAssertedBoundName(AssertedScopeKind scopeKind);
-  JS::Result<Ok> parseListOfAssertedDeclaredName(AssertedScopeKind scopeKind);
+  JS::Result<ParseNode*> parseArguments(const Context& context);
+  JS::Result<ListNode*> parseFunctionBody(const Context& context);
+  JS::Result<Ok> parseListOfAssertedBoundName(AssertedScopeKind scopeKind,
+                                              const Context& context);
+  JS::Result<Ok> parseListOfAssertedDeclaredName(AssertedScopeKind scopeKind,
+                                                 const Context& context);
   JS::Result<Ok> parseListOfAssertedMaybePositionalParameterName(
       AssertedScopeKind scopeKind,
-      MutableHandle<GCVector<JSAtom*>> positionalParams);
-  JS::Result<ListNode*> parseListOfDirective();
-  JS::Result<ListNode*> parseListOfObjectProperty();
-  JS::Result<ListNode*> parseListOfOptionalSpreadElementOrExpression();
-  JS::Result<ListNode*> parseListOfParameter();
-  JS::Result<ListNode*> parseListOfStatement();
-  JS::Result<ListNode*> parseListOfSwitchCase();
+      MutableHandle<GCVector<JSAtom*>> positionalParams,
+      const Context& context);
+  JS::Result<ListNode*> parseListOfDirective(const Context& context);
+  JS::Result<ListNode*> parseListOfObjectProperty(const Context& context);
+  JS::Result<ListNode*> parseListOfOptionalSpreadElementOrExpression(
+      const Context& context);
+  JS::Result<ListNode*> parseListOfParameter(const Context& context);
+  JS::Result<ListNode*> parseListOfStatement(const Context& context);
+  JS::Result<ListNode*> parseListOfSwitchCase(const Context& context);
   JS::Result<ListNode*> parseListOfVariableDeclarator(
-      ParseNodeKind declarationListKind);
+      ParseNodeKind declarationListKind, const Context& context);
 
   // ----- Default values (by lexicographical order)
-  JS::Result<ParseNode*> parseOptionalBinding();
-  JS::Result<ParseNode*> parseOptionalBindingIdentifier();
-  JS::Result<LexicalScopeNode*> parseOptionalCatchClause();
-  JS::Result<ParseNode*> parseOptionalExpression();
-  JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression();
-  JS::Result<ParseNode*> parseOptionalStatement();
-  JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression();
+  JS::Result<ParseNode*> parseOptionalBinding(const Context& context);
+  JS::Result<ParseNode*> parseOptionalBindingIdentifier(const Context& context);
+  JS::Result<LexicalScopeNode*> parseOptionalCatchClause(
+      const Context& context);
+  JS::Result<ParseNode*> parseOptionalExpression(const Context& context);
+  JS::Result<ParseNode*> parseOptionalSpreadElementOrExpression(
+      const Context& context);
+  JS::Result<ParseNode*> parseOptionalStatement(const Context& context);
+  JS::Result<ParseNode*> parseOptionalVariableDeclarationOrExpression(
+      const Context& context);
 };
 
 extern template class BinASTParser<BinASTTokenReaderMultipart>;
 
 }  // namespace frontend
 }  // namespace js
 
 #endif  // frontend_BinASTParser_h
--- a/js/src/frontend/BinASTParserPerTokenizer.cpp
+++ b/js/src/frontend/BinASTParserPerTokenizer.cpp
@@ -127,17 +127,18 @@ JS::Result<ParseNode*> BinASTParserPerTo
   ParseContext::VarScope varScope(cx_, &globalpc, usedNames_);
   if (!varScope.init(&globalpc)) {
     return cx_->alreadyReportedError();
   }
 
   MOZ_TRY(tokenizer_->readHeader());
 
   ParseNode* result(nullptr);
-  MOZ_TRY_VAR(result, asFinalParser()->parseProgram());
+  const Context topContext(Context::topLevel());
+  MOZ_TRY_VAR(result, asFinalParser()->parseProgram(topContext));
 
   mozilla::Maybe<GlobalScope::Data*> bindings =
       NewGlobalScopeData(cx_, varScope, alloc_, pc_);
   if (!bindings) {
     return cx_->alreadyReportedError();
   }
   globalsc->bindings = *bindings;
 
@@ -186,17 +187,22 @@ JS::Result<FunctionNode*> BinASTParserPe
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* tmpBody;
   auto parseFunc = isExpr ? &FinalParser::parseFunctionExpressionContents
                           : &FinalParser::parseFunctionOrMethodContents;
-  MOZ_TRY((asFinalParser()->*parseFunc)(func->nargs(), &params, &tmpBody));
+
+  // Inject a toplevel context (i.e. no parent) to parse the lazy content.
+  // In the future, we may move this to a more specific context.
+  const Context context(Context::topLevel());
+  MOZ_TRY(
+      (asFinalParser()->*parseFunc)(func->nargs(), &params, &tmpBody, context));
 
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(body, handler_.newLexicalScope(*lexicalScopeData, tmpBody));
 
   auto binASTKind = isExpr ? BinASTKind::LazyFunctionExpression
                            : BinASTKind::LazyFunctionDeclaration;
   return buildFunction(firstOffset, binASTKind, nullptr, params, body);
--- a/js/src/frontend/BinASTParserPerTokenizer.h
+++ b/js/src/frontend/BinASTParserPerTokenizer.h
@@ -51,16 +51,17 @@ class BinASTParserPerTokenizer : public 
                                  public BCEParserHandle {
  public:
   using Tokenizer = Tok;
 
   using AutoList = typename Tokenizer::AutoList;
   using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
   using BinASTFields = typename Tokenizer::BinASTFields;
   using Chars = typename Tokenizer::Chars;
+  using Context = BinASTTokenReaderBase::Context;
 
  public:
   // Auto-generated types.
   using AssertedDeclaredKind = binast::AssertedDeclaredKind;
   using VariableDeclarationKind = binast::VariableDeclarationKind;
 
  public:
   BinASTParserPerTokenizer(JSContext* cx, LifoAlloc& alloc,
--- a/js/src/frontend/BinASTToken.h
+++ b/js/src/frontend/BinASTToken.h
@@ -9,16 +9,18 @@
 // To generate this file, see the documentation in
 // js/src/frontend/binast/README.md.
 
 #ifndef frontend_BinASTToken_h
 #define frontend_BinASTToken_h
 
 #include <stddef.h>
 
+#include "jstypes.h"
+
 /**
  * Definition of Binary AST tokens.
  *
  * In the Binary AST world, an AST is composed of nodes, where a node is
  * defined by:
  * - a Kind (see `BinASTKind`);
  * - a list of fields, where each field is:
  *    - a Name (see `BinASTField`);
@@ -180,17 +182,17 @@ namespace frontend {
   F(UpdateExpression, "UpdateExpression")                                     \
   F(VariableDeclaration, "VariableDeclaration")                               \
   F(VariableDeclarator, "VariableDeclarator")                                 \
   F(WhileStatement, "WhileStatement")                                         \
   F(WithStatement, "WithStatement")                                           \
   F(YieldExpression, "YieldExpression")                                       \
   F(YieldStarExpression, "YieldStarExpression")
 
-enum class BinASTKind {
+enum class BinASTKind : uint16_t {
 #define EMIT_ENUM(name, _) name,
   FOR_EACH_BIN_KIND(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 
 // The number of distinct values of BinASTKind.
 const size_t BINASTKIND_LIMIT = 120;
 
@@ -273,17 +275,17 @@ const size_t BINASTKIND_LIMIT = 120;
   F(Scope, "scope")                                   \
   F(Statements, "statements")                         \
   F(Super, "super")                                   \
   F(Tag, "tag")                                       \
   F(Test, "test")                                     \
   F(Update, "update")                                 \
   F(Value, "value")
 
-enum class BinASTField {
+enum class BinASTField : uint16_t {
 #define EMIT_ENUM(name, _) name,
   FOR_EACH_BIN_FIELD(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 
 // The number of distinct values of BinASTField.
 const size_t BINASTFIELD_LIMIT = 69;
 
@@ -349,17 +351,17 @@ const size_t BINASTFIELD_LIMIT = 69;
   F(UnaryOperatorNot, "!")                                    \
   F(UnaryOperatorTypeof, "typeof")                            \
   F(UnaryOperatorVoid, "void")                                \
   F(UpdateOperatorDecr, "--")                                 \
   F(UpdateOperatorIncr, "++")                                 \
   F(VariableDeclarationKindConst, "const")                    \
   F(VariableDeclarationKindLet, "let")
 
-enum class BinASTVariant {
+enum class BinASTVariant : uint16_t {
 #define EMIT_ENUM(name, _) name,
   FOR_EACH_BIN_VARIANT(EMIT_ENUM)
 #undef EMIT_ENUM
 };
 
 // The number of distinct values of BinASTVariant.
 const size_t BINASTVARIANT_LIMIT = 49;
 
--- a/js/src/frontend/BinASTTokenReaderBase.h
+++ b/js/src/frontend/BinASTTokenReaderBase.h
@@ -20,16 +20,59 @@ namespace frontend {
 // A constant used by tokenizers to represent a null float.
 extern const uint64_t NULL_FLOAT_REPRESENTATION;
 
 class MOZ_STACK_CLASS BinASTTokenReaderBase {
  public:
   template <typename T>
   using ErrorResult = mozilla::GenericErrorResult<T>;
 
+  // The context in which we read a token.
+  struct Context {
+    // Construct a context for a root node.
+    constexpr static Context topLevel() {
+      return Context{BinASTKind::_Null, 0, ElementOf::TaggedTuple};
+    }
+
+    Context arrayElement() const {
+      return Context{kind, fieldIndex, ElementOf::Array};
+    }
+
+    // Construct a context for a field of a tagged tuple.
+    constexpr static Context firstField(BinASTKind kind) {
+      return Context{kind, 0, ElementOf::TaggedTuple};
+    }
+
+    const Context operator++(int) {
+      MOZ_ASSERT(elementOf == ElementOf::TaggedTuple);
+      Context result = *this;
+      fieldIndex++;
+      return result;
+    }
+
+    // The kind of the tagged tuple containing the token.
+    //
+    // If the parent is the root, use `BinASTKind::_Null`.
+    BinASTKind kind;
+
+    // The index of the token as a field of the parent.
+    uint8_t fieldIndex;
+
+    enum class ElementOf {
+      // This token is an element of an array.
+      Array,
+
+      // This token is a field of a tagged tuple.
+      TaggedTuple,
+    };
+    ElementOf elementOf;
+
+    Context() = delete;
+  };
+
   // The information needed to skip a subtree.
   class SkippableSubTree {
    public:
     SkippableSubTree(const size_t startOffset, const size_t length)
         : startOffset_(startOffset), length_(length) {}
 
     // The position in the source buffer at which the subtree starts.
     //
--- a/js/src/frontend/BinASTTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinASTTokenReaderMultipart.cpp
@@ -216,17 +216,17 @@ JS::Result<Ok> BinASTTokenReaderMultipar
 }
 
 void BinASTTokenReaderMultipart::traceMetadata(JSTracer* trc) {
   if (metadata_) {
     metadata_->trace(trc);
   }
 }
 
-JS::Result<bool> BinASTTokenReaderMultipart::readBool() {
+JS::Result<bool> BinASTTokenReaderMultipart::readBool(const Context&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(byte, readByte());
 
   switch (byte) {
     case 0:
       return false;
     case 1:
       return true;
@@ -236,17 +236,17 @@ JS::Result<bool> BinASTTokenReaderMultip
       return raiseError("Invalid boolean value");
   }
 }
 
 // Nullable doubles (little-endian)
 //
 // NULL_FLOAT_REPRESENTATION (signaling NaN) => null
 // anything other 64 bit sequence => IEEE-764 64-bit floating point number
-JS::Result<double> BinASTTokenReaderMultipart::readDouble() {
+JS::Result<double> BinASTTokenReaderMultipart::readDouble(const Context&) {
   updateLatestKnownGood();
 
   uint8_t bytes[8];
   MOZ_ASSERT(sizeof(bytes) == sizeof(double));
   MOZ_TRY(
       readBuf(reinterpret_cast<uint8_t*>(bytes), mozilla::ArrayLength(bytes)));
 
   // Decode little-endian.
@@ -257,71 +257,77 @@ JS::Result<double> BinASTTokenReaderMult
   }
 
   // Canonicalize NaN, just to make sure another form of signalling NaN
   // doesn't slip past us.
   return JS::CanonicalizeNaN(mozilla::BitwiseCast<double>(asInt));
 }
 
 // A single atom is represented as an index into the table of strings.
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeAtom() {
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeAtom(const Context&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table");
   }
   return metadata_->getAtom(index);
 }
 
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readAtom() {
-  BINJS_MOZ_TRY_DECL(maybe, readMaybeAtom());
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readAtom(
+    const Context& context) {
+  BINJS_MOZ_TRY_DECL(maybe, readMaybeAtom(context));
 
   if (!maybe) {
     return raiseError("Empty string");
   }
 
   return maybe;
 }
 
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeIdentifierName() {
-  BINJS_MOZ_TRY_DECL(result, readMaybeAtom());
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeIdentifierName(
+    const Context& context) {
+  BINJS_MOZ_TRY_DECL(result, readMaybeAtom(context));
   if (result) {
     if (!IsIdentifier(result)) {
       return raiseError("Invalid identifier");
     }
   }
   return result;
 }
 
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readIdentifierName() {
-  BINJS_MOZ_TRY_DECL(result, readAtom());
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readIdentifierName(
+    const Context& context) {
+  BINJS_MOZ_TRY_DECL(result, readAtom(context));
   if (!IsIdentifier(result)) {
     return raiseError("Invalid identifier");
   }
   return result;
 }
 
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readPropertyKey() {
-  return readAtom();
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readPropertyKey(
+    const Context& context) {
+  return readAtom(context);
 }
 
-JS::Result<Ok> BinASTTokenReaderMultipart::readChars(Chars& out) {
+JS::Result<Ok> BinASTTokenReaderMultipart::readChars(Chars& out,
+                                                     const Context&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table for string enum");
   }
 
   out = metadata_->getSlice(index);
   return Ok();
 }
 
-JS::Result<BinASTVariant> BinASTTokenReaderMultipart::readVariant() {
+JS::Result<BinASTVariant> BinASTTokenReaderMultipart::readVariant(
+    const Context&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table for string enum");
   }
 
   auto variantsPtr = variantsTable_.lookupForAdd(index);
@@ -346,17 +352,17 @@ JS::Result<BinASTVariant> BinASTTokenRea
   if (!variantsTable_.add(variantsPtr, index, *variant)) {
     return raiseOOM();
   }
 
   return *variant;
 }
 
 JS::Result<BinASTTokenReaderBase::SkippableSubTree>
-BinASTTokenReaderMultipart::readSkippableSubTree() {
+BinASTTokenReaderMultipart::readSkippableSubTree(const Context&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
   if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
     return raiseError("Invalid byte length in readSkippableSubTree");
   }
 
   const auto start = offset();
@@ -365,17 +371,17 @@ BinASTTokenReaderMultipart::readSkippabl
 
   return BinASTTokenReaderBase::SkippableSubTree(start, byteLen);
 }
 
 // Tagged tuples:
 // - uint32_t index in table [grammar];
 // - content (specified by the higher-level grammar);
 JS::Result<Ok> BinASTTokenReaderMultipart::enterTaggedTuple(
-    BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields&,
+    BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields&, const Context&,
     AutoTaggedTuple& guard) {
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
   if (index >= metadata_->numBinASTKinds()) {
     return raiseError("Invalid index to grammar table");
   }
 
   tag = metadata_->getBinASTKind(index);
 
@@ -387,16 +393,17 @@ JS::Result<Ok> BinASTTokenReaderMultipar
 // List:
 //
 // - uint32_t number of items;
 // - contents (specified by higher-level grammar);
 //
 // The total byte length of `number of items` + `contents` must be `byte
 // length`.
 JS::Result<Ok> BinASTTokenReaderMultipart::enterList(uint32_t& items,
+                                                     const Context&,
                                                      AutoList& guard) {
   guard.init();
 
   MOZ_TRY_VAR(items, readInternalUint32());
 
   return Ok();
 }
 
--- a/js/src/frontend/BinASTTokenReaderMultipart.h
+++ b/js/src/frontend/BinASTTokenReaderMultipart.h
@@ -32,16 +32,17 @@ namespace frontend {
  */
 class MOZ_STACK_CLASS BinASTTokenReaderMultipart
     : public BinASTTokenReaderBase {
  public:
   class AutoList;
   class AutoTaggedTuple;
 
   using CharSlice = BinaryASTSupport::CharSlice;
+  using Context = BinASTTokenReaderBase::Context;
 
   // This implementation of `BinASTFields` is effectively `void`, as the format
   // does not embed field information.
   class BinASTFields {
    public:
     explicit BinASTFields(JSContext*) {}
   };
   using Chars = CharSlice;
@@ -78,63 +79,65 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading if an exception in pending is an error and
   // will cause assertion failures. Do NOT attempt to read once an exception
   // has been cleared: the token reader does NOT support recovery, by design.
 
   /**
    * Read a single `true | false` value.
    */
-  MOZ_MUST_USE JS::Result<bool> readBool();
+  MOZ_MUST_USE JS::Result<bool> readBool(const Context&);
 
   /**
    * Read a single `number` value.
    */
-  MOZ_MUST_USE JS::Result<double> readDouble();
+  MOZ_MUST_USE JS::Result<double> readDouble(const Context&);
 
   /**
    * Read a single `string | null` value.
    *
    * Fails if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom();
-  MOZ_MUST_USE JS::Result<JSAtom*> readAtom();
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readAtom(const Context&);
 
   /**
    * Read a single IdentifierName value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName();
-  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName();
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName(const Context&);
 
   /**
    * Read a single PropertyKey value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey();
+  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey(const Context&);
 
   /**
    * Read a single `string | null` value.
    *
    * MAY check if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&);
+  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&, const Context&);
 
   /**
    * Read a single `BinASTVariant | null` value.
    */
-  MOZ_MUST_USE JS::Result<mozilla::Maybe<BinASTVariant>> readMaybeVariant();
-  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant();
+  MOZ_MUST_USE JS::Result<mozilla::Maybe<BinASTVariant>> readMaybeVariant(
+      const Context&);
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(const Context&);
 
   /**
    * Read over a single `[Skippable]` subtree value.
    *
    * This does *not* attempt to parse the subtree itself. Rather, the
    * returned `SkippableSubTree` contains the necessary information
    * to parse/tokenize the subtree at a later stage
    */
-  MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree();
+  MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree(
+      const Context&);
 
   // --- Composite values.
   //
   // The underlying format does NOT allows for a `null` composite value.
   //
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading from a poisoned tokenizer is an error and
   // will cause assertion failures.
@@ -146,17 +149,18 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
    * @param guard (OUT) A guard, ensuring that we read the list correctly.
    *
    * The `guard` is dedicated to ensuring that reading the list has consumed
    * exactly all the bytes from that list. The `guard` MUST therefore be
    * destroyed at the point where the caller has reached the end of the list.
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    */
-  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, AutoList& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, const Context&,
+                                        AutoList& guard);
 
   /**
    * Start reading a tagged tuple.
    *
    * @param tag (OUT) The tag of the tuple.
    * @param fields Ignored, provided for API compatibility.
    * @param guard (OUT) A guard, ensuring that we read the tagged tuple
    * correctly.
@@ -166,22 +170,22 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
    * destroyed at the point where the caller has reached the end of the tuple.
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    *
    * @return out If the header of the tuple is invalid.
    */
   MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
       BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
-      AutoTaggedTuple& guard);
+      const Context&, AutoTaggedTuple& guard);
 
   /**
    * Read a single unsigned long.
    */
-  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong() {
+  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const Context&) {
     return readInternalUint32();
   }
 
  private:
   /**
    * Read a single uint32_t.
    */
   MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
--- a/js/src/frontend/binast/src/main.rs
+++ b/js/src/frontend/binast/src/main.rs
@@ -830,22 +830,28 @@ impl CPPExporter {
                             ""
                         },
                         s.reindent("        "))
             }
             _ => {
                 "".to_string()
             }
         };
-        format!("    JS::Result<{type_ok}> parse{prefix}{kind}({args}{extra});\n",
+        format!("    JS::Result<{type_ok}> parse{prefix}{kind}({args}{extra}{before_context}{context});\n",
             prefix = prefix,
             type_ok = type_ok,
             kind = kind,
             args = args,
             extra = extra,
+            before_context = if args.len() > 0 || extra_params.is_some() {
+                ", "
+            } else {
+                ""
+            },
+            context = "const Context& context",
         )
     }
 
     fn get_method_definition_start(&self, name: &NodeName, prefix: &str, args: &str,
                                    extra_params: &Option<Rc<String>>) -> String {
         let type_ok = self.get_type_ok(name);
         let kind = name.to_class_cases();
         let extra = match extra_params {
@@ -857,30 +863,37 @@ impl CPPExporter {
                             ""
                         },
                         s.reindent("        "))
             }
             _ => {
                 "".to_string()
             }
         };
-        format!("{parser_class_template}JS::Result<{type_ok}>\n{parser_class_name}::parse{prefix}{kind}({args}{extra})",
+        format!("{parser_class_template}JS::Result<{type_ok}>\n{parser_class_name}::parse{prefix}{kind}({args}{extra}{before_context}{context})",
             parser_class_template = self.rules.parser_class_template,
             prefix = prefix,
             type_ok = type_ok,
             parser_class_name = self.rules.parser_class_name,
             kind = kind,
             args = args,
             extra = extra,
+            before_context = if args.len() > 0 || extra_params.is_some() {
+                ", "
+            } else {
+                ""
+            },
+            context = "const Context& context",
         )
     }
 
     fn get_method_call(&self, var_name: &str, name: &NodeName,
                        prefix: &str, args: &str,
                        extra_params: &Option<Rc<String>>,
+                       context_name: &str,
                        call_kind: MethodCallKind) -> String {
         let type_ok_is_ok = match call_kind {
             MethodCallKind::Decl | MethodCallKind::Var => {
                 self.get_type_ok(name).to_str() == "Ok"
             }
             MethodCallKind::AlwaysDecl | MethodCallKind::AlwaysVar => {
                 false
             }
@@ -894,21 +907,28 @@ impl CPPExporter {
                             ""
                         },
                         s.reindent("    "))
             }
             _ => {
                 "".to_string()
             }
         };
-        let call = format!("parse{prefix}{name}({args}{extra})",
+        let call = format!("parse{prefix}{name}({args}{extra}{before_context}{context})",
                            prefix = prefix,
                            name = name.to_class_cases(),
                            args = args,
-                           extra = extra);
+                           extra = extra,
+                           before_context = if extra_params.is_some() || args.len() > 0 {
+                               ", "
+                           } else {
+                               ""
+                           },
+                           context = context_name
+        );
 
         if type_ok_is_ok {
             // Special case: `Ok` means that we shouldn't bind the return value.
             format!("MOZ_TRY({call});",
                     call = call)
         } else {
             match call_kind {
                 MethodCallKind::Decl | MethodCallKind::AlwaysDecl => {
@@ -1243,27 +1263,28 @@ impl CPPExporter {
             buffer.push_str(&format!("{bnf}
 {first_line}
 {{
     BinASTKind kind;
     BinASTFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
     const auto start = tokenizer_->offset();
 
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
 {call}
 
     MOZ_TRY(guard.done());
     return result;
 }}\n",
                 bnf = rendered_bnf,
                 call = self.get_method_call("result", name,
                                             "Sum", INTERFACE_ARGS,
                                             &extra_args,
+                                            "context",
                                             MethodCallKind::AlwaysDecl)
                     .reindent("    "),
                 first_line = self.get_method_definition_start(name, "", "",
                                                               &extra_params)
             ));
         }
 
         let inner_prefix = "Sum";
@@ -1288,16 +1309,17 @@ impl CPPExporter {
 
             buffer_cases.push_str(&format!("
       case BinASTKind::{variant_name}:
 {call}
 {arm_after}        break;",
                 call = self.get_method_call("result", node,
                                             "Interface", INTERFACE_ARGS,
                                             &extra_args,
+                                            "context",
                                             MethodCallKind::AlwaysVar)
                     .reindent("        "),
                 variant_name = node.to_cpp_enum_case(),
                 arm_after = rule_for_this_arm.after_arm.reindent("        ")
                     .newline_if_not_empty()));
         }
         buffer.push_str(&format!("\n{first_line}
 {{
@@ -1373,20 +1395,21 @@ impl CPPExporter {
 
 
         let rendered = format!("\n{first_line}
 {{
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    MOZ_TRY(tokenizer_->enterList(length, guard));{empty_check}
+    MOZ_TRY(tokenizer_->enterList(length, context, guard));{empty_check}
 {init}
 
-    for (uint32_t i = 0; i < length; ++i) {{
+    const Context childContext(context.arrayElement());
+    for (uint8_t i = 0; i < length; ++i) {{
 {call}
 {append}    }}
 
     MOZ_TRY(guard.done());
     return result;
 }}\n",
             first_line = first_line,
             empty_check =
@@ -1398,16 +1421,17 @@ impl CPPExporter {
         return raiseEmpty(\"{kind}\");
     }}
 ",
                         kind = kind)
                 },
             call = self.get_method_call("item",
                                         &parser.elements, "", "",
                                         &extra_args,
+                                        "childContext",
                                         MethodCallKind::Decl)
                 .reindent("        "),
             init = init,
             append = append);
         buffer.push_str(&rendered);
     }
 
     fn generate_implement_option(&self, buffer: &mut String, parser: &OptionParserData) {
@@ -1457,17 +1481,17 @@ impl CPPExporter {
         match named_implementation {
             NamedType::Interface(_) => {
                 buffer.push_str(&format!("{first_line}
 {{
     BinASTKind kind;
     BinASTFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
     {type_ok} result;
     if (kind == BinASTKind::{null}) {{
 {none_block}
     }} else if (kind == BinASTKind::{kind}) {{
         const auto start = tokenizer_->offset();
 {before}{call}{after}
     }} else {{
         return raiseInvalidKind(\"{kind}\", kind);
@@ -1480,16 +1504,17 @@ impl CPPExporter {
 ",
                     first_line = self.get_method_definition_start(&parser.name, "", "",
                                                                   &extra_params),
                     null = self.syntax.get_null_name().to_cpp_enum_case(),
                     call = self.get_method_call("result",
                                                 &parser.elements,
                                                 "Interface", INTERFACE_ARGS,
                                                 &extra_args,
+                                                "context",
                                                 MethodCallKind::AlwaysVar)
                         .reindent("        "),
                     before = rules_for_this_node.some_before
                         .map_or_else(|| "".to_string(),
                                      |s| s
                                      .reindent("        ")
                                      .newline_if_not_empty()),
                     after = rules_for_this_node.some_after
@@ -1510,17 +1535,17 @@ impl CPPExporter {
                 match type_.spec() {
                     &TypeSpec::TypeSum(_) => {
                 buffer.push_str(&format!("{first_line}
 {{
     BinASTKind kind;
     BinASTFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
     {type_ok} result;
     if (kind == BinASTKind::{null}) {{
 {none_block}
     }} else {{
         const auto start = tokenizer_->offset();
 {before}{call}{after}
     }}
     MOZ_TRY(guard.done());
@@ -1529,16 +1554,17 @@ impl CPPExporter {
 }}
 
 ",
                             first_line = self.get_method_definition_start(&parser.name, "", "",
                                                                           &extra_params),
                             call = self.get_method_call("result", &parser.elements,
                                                         "Sum", INTERFACE_ARGS,
                                                         &extra_args,
+                                                        "context",
                                                         MethodCallKind::AlwaysVar)
                                 .reindent("        "),
                             before = rules_for_this_node.some_before
                                 .map_or_else(|| "".to_string(),
                                              |s| s
                                              .reindent("        ")
                                              .newline_if_not_empty()),
                             after = rules_for_this_node.some_after
@@ -1566,17 +1592,17 @@ impl CPPExporter {
 }}
 
 ",
                                 first_line = first_line,
                                 kind = parser.name.to_str()));
                         } else {
                             buffer.push_str(&format!("{first_line}
 {{
-    BINJS_MOZ_TRY_DECL(result, tokenizer_->readMaybeAtom());
+    BINJS_MOZ_TRY_DECL(result, tokenizer_->readMaybeAtom(context));
 
 {build}
 
     return result;
 }}
 
 ",
                                 first_line = first_line,
@@ -1595,17 +1621,17 @@ impl CPPExporter {
 }}
 
 ",
                                 first_line = first_line,
                                 kind = parser.name.to_str()));
                         } else {
                             buffer.push_str(&format!("{first_line}
 {{
-    BINJS_MOZ_TRY_DECL(result, tokenizer_->readMaybeIdentifierName());
+    BINJS_MOZ_TRY_DECL(result, tokenizer_->readMaybeIdentifierName(context));
 
 {build}
 
     return result;
 }}
 
 ",
                                 first_line = first_line,
@@ -1660,17 +1686,17 @@ impl CPPExporter {
 
             // Generate public method
             buffer.push_str(&format!("{first_line}
 {{
     BinASTKind kind;
     BinASTFields fields(cx_);
     AutoTaggedTuple guard(*tokenizer_);
 
-    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
+    MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
     if (kind != BinASTKind::{kind}) {{
         return raiseInvalidKind(\"{kind}\", kind);
     }}
     const auto start = tokenizer_->offset();
 {call}
     MOZ_TRY(guard.done());
 
     return result;
@@ -1678,16 +1704,17 @@ impl CPPExporter {
 
 ",
                 first_line = self.get_method_definition_start(name, "", "",
                                                               &extra_params),
                 kind = name.to_cpp_enum_case(),
                 call = self.get_method_call("result", name,
                                             "Interface", INTERFACE_ARGS,
                                             &extra_args,
+                                            "context",
                                             MethodCallKind::AlwaysDecl)
                     .reindent("    ")
             ));
         }
 
         let inner_prefix = "Interface";
         if !self.refgraph.is_used(Rc::new(format!("{}{}", inner_prefix, name))) {
             return;
@@ -1702,83 +1729,111 @@ impl CPPExporter {
         let fields_type_list = format!("{{ {} }}", interface.contents()
             .fields()
             .iter()
             .map(|field| format!("BinASTField::{}", field.name().to_cpp_enum_case()))
             .format(", "));
 
         let mut fields_implem = String::new();
         for field in interface.contents().fields() {
+            let context = "fieldContext++";
+
             let rules_for_this_field = rules_for_this_interface.by_field.get(field.name())
                 .cloned()
                 .unwrap_or_default();
             let needs_block = rules_for_this_field.block_before_field.is_some() || rules_for_this_field.block_after_field.is_some();
 
             let var_name = field.name().to_cpp_field_case();
             let (decl_var, parse_var) = match field.type_().get_primitive(&self.syntax) {
                 Some(IsNullable { is_nullable: false, content: Primitive::Number }) => {
                     if needs_block {
                         (Some(format!("double {var_name};", var_name = var_name)),
-                            Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readDouble());", var_name = var_name)))
+                            Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readDouble({context}));",
+                                var_name = var_name,
+                                context = context)))
                     } else {
                         (None,
-                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readDouble());", var_name = var_name)))
+                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readDouble({context}));",
+                                var_name = var_name,
+                                context = context)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::UnsignedLong }) => {
                     if needs_block {
                         (Some(format!("uint32_t {var_name};", var_name = var_name)),
-                            Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readUnsignedLong());", var_name = var_name)))
+                            Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readUnsignedLong({context}));",
+                                var_name = var_name,
+                                context = context)))
                     } else {
                         (None,
-                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readUnsignedLong());", var_name = var_name)))
+                            Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readUnsignedLong({context}));",
+                                var_name = var_name,
+                                context = context)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::Boolean }) => {
                     if needs_block {
                         (Some(format!("bool {var_name};", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readBool());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readBool({context}));",
+                            var_name = var_name,
+                            context = context)))
                     } else {
                         (None,
-                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readBool());", var_name = var_name)))
+                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readBool({context}));",
+                            var_name = var_name,
+                            context = context)))
                     }
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::Offset }) => {
                     if needs_block {
                         (Some(format!("BinASTTokenReaderBase::SkippableSubTree {var_name};", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readSkippableSubTree());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readSkippableSubTree({context}));",
+                            var_name = var_name,
+                            context = context)))
                     } else {
                         (None,
-                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readSkippableSubTree());", var_name = var_name)))
+                        Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_->readSkippableSubTree({context}));",
+                            var_name = var_name,
+                            context = context)))
                     }
                 }
                 Some(IsNullable { content: Primitive::Void, .. }) => {
                     warn!("Internal error: We shouldn't have any `void` types at this stage.");
                     (Some(format!("// Skipping void field {}", field.name().to_str())),
                         None)
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::String }) => {
                     (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readAtom());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readAtom({context}));",
+                            var_name = var_name,
+                            context = context)))
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::IdentifierName }) => {
                     (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readIdentifierName());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readIdentifierName({context}));",
+                            var_name = var_name,
+                            context = context)))
                 }
                 Some(IsNullable { is_nullable: false, content: Primitive::PropertyKey }) => {
                     (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readPropertyKey());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readPropertyKey({context}));",
+                            var_name = var_name,
+                            context = context)))
                 }
                 Some(IsNullable { is_nullable: true, content: Primitive::String }) => {
                     (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readMaybeAtom());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readMaybeAtom({context}));",
+                            var_name = var_name,
+                            context = context)))
                 }
                 Some(IsNullable { is_nullable: true, content: Primitive::IdentifierName }) => {
                     (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)),
-                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readMaybeIdentifierName());", var_name = var_name)))
+                        Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_->readMaybeIdentifierName({context}));",
+                            var_name = var_name,
+                            context = context)))
                 }
                 Some(IsNullable { is_nullable: true, content: Primitive::PropertyKey }) => {
                     panic!("PropertyKey shouldn't be optional");
                 }
                 _else => {
                     let typename = TypeName::type_(field.type_());
                     let name = self.syntax.get_node_name(typename.to_str())
                         .expect("NodeName for the field type should exist.");
@@ -1792,16 +1847,17 @@ impl CPPExporter {
                     } else {
                         (None,
                          MethodCallKind::Decl)
                     };
 
                     (decl_var,
                      Some(self.get_method_call(var_name.to_str(),
                                                &name, "", "", &field_extra_args,
+                                               &context,
                                                call_kind)))
                 }
             };
             let rendered = {
                 if rules_for_this_field.replace.is_some() {
                     for &(condition, rule_name) in &[
                         (rules_for_this_field.before_field.is_some(), "before:"),
                         (rules_for_this_field.after_field.is_some(), "after:"),
@@ -1818,26 +1874,28 @@ impl CPPExporter {
                     let after_field = rules_for_this_field.after_field.reindent("    ");
                     let decl_var = if rules_for_this_field.declare.is_some() {
                         rules_for_this_field.declare.reindent("    ")
                     } else {
                         decl_var.reindent("    ")
                     };
                     if needs_block {
                         let parse_var = parse_var.reindent("        ");
-                        format!("{before_field}{decl_var}    {{
+                        format!("
+{before_field}{decl_var}    {{
 {block_before_field}{parse_var}{block_after_field}
     }}
 {after_field}",
                             before_field = before_field.reindent("    ").newline_if_not_empty(),
                             decl_var = decl_var.reindent("    ").newline_if_not_empty(),
                             block_before_field = rules_for_this_field.block_before_field.reindent("        ").newline_if_not_empty(),
                             parse_var = parse_var.reindent("        ").newline_if_not_empty(),
                             block_after_field = rules_for_this_field.block_after_field.reindent("        "),
-                            after_field = after_field.reindent("    "))
+                            after_field = after_field.reindent("    "),
+                        )
                     } else {
                         // We have a before_field and an after_field. This will create newlines
                         // for them.
                         format!("
 {before_field}{decl_var}{parse_var}{after_field}",
                             before_field = before_field.reindent("    ").newline_if_not_empty(),
                             decl_var = decl_var.reindent("    ").newline_if_not_empty(),
                             parse_var = parse_var.reindent("    ").newline_if_not_empty(),
@@ -1873,28 +1931,33 @@ impl CPPExporter {
 #endif // defined(DEBUG)",
                     fields_type_list = fields_type_list,
                     number_of_fields = number_of_fields)
             };
             buffer.push_str(&format!("{first_line}
 {{
     MOZ_ASSERT(kind == BinASTKind::{kind});
     BINJS_TRY(CheckRecursionLimit(cx_));
-{check_fields}
+{maybe_field_context}{check_fields}
 {pre}{fields_implem}
 {post}    return result;
 }}
 
 ",
                 check_fields = check_fields,
                 fields_implem = fields_implem,
                 pre = init.newline_if_not_empty(),
                 post = build_result.newline_if_not_empty(),
                 kind = name.to_cpp_enum_case(),
                 first_line = first_line,
+                maybe_field_context = if interface.contents().fields().len() > 0 {
+                    "    Context fieldContext = Context::firstField(kind);\n"
+                } else {
+                    ""
+                },
             ));
         }
     }
 
     /// Generate C++ code for SpiderMonkey
     fn to_spidermonkey_cpp(&self) -> String {
         let mut buffer = String::new();
 
@@ -1962,17 +2025,17 @@ impl CPPExporter {
                     kind = kind,
                     cases = enum_.strings()
                             .iter()
                             .map(|s| format!("    \"{}\"", s))
                             .format(",\n")
                 );
                 buffer.push_str(&format!("{rendered_doc}{first_line}
 {{
-    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
+    BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
 {convert}
 }}
 
 ",
                     rendered_doc = rendered_doc,
                     convert = convert,
                     first_line = self.get_method_definition_start(kind, "", "",