WIP: Ported BinSource to enum class taggedTuple draft
authorDavid Teller <dteller@mozilla.com>
Thu, 27 Jul 2017 15:18:47 +0200
changeset 641347 2e984780380a5d2fbf48838b00fdfdf85c82f2a4
parent 641346 af1f8f5422fe09e984bf2cced0ebe30fe08de48e
child 641348 43f2d9ccd502a1562ba6fb682ea8060905a9ca91
push id72504
push userdteller@mozilla.com
push dateSun, 06 Aug 2017 22:28:40 +0000
milestone57.0a1
WIP: Ported BinSource to enum class taggedTuple MozReview-Commit-ID: EQSqkL28u4U
js/src/frontend/BinSource.cpp
js/src/frontend/BinTokenReader.cpp
js/src/frontend/BinTokenReader.h
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -108,22 +108,22 @@ private:
     bool parseBlockStatement(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
     bool parseCatchClause(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
     bool parseVariableDeclarator(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
     bool parsePatternList(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
     bool parseDirectiveList(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
 
     // --- Parse the contents of a node whose kind has already been determined.
 
-    bool parseFunctionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
-    bool parsePatternAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
-    bool parseBlockStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
-    bool parseExpressionStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
-    bool parseExpressionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
-    bool parseVariableDeclarationAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
+    bool parseFunctionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+    bool parsePatternAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+    bool parseBlockStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+    bool parseExpressionStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+    bool parseExpressionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+    bool parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
 
     // --- Utilities.
 
     bool readString(SimpleTokenReader* reader, std::string&);
     bool readString(SimpleTokenReader* reader, MutableHandleString);
     bool readString(SimpleTokenReader* reader, MutableHandleAtom);
 
     const Directives& currentDirectives() const;
@@ -190,118 +190,127 @@ ASTReader::parse(char* start, char* stop
 }
 
 bool
 ASTReader::parseProgram(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
     if (out) {
         // Already parsed.
         return this->raiseError();
     }
-    SimpleTokenReader::Fields fields(this->cx);
+    BinKind kind;
+    SimpleTokenReader::BinFields fields(this->cx);
     SimpleTokenReader sub(this->cx);
 
-    std::string name;
-    if (!reader->taggedTuple(&name, &fields, &sub)) {
+    if (!reader->taggedTuple(kind, fields, &sub)) {
         return false;
     }
 
-    if (name != "Program") {
+    if (kind != BinKind::program) {
         return this->raiseError();
     }
 
-    return this->parseBlockStatementAux(&sub, name, &fields, out);
+    return this->parseBlockStatementAux(&sub, kind, fields, out);
 }
 
 bool
 ASTReader::parseScope(SimpleTokenReader* reader,
     ScopeData& out)
 {
     if (out.hasDirectEval.isSome()
        || out.letNames.address() != nullptr
        || out.constNames.address() != nullptr
        || out.varNames.address() != nullptr
        || out.capturedNames.address() != nullptr) {
            // Already parsed.
            return this->raiseError();
     }
 
-    SimpleTokenReader::Fields fields(this->cx);
+    BinKind kind;
+    SimpleTokenReader::BinFields fields(this->cx);
     SimpleTokenReader sub(this->cx);
 
-    std::string name;
-    if (!reader->taggedTuple(&name, &fields, &sub)) {
+    if (!reader->taggedTuple(kind, fields, &sub)) {
         return false;
     }
 
-    if (name != BINJS_SCOPE) {
+    if (kind != BinKind::binjs_scope) {
         return this->raiseError();
     }
 
     for (auto field: fields) {
-        if (field == BINJS_DIRECT_EVAL) {
-            if (!this->parseBool(reader, &out.hasDirectEval)) {
-                return false;
-            }
-        } else if (field == BINJS_LET_NAME) {
-            if (!this->parseStringList(reader, &out.letNames)) {
-                return false;
-            }
-        } else if (field == BINJS_CONST_NAME) {
-            if (!this->parseStringList(reader, &out.constNames)) {
-                return false;
-            }
-        } else if (field == BINJS_VAR_NAME) {
-            if (!this->parseStringList(reader, &out.varNames)) {
-                return false;
-            }
-        } else if (field == BINJS_CAPTURED_NAME) {
-            if (!this->parseStringSet(reader, &out.capturedNames)) {
-                return false;
-            }
-        } else {
-            return this->raiseError();
+        switch (field) {
+            case BinField::has_direct_eval:
+                if (!this->parseBool(reader, &out.hasDirectEval)) {
+                    return false;
+                }
+                break;
+            case BinField::let_decl_names:
+                if (!this->parseStringList(reader, &out.letNames)) {
+                    return false;
+                }
+                break;
+            case BinField::const_decl_names:
+                if (!this->parseStringList(reader, &out.constNames)) {
+                    return false;
+                }
+                break;
+            case BinField::var_decl_names:
+                if (!this->parseStringList(reader, &out.varNames)) {
+                    return false;
+                }
+                break;
+            case BinField::captured_names:
+                if (!this->parseStringSet(reader, &out.capturedNames)) {
+                    return false;
+                }
+                break;
+            default:
+                return this->raiseError();
         }
     }
 
     if (out.hasDirectEval.isNothing()
        || out.letNames.address() == nullptr
        || out.constNames.address() == nullptr
        || out.varNames.address() == nullptr
        || out.capturedNames.address() == nullptr) {
            return this->raiseError();
        }
    return true;
 }
 
 bool
 ASTReader::parseBlockStatementAux(SimpleTokenReader* reader,
-    const std::string& name,
-    const SimpleTokenReader::Fields* fields,
+    const BinKind name,
+    const SimpleTokenReader::BinFields& fields,
     UniquePtr<ParseNode>& out)
 {
     UniquePtr<ParseNode> body;
     UniquePtr<ParseNode> directives;
     ScopeData scope(this->cx);
 
-    for (auto field: *fields) {
-        if (field == BINJS_SCOPE) {
-            if (!this->parseScope(reader, scope)) {
-                return false;
-            }
-        } else if (field == "body") {
-            if (!this->parseStatementList(reader, body)) {
-                return false;
-            }
-        } else if (field == "directives") {
-            if (!this->parseDirectiveList(reader, directives)) {
-                return false;
-            }
-        } else {
-            this->raiseError();
-            return false;
+    for (auto field: fields) {
+        switch (field) {
+            case BinField::binjs_scope:
+                if (!this->parseScope(reader, scope)) {
+                    return false;
+                }
+                break;
+            case BinField::body:
+                if (!this->parseStatementList(reader, body)) {
+                    return false;
+                }
+                break;
+            case BinField::directives:
+                if (!this->parseDirectiveList(reader, directives)) {
+                    return false;
+                }
+                break;
+            default:
+                return this->raiseError();
         }
     }
 
     // Check if all fields have been parsed.
     if (!body || !directives || !scope.isSome()) {
         // FIXME: Once we have headers + header validation, this error check
         // should become an assertion.
         return this->raiseError();
@@ -407,187 +416,217 @@ ASTReader::parseStatementList(SimpleToke
     return true;
 }
 
 bool
 ASTReader::parseStatement(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
     if (out) {
         return this->raiseError();
     }
-    SimpleTokenReader::Fields fields(this->cx);
+    BinKind kind;
+    SimpleTokenReader::BinFields fields(this->cx);
     SimpleTokenReader sub(this->cx);
 
-    std::string name;
-    if (!reader->taggedTuple(&name, &fields, &sub)) {
+    if (!reader->taggedTuple(kind, fields, &sub)) {
         return false;
     }
 
-    if (name == "EmptyStatement") {
-        UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NOP, TokenPos()));
-        if (!result) {
-            return false;
+    switch (kind) {
+        case BinKind::empty_statement: {
+            UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NOP, TokenPos()));
+            if (!result) {
+                return false;
+            }
+            out = Move(result);
+            break;
         }
-        out = Move(result);
-    } else if (name == "BlockStatement") {
-        UniquePtr<ParseNode> body;
-        if (!this->parseBlockStatementAux(&sub, name, &fields, body)) {
-            return false;
+        case BinKind::block_statement: {
+            UniquePtr<ParseNode> body;
+            if (!this->parseBlockStatementAux(&sub, kind, fields, body)) {
+                return false;
+            }
+            out = Move(body);
+            break;
         }
-        out = Move(body);
-    } else if (name == "ExpressionStatement") {
-        UniquePtr<ParseNode> body;
-        if (!this->parseExpressionStatementAux(&sub, name, &fields, body)) {
-            return false;
+        case BinKind::expression_statement: {
+            UniquePtr<ParseNode> body;
+            if (!this->parseExpressionStatementAux(&sub, kind, fields, body)) {
+                return false;
+            }
+            out = Move(body);
+            break;
         }
-        out = Move(body);
-    } else if (name == "DebuggerStatement") {
-        UniquePtr<ParseNode> result(new_<DebuggerStatement>(TokenPos()));
-        if (!result) {
-            return false;
+        case BinKind::debugger_statement: {
+            UniquePtr<ParseNode> result(new_<DebuggerStatement>(TokenPos()));
+            if (!result) {
+                return false;
+            }
+            out = Move(result);
+            break;
         }
-        out = Move(result);
-    } else if (name == "WithStatement") {
-        UniquePtr<ParseNode> body;
-        UniquePtr<ParseNode> expr;
-        for (auto field: fields) {
-            if (field == "body") {
-                if (!this->parseStatement(&sub, body)) {
-                    return false;
+        case BinKind::with_statement: {
+            UniquePtr<ParseNode> body;
+            UniquePtr<ParseNode> expr;
+            for (auto field: fields) {
+                switch (field) {
+                    case BinField::body:
+                        if (!this->parseStatement(&sub, body)) {
+                            return false;
+                        }
+                        break;
+                    case BinField::object:
+                        if (!this->parseExpression(&sub, body)) {
+                            return false;
+                        }
+                        break;
+                    default:
+                        return this->raiseError();
                 }
-            } else if (field == "object") {
-                if (!this->parseExpression(&sub, body)) {
-                    return false;
-                }
-            } else {
+            }
+            if (!body || !expr) {
+                return false;
+            }
+
+            UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(),
+                                            expr.get(), body.get()));
+            if (!result) {
                 return this->raiseError();
             }
-        }
-        if (!body || !expr) {
-            return false;
-        }
+            Unused << expr.release();
+            Unused << body.release();
 
-        UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(),
-                                        expr.get(), body.get()));
-        if (!result) {
-            return this->raiseError();
+            out = Move(result);
+            break;
         }
-        Unused << expr.release();
-        Unused << body.release();
-
-        out = Move(result);
-
-    } else if (name == "ReturnStatement") {
+        case BinKind::return_statement: {
+            UniquePtr<ParseNode> arg;
+            for (auto field: fields) {
+                switch (field) {
+                    case BinField::argument:
+                        if (!this->parseExpression(&sub, arg)) { // FIXME: Make sure that it works with no expression.
+                            return false;
+                        }
+                        break;
+                    default:
+                        return this->raiseError();
+                }
+            }
 
-        UniquePtr<ParseNode> arg;
-        for (auto field: fields) {
-            if (field == "argument") {
-                if (!this->parseExpression(&sub, arg)) { // FIXME: Make sure that it works with no expression.
-                    return false;
-                }
-            } else {
+            // `arg` is optional, so we don't check whether it's `nullptr`.
+            UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, TokenPos(), arg.get()));
+            if (!result) {
                 return this->raiseError();
             }
+
+            Unused << arg.release();
+            out = Move(result);
+            break;
         }
-
-        // `arg` is optional, so we don't check whether it's `nullptr`.
-        UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, TokenPos(), arg.get()));
-        if (!result) {
-            return this->raiseError();
-        }
-
-        Unused << arg.release();
-        out = Move(result);
-
-    } else if (name == "LabeledStatement") {
+        case BinKind::labeled_statement: {
+            UniquePtr<PropertyName> label;
+            UniquePtr<ParseNode> body;
 
-        UniquePtr<PropertyName> label;
-        UniquePtr<ParseNode> body;
+            for (auto field: fields) {
+                switch (field) {
+                    case BinField::label:
+                        if (!this->parsePropertyName(&sub, label)) {
+                            return false;
+                        }
+                        break;
+                    case BinField::body:
+                        if (!this->parseStatement(&sub, body)) {
+                            return false;
+                        }
+                        break;
+                    default:
+                        return this->raiseError();
+                }
+            }
 
-        for (auto field: fields) {
-            if (field == "label") {
-                if (!this->parsePropertyName(&sub, label)) {
-                    return false;
-                }
-            } else if (field == "body") {
-                if (!this->parseStatement(&sub, body)) {
-                    return false;
-                }
-            } else {
+            if (!label || !body) {
                 return this->raiseError();
             }
-        }
 
-        if (!label || !body) {
-            return this->raiseError();
-        }
+            UniquePtr<ParseNode> result(new_<LabeledStatement>(label.get(), body.get(), 0));
+            if (!result) {
+                return false;
+            }
 
-        UniquePtr<ParseNode> result(new_<LabeledStatement>(label.get(), body.get(), 0));
-        if (!result) {
-            return false;
-        }
-
-        Unused << label.release();
-        Unused << body.release();
-        out = Move(result);
-
-    } else if (name == "BreakStatement" || name == "ContinueStatement") {
+            Unused << label.release();
+            Unused << body.release();
+            out = Move(result);
+            break;
+    }
+    case BinKind::break_statement: MOZ_FALLTHROUGH;
+    case BinKind::continue_statement: {
 
         UniquePtr<PropertyName> label;
 
         for (auto field: fields) {
-            if (field == "label") {
-                if (!this->parsePropertyName(&sub, label)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+            switch (field) {
+                case BinField::label:
+                    if (!this->parsePropertyName(&sub, label)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!label) {
             return this->raiseError();
         }
 
-        if (name == "BreakStatement") {
+        if (kind == BinKind::break_statement) {
             UniquePtr<ParseNode> result(new_<BreakStatement>(label.get(), TokenPos()));
             if (!result) {
                 return false;
             }
             out = Move(result);
         } else {
             UniquePtr<ParseNode> result(new_<ContinueStatement>(label.get(), TokenPos()));
             if (!result) {
                 return false;
             }
             out = Move(result);
         }
 
         Unused << label.release();
+        break;
 
-    } else if (name == "IfStatement") {
+    }
+    case BinKind::if_statement: {
 
         UniquePtr<ParseNode> test;
         UniquePtr<ParseNode> consequent;
         UniquePtr<ParseNode> alternate; // Optional
 
         for (auto field: fields) {
-            if (field == "test") {
-                if (!this->parseExpression(&sub, test)) {
-                    return false;
+            switch (field) {
+                case BinField::test: {
+                    if (!this->parseExpression(&sub, test)) {
+                        return false;
+                    }
+                    break;
                 }
-            } else if (field == "consequent") {
-                if (!this->parseStatement(&sub, consequent)) {
-                    return false;
+                case BinField::consequent: {
+                    if (!this->parseStatement(&sub, consequent)) {
+                        return false;
+                    }
+                    break;
                 }
-            } else if (field == "alternate") {
-                if (!this->parseStatement(&sub, alternate)) {
-                    return false;
+                case BinField::alternate: {
+                    if (!this->parseStatement(&sub, alternate)) {
+                        return false;
+                    }
+                    break;
                 }
-            } else {
-                return this->raiseError();
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!test || !consequent) {
             // Do not test `alternate`, since that value is optional.
             return this->raiseError();
         }
 
@@ -596,82 +635,95 @@ ASTReader::parseStatement(SimpleTokenRea
             return false;
         }
 
         Unused << test.release();
         Unused << consequent.release();
         Unused << alternate.release();
 
         out = Move(result);
-
-    } else if (name == "SwitchStatement") {
+        break;
+    }
+    case BinKind::switch_statement: {
 
         UniquePtr<ParseNode> discriminant;
         UniquePtr<ParseNode> cases;
 
         for (auto field: fields) {
-            if (field == "discriminant") {
-                if (!this->parseExpression(&sub, discriminant)) {
-                    return false;
+            switch (field) {
+                case BinField::discriminant: {
+                    if (!this->parseExpression(&sub, discriminant)) {
+                        return false;
+                    }
+                    break;
                 }
-            } else if (field == "cases") {
-                if (!this->parseSwitchCaseList(&sub, cases)) {
-                    return false;
+                case BinField::cases: {
+                    if (!this->parseSwitchCaseList(&sub, cases)) {
+                        return false;
+                    }
+                    break;
                 }
-            } else {
-                return this->raiseError();
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!discriminant || !cases) {
             return this->raiseError();
         }
 
         UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, TokenPos(), discriminant.get(), cases.get()));
         if (!result) {
             return false;
         }
 
         Unused << discriminant.release();
         Unused << cases.release();
         out = Move(result);
-
-    } else if (name == "SwitchCase") {
+        break;
+    }
+    case BinKind::switch_case: {
 
         UniquePtr<ParseNode> test;
         UniquePtr<ParseNode> consequent;
 
         for (auto field: fields) {
-            if (field == "test") {
-                if (!this->parseExpression(&sub, test)) {
-                    return false;
-                }
-            } else if (field == "consequent") {
-                if (!this->parseStatementList(&sub, consequent)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+            switch (field) {
+                case BinField::test:
+                    if (!this->parseExpression(&sub, test)) {
+                        return false;
+                    }
+                    break;
+                case BinField::consequent:
+                    if (!this->parseStatementList(&sub, consequent)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         UniquePtr<ParseNode> result(new_<CaseClause>(test.get(), consequent.get(), 0));
         if (!result) {
             return false;
         }
 
         Unused << test.release();
         Unused << consequent.release();
         out = Move(result);
+        break;
 
-    } else if (name == "ThrowStatement") {
+    }
+
+    case BinKind::throw_statement: {
 
         UniquePtr<ParseNode> arg;
         for (auto field: fields) {
-            if (field == "argument") {
+            if (field == BinField::arguments) {
                 if (!this->parseExpression(&sub, arg)) {
                     return false;
                 }
             } else {
                 return this->raiseError();
             }
         }
 
@@ -681,38 +733,45 @@ ASTReader::parseStatement(SimpleTokenRea
 
         UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_THROW, JSOP_THROW, TokenPos(), arg.get()));
         if (!result) {
             return this->raiseError();
         }
 
         Unused << arg.release();
         out = Move(result);
+        break;
 
-    } else if (name == "TryStatement") {
+    }
+
+    case BinKind::try_statement: {
 
         UniquePtr<ParseNode> block;
         UniquePtr<ParseNode> handler;
         UniquePtr<ParseNode> finalizer;
 
         for (auto field: fields) {
-            if (field == "block") {
-                if (!this->parseBlockStatement(&sub, block)) {
-                    return false;
-                }
-            } else if (field == "handler") {
-                if (!this->parseCatchClause(&sub, handler)) {
-                    return false;
-                }
-            } else if (field == "finalizer") {
-                if (!this->parseBlockStatement(&sub, finalizer)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+            switch (field) {
+                case BinField::block:
+                    if (!this->parseBlockStatement(&sub, block)) {
+                        return false;
+                    }
+                    break;
+                case BinField::handler:
+                    if (!this->parseCatchClause(&sub, handler)) {
+                        return false;
+                    }
+                    break;
+                case BinField::finalizer:
+                    if (!this->parseBlockStatement(&sub, finalizer)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!block || !handler) { // `finalizer` is optional
             return this->raiseError();
         }
 
         UniquePtr<ParseNode> result(new_<TernaryNode>(PNK_TRY, JSOP_NOP, block.get(), handler.get(), finalizer.get(), TokenPos()));
@@ -720,41 +779,48 @@ ASTReader::parseStatement(SimpleTokenRea
             return false;
         }
 
         Unused << block.release();
         Unused << handler.release();
         Unused << finalizer.release();
 
         out = Move(result);
+        break;
 
-    } else if (name == "WhileStatement" || name == "DoWhileStatement") {
+    }
+
+    case BinKind::while_statement: MOZ_FALLTHROUGH;
+    case BinKind::do_while_statement: {
 
         UniquePtr<ParseNode> test;
         UniquePtr<ParseNode> body;
 
         for (auto field: fields) {
-            if (field == "test") {
-                if (!this->parseExpression(&sub, test)) {
-                    return false;
-                }
-            } else if (field == "body") {
-                if (!this->parseStatement(&sub, test)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+            switch (field) {
+                case BinField::test:
+                    if (!this->parseExpression(&sub, test)) {
+                        return false;
+                    }
+                    break;
+                case BinField::body:
+                    if (!this->parseStatement(&sub, test)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!test || !body) {
             return this->raiseError();
         }
 
-        if (name == "WhileStatement") {
+        if (kind == BinKind::while_statement) {
             UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WHILE, JSOP_NOP, TokenPos(), body.get(), test.get()));
 
             if (!result) {
                 return false;
             }
             out = Move(result);
         } else {
             UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, TokenPos(), body.get(), test.get()));
@@ -762,66 +828,72 @@ ASTReader::parseStatement(SimpleTokenRea
             if (!result) {
                 return false;
             }
             out = Move(result);
         }
 
         Unused << test.release();
         Unused << body.release();
+        break;
+    }
 
-    } else if (name == "ForStatement") {
+    case BinKind::for_statement: {
 
         UniquePtr<ParseNode> init; // Optional
         UniquePtr<ParseNode> test; // Optional
         UniquePtr<ParseNode> update; // Optional
         ScopeData scope(this->cx); // Optional
         UniquePtr<ParseNode> body; // Required
 
         for (auto field: fields) {
-            if (field == "init") {
-
-                // This can be either a VarDecl or an Expression.
-                SimpleTokenReader::Fields subFields(this->cx);
-                SimpleTokenReader subSub(this->cx);
-                std::string subName;
+            switch (field) {
+                case BinField::init: {
+                    // This can be either a VarDecl or an Expression.
+                    SimpleTokenReader::BinFields subFields(this->cx);
+                    SimpleTokenReader subSub(this->cx);
+                    BinKind subKind;
 
-                if (!sub.taggedTuple(&subName, &subFields, &subSub)) {
-                    return false;
-                }
-
-
-                if (subName == "VariableDeclaration") {
-                    if (!this->parseVariableDeclarationAux(&subSub, subName, &subFields, init)) {
-                        return false;
-                    }
-                } else /* Parse as expression */ {
-                    if (!this->parseExpressionAux(&subSub, subName, &subFields, init)) {
+                    if (!sub.taggedTuple(subKind, subFields, &subSub)) {
                         return false;
                     }
-                }
 
-            } else if (field == "test") {
-                if (!this->parseExpression(&sub, test)) {
-                    return false;
-                }
-            } else if (field == "update") {
-                if (!this->parseExpression(&sub, update)) {
-                    return false;
+                    if (subKind == BinKind::variable_declaration) {
+                        if (!this->parseVariableDeclarationAux(&subSub, subKind, subFields, init)) {
+                            return false;
+                        }
+                    } else /* Parse as expression */ {
+                        if (!this->parseExpressionAux(&subSub, subKind, subFields, init)) {
+                            return false;
+                        }
+                    }
+                    break;
                 }
-            } else if (field == BINJS_SCOPE) {
-                if (!this->parseScope(&sub, scope)) {
-                    return false;
-                }
-            } else if (field == "body") {
-                if (!this->parseStatement(&sub, body)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+                case BinField::test:
+                    if (!this->parseExpression(&sub, test)) {
+                        return false;
+                    }
+                    break;
+                case BinField::update:
+                    if (!this->parseExpression(&sub, update)) {
+                        return false;
+                    }
+                    break;
+                case BinField::binjs_scope:
+                    if (!this->parseScope(&sub, scope)) {
+                        return false;
+                    }
+                    break;
+                case BinField::body:
+                    if (!this->parseStatement(&sub, body)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!body) {
             return this->raiseError();
         }
 
         UniquePtr<ParseNode> forHead(new_<TernaryNode>(PNK_FORHEAD, JSOP_NOP, init.get(), test.get(), update.get(), TokenPos()));
@@ -838,61 +910,66 @@ ASTReader::parseStatement(SimpleTokenRea
         if (!result) {
             return false;
         }
 
         Unused << forHead.release();
         Unused << body.release();
 
         out = Move(result);
+        break;
+    }
 
-    } else if (name == "ForInStatement") {
+    case BinKind::for_in_statement: {
 
         UniquePtr<ParseNode> left;
         UniquePtr<ParseNode> right;
         UniquePtr<ParseNode> body;
         ScopeData scope(this->cx); // Optional
 
         for (auto field: fields) {
-            if (field == "left") {
-
-                // This can be either a VarDecl or a Pattern.
-                SimpleTokenReader::Fields subFields(this->cx);
-                SimpleTokenReader subSub(this->cx);
-                std::string subName;
+            switch (field) {
+                case BinField::left: {
+                    // This can be either a VarDecl or a Pattern.
+                    SimpleTokenReader::BinFields subFields(this->cx);
+                    SimpleTokenReader subSub(this->cx);
+                    BinKind subKind;
 
-                if (!sub.taggedTuple(&subName, &subFields, &subSub)) {
-                    return false;
-                }
-
-
-                if (subName == "VariableDeclaration") {
-                    if (!this->parseVariableDeclarationAux(&subSub, subName, &subFields, left)) {
+                    if (!sub.taggedTuple(subKind, subFields, &subSub)) {
                         return false;
                     }
-                } else /* Parse as pattern */ {
-                    if (!this->parsePatternAux(&subSub, subName, &subFields, left)) {
+
+                    if (subKind == BinKind::variable_declaration) {
+                        if (!this->parseVariableDeclarationAux(&subSub, subKind, subFields, left)) {
+                            return false;
+                        }
+                    } else /* Parse as pattern */ {
+                        if (!this->parsePatternAux(&subSub, subKind, subFields, left)) {
+                            return false;
+                        }
+                    }
+                    break;
+                }
+                case BinField::right:
+                    if (!this->parseExpression(&sub, right)) {
                         return false;
                     }
-                }
-
-            } else if (field == "right") {
-                if (!this->parseExpression(&sub, right)) {
-                    return false;
-                }
-            } else if (field == "body") {
-                if (!this->parseExpression(&sub, body)) {
-                    return false;
-                }
-            } else if (field == BINJS_SCOPE) {
-                if (!this->parseScope(&sub, scope)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+                    break;
+                case BinField::body:
+                    if (!this->parseExpression(&sub, body)) {
+                        return false;
+                    }
+                    break;
+                case BinField::binjs_scope:
+                    if (!this->parseScope(&sub, scope)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!left || !right || !body) {
             return this->raiseError();
         }
 
         UniquePtr<ParseNode> forHead(new_<TernaryNode>(PNK_FORIN, JSOP_NOP, left.get(), nullptr, right.get(), TokenPos()));
@@ -908,43 +985,51 @@ ASTReader::parseStatement(SimpleTokenRea
         if (!result) {
             return false;
         }
 
         Unused << forHead.release();
         Unused << body.release();
 
         out = Move(result);
+        break;
 
-    } else if (name == "FunctionDeclaration") {
+    }
+
+    case BinKind::function_declaration: {
 
         RootedAtom funName(this->cx);
         UniquePtr<ParseNode> params;
         UniquePtr<ParseNode> body;
         ScopeData scope(this->cx);
 
         for (auto field: fields) {
-            if (field == "id") {
-                if (!this->readString(&sub, &funName)) {
-                    return false;
-                }
-            } else if (field == "params") {
-                if (!this->parsePatternList(&sub, params)) {
-                    return false;
-                }
-            } else if (field == "body") {
-                if (!this->parseStatement(&sub, body)) {
-                    return false;
-                }
-            } else if (field == BINJS_SCOPE) {
-                if (!this->parseScope(&sub, scope)) {
-                    return false;
-                }
-            } else {
-                return this->raiseError();
+            switch (field) {
+                case BinField::id:
+                    if (!this->readString(&sub, &funName)) {
+                        return false;
+                    }
+                    break;
+                case BinField::params:
+                    if (!this->parsePatternList(&sub, params)) {
+                        return false;
+                    }
+                    break;
+                case BinField::body:
+                    if (!this->parseStatement(&sub, body)) {
+                        return false;
+                    }
+                    break;
+                case BinField::binjs_scope:
+                    if (!this->parseScope(&sub, scope)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    return this->raiseError();
             }
         }
 
         if (!funName || !params || !body || !scope.isSome()) {
             return this->raiseError();
         }
 
         RootedFunction fun(this->cx,
@@ -989,100 +1074,108 @@ ASTReader::parseStatement(SimpleTokenRea
             return false;
         }
         result->pn_funbox = funbox;
         result->pn_body   = params.release();
 
         out = Move(result);
 
         // FIXME: Scope
+        break;
 
-    } else if (name == "VariableDeclaration") {
-
-        if (!this->parseVariableDeclarationAux(&sub, name, &fields, out)) {
+    }
+    case BinKind::variable_declaration:
+        if (!this->parseVariableDeclarationAux(&sub, kind, fields, out)) {
             return false;
         }
-
-    } else {
+        break;
+    default:
         return this->raiseError();
     }
 
     return true;
 }
 
 bool
-ASTReader::parseVariableDeclarationAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out) {
+ASTReader::parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind name, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
     if (!out) {
         return this->raiseError();
     }
 
     ParseNodeKind kind = PNK_LIMIT;
     JSOp op = JSOP_NOP;
     UniquePtr<ParseNode> result;
 
-    for (auto field: *fields) {
-        if (field == "kind") {
-            std::string kindName;
-            if (!this->readString(reader, kindName)) {
-                return false;
-            }
+    for (auto field: fields) {
+        switch (field) {
+            case BinField::kind: {
+                std::string kindName;
+                if (!this->readString(reader, kindName)) {
+                    return false;
+                }
 
-            if (kindName == "let") {
-                kind = PNK_LET;
-                op = JSOP_DEFLET;
-            } else if (kindName == "var") {
-                kind = PNK_VAR;
-                op = JSOP_DEFVAR;
-            } else if (kindName == "const") {
-                kind = PNK_CONST;
-                op = JSOP_DEFCONST;
-            } else {
-                return this->raiseError();
+                if (kindName == "let") {
+                    kind = PNK_LET;
+                    op = JSOP_DEFLET;
+                } else if (kindName == "var") {
+                    kind = PNK_VAR;
+                    op = JSOP_DEFVAR;
+                } else if (kindName == "const") {
+                    kind = PNK_CONST;
+                    op = JSOP_DEFCONST;
+                } else {
+                    return this->raiseError();
+                }
+                break;
             }
-        } else if (field == "declarations") {
-            if (result) {
-                // Already parsed.
-                return this->raiseError();
-            }
+            case BinField::declarations: {
+                if (result) {
+                    // Already parsed.
+                    return this->raiseError();
+                }
 
-            uint32_t length;
-            SimpleTokenReader sub(this->cx);
+                uint32_t length;
+                SimpleTokenReader sub(this->cx);
 
-            if (!reader->readList(&length, &sub)) {
-                return false;
-            }
+                if (!reader->readList(&length, &sub)) {
+                    return false;
+                }
 
-            if (length == 0) {
-                return this->raiseError();
-            }
+                if (length == 0) {
+                    return this->raiseError();
+                }
 
-            UniquePtr<ParseNode> root(new_<ListNode>(PNK_LIMIT /*Placeholder*/, JSOP_NOP/*Placeholder*/, TokenPos()));
-            if (!root) {
-                return false;
-            }
+                UniquePtr<ParseNode> root(new_<ListNode>(PNK_LIMIT /*Placeholder*/, JSOP_NOP/*Placeholder*/, TokenPos()));
+                if (!root) {
+                    return false;
+                }
 
-            UniquePtr<ParseNode> first;
-            if (!this->parseVariableDeclarator(&sub, first)) {
-                return false;
-            }
-            root->initList(first.release());
+                UniquePtr<ParseNode> first;
+                if (!this->parseVariableDeclarator(&sub, first)) {
+                    return false;
+                }
+                root->initList(first.release());
 
 
-            for (uint32_t i = 1; i < length; ++i) {
-                UniquePtr<ParseNode> current;
-                if (!this->parseVariableDeclarator(&sub, current)) {
-                    return false;
+                for (uint32_t i = 1; i < length; ++i) {
+                    UniquePtr<ParseNode> current;
+                    if (!this->parseVariableDeclarator(&sub, current)) {
+                        return false;
+                    }
+                    if (!current) {
+                        return this->raiseError();
+                    }
+                    root->append(current.release());
                 }
-                if (!current) {
-                    return this->raiseError();
-                }
-                root->append(current.release());
+
+                result = Move(root);
+                break;
             }
-
-            result = Move(root);
+            default:
+                return this->raiseError();
         }
     }
 
     if (!result || kind == PNK_LIMIT) {
         return this->raiseError();
     }
 
     result->setKind(kind);
@@ -1104,54 +1197,69 @@ ASTReader::parseBool(SimpleTokenReader* 
 }
 
 bool
 ASTReader::parseExpression(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
     if (out) {
         return this->raiseError();
     }
 
-    SimpleTokenReader::Fields fields(this->cx);
+    SimpleTokenReader::BinFields fields(this->cx);
     SimpleTokenReader sub(this->cx);
+    BinKind kind;
 
-    std::string name;
-    if (!reader->taggedTuple(&name, &fields, &sub)) {
+    if (!reader->taggedTuple(kind, fields, &sub)) {
         return false;
     }
 
-    if (name == "ThisExpression") {
-        // FIXME: Implement
-    } else if (name == "ArrayExpression") {
-        // FIXME: Implement
-    } else if (name == "ObjectExpression") {
-        // FIXME: Implement
-    } else if (name == "FunctionExpression") {
-        // FIXME: Implement
-    } else if (name == "UnaryExpression") {
-        // FIXME: Implement
-    } else if (name == "UpdateExpression") {
-        // FIXME: Implement
-    } else if (name == "BinaryExpression") {
-        // FIXME: Implement
-    } else if (name == "AssignmentExpression") {
-        // FIXME: Implement
-    } else if (name == "LogicalExpression") {
-        // FIXME: Implement
-    } else if (name == "MemberExpression") {
-        // FIXME: Implement
-    } else if (name == "ConditionalExpression") {
-        // FIXME: Implement
-    } else if (name == "CallExpression") {
-        // FIXME: Implement
-    } else if (name == "NewExpression") {
-        // FIXME: Implement
-    } else if (name == "SequenceExpression") {
-        // FIXME: Implement
-    } else {
-        return this->raiseError();
+    switch (kind) {
+        case BinKind::this_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::array_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::object_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::function_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::unary_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::update_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::binary_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::assignment_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::logical_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::member_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::conditional_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::call_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::new_expression:
+            // FIXME: Implement
+            break;
+        case BinKind::sequence_expression:
+            // FIXME: Implement
+            break;
+        default:
+            return this->raiseError();
     }
 
     return false;
 }
 
 
 bool
 ASTReader::raiseError() {
--- a/js/src/frontend/BinTokenReader.cpp
+++ b/js/src/frontend/BinTokenReader.cpp
@@ -268,17 +268,17 @@ SimpleTokenReader::taggedTuple(std::stri
     if (!this->readConst("</head>")) {
         return false;
     }
 
     subReader->init(this->current, this->stop, nullptr, "</tuple>", this);
     return true;
 }
 bool
-SimpleTokenReader::taggedTuple(Kind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader* subReader)
+SimpleTokenReader::taggedTuple(BinKind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader* subReader)
 {
     // Header
     if (!this->readConst("<tuple>")) {
         return false;
     }
 
     if (!this->readConst("<head>")) {
         return false;
@@ -293,141 +293,141 @@ SimpleTokenReader::taggedTuple(Kind& tag
 
     if (!maybeName) {
         return false;
     }
 
     // This would probably be faster with a HashTable, but we don't
     // really care about the speed of SimpleTokenReader.
     if (*maybeName == "ArrayExpression") {
-        tag = Kind::array_expression;
+        tag = BinKind::array_expression;
     } else if (*maybeName == "AssignmentExpression") {
-        tag = Kind::assignment_expression;
+        tag = BinKind::assignment_expression;
     } else if (*maybeName == "AssignmentOperator") {
-        tag = Kind::assignment_operator;
+        tag = BinKind::assignment_operator;
     } else if (*maybeName == "BinaryExpression") {
-        tag = Kind::binary_expression;
+        tag = BinKind::binary_expression;
     } else if (*maybeName == "BinaryOperator") {
-        tag = Kind::binary_operator;
+        tag = BinKind::binary_operator;
     } else if (*maybeName == "BINJS:Scope") {
-        tag = Kind::binjs_scope;
+        tag = BinKind::binjs_scope;
     } else if (*maybeName == "BlockStatement") {
-        tag = Kind::block_statement;
+        tag = BinKind::block_statement;
     } else if (*maybeName == "BooleanLiteral") {
-        tag = Kind::boolean_literal;
+        tag = BinKind::boolean_literal;
     } else if (*maybeName == "BreakStatement") {
-        tag = Kind::break_statement;
+        tag = BinKind::break_statement;
     } else if (*maybeName == "CallExpression") {
-        tag = Kind::call_expression;
+        tag = BinKind::call_expression;
     } else if (*maybeName == "CatchClause") {
-        tag = Kind::catch_clause;
+        tag = BinKind::catch_clause;
     } else if (*maybeName == "ConditionalExpression") {
-        tag = Kind::conditional_expression;
+        tag = BinKind::conditional_expression;
     } else if (*maybeName == "ContinueStatement") {
-        tag = Kind::continue_statement;
+        tag = BinKind::continue_statement;
     } else if (*maybeName == "DebuggerStatement") {
-        tag = Kind::debugger_statement;
+        tag = BinKind::debugger_statement;
     } else if (*maybeName == "Declaration") {
-        tag = Kind::declaration;
+        tag = BinKind::declaration;
     } else if (*maybeName == "Directive") {
-        tag = Kind::directive;
+        tag = BinKind::directive;
     } else if (*maybeName == "DirectiveLiteral") {
-        tag = Kind::directive_literal;
+        tag = BinKind::directive_literal;
     } else if (*maybeName == "DoWhileStatement") {
-        tag = Kind::do_while_statement;
+        tag = BinKind::do_while_statement;
     } else if (*maybeName == "EmptyStatement") {
-        tag = Kind::empty_statement;
+        tag = BinKind::empty_statement;
     } else if (*maybeName == "Expression") {
-        tag = Kind::expression;
+        tag = BinKind::expression;
     } else if (*maybeName == "ExpressionStatement") {
-        tag = Kind::expression_statement;
+        tag = BinKind::expression_statement;
     } else if (*maybeName == "ForStatement") {
-        tag = Kind::for_statement;
+        tag = BinKind::for_statement;
     } else if (*maybeName == "ForInStatement") {
-        tag = Kind::for_in_statement;
+        tag = BinKind::for_in_statement;
     } else if (*maybeName == "Function") {
-        tag = Kind::function;
+        tag = BinKind::function;
     } else if (*maybeName == "FunctionExpression") {
-        tag = Kind::function_expression;
+        tag = BinKind::function_expression;
     } else if (*maybeName == "FunctionDeclaration") {
-        tag = Kind::function_declaration;
+        tag = BinKind::function_declaration;
     } else if (*maybeName == "Identifier") {
-        tag = Kind::identifier;
+        tag = BinKind::identifier;
     } else if (*maybeName == "IfStatement") {
-        tag = Kind::if_statement;
+        tag = BinKind::if_statement;
     } else if (*maybeName == "LabeledStatement") {
-        tag = Kind::labeled_statement;
+        tag = BinKind::labeled_statement;
     } else if (*maybeName == "Literal") {
-        tag = Kind::literal;
+        tag = BinKind::literal;
     } else if (*maybeName == "LogicalExpression") {
-        tag = Kind::logical_expression;
+        tag = BinKind::logical_expression;
     } else if (*maybeName == "LogicalOperator") {
-        tag = Kind::logical_operator;
+        tag = BinKind::logical_operator;
     } else if (*maybeName == "MemberExpression") {
-        tag = Kind::member_expression;
+        tag = BinKind::member_expression;
     } else if (*maybeName == "Node") {
-        tag = Kind::node;
+        tag = BinKind::node;
     } else if (*maybeName == "NewExpression") {
-        tag = Kind::new_expression;
+        tag = BinKind::new_expression;
     } else if (*maybeName == "NullLiteral") {
-        tag = Kind::null_literal;
+        tag = BinKind::null_literal;
     } else if (*maybeName == "NumericLiteral") {
-        tag = Kind::numeric_literal;
+        tag = BinKind::numeric_literal;
     } else if (*maybeName == "ObjectExpression") {
-        tag = Kind::object_expression;
+        tag = BinKind::object_expression;
     } else if (*maybeName == "ObjectMember") {
-        tag = Kind::object_member;
+        tag = BinKind::object_member;
     } else if (*maybeName == "ObjectMethod") {
-        tag = Kind::object_method;
+        tag = BinKind::object_method;
     } else if (*maybeName == "ObjectProperty") {
-        tag = Kind::object_property;
+        tag = BinKind::object_property;
     } else if (*maybeName == "Pattern") {
-        tag = Kind::pattern;
+        tag = BinKind::pattern;
     } else if (*maybeName == "Program") {
-        tag = Kind::program;
+        tag = BinKind::program;
     } else if (*maybeName == "PropertyKind") {
-        tag = Kind::property_kind;
+        tag = BinKind::property_kind;
     } else if (*maybeName == "RegExpLiteral") {
-        tag = Kind::regexp_literal;
+        tag = BinKind::regexp_literal;
     } else if (*maybeName == "ReturnStatement") {
-        tag = Kind::return_statement;
+        tag = BinKind::return_statement;
     } else if (*maybeName == "SequenceExpression") {
-        tag = Kind::sequence_expression;
+        tag = BinKind::sequence_expression;
     } else if (*maybeName == "StringLiteral") {
-        tag = Kind::string_literal;
+        tag = BinKind::string_literal;
     } else if (*maybeName == "Statement") {
-        tag = Kind::statement;
+        tag = BinKind::statement;
     } else if (*maybeName == "SwitchCase") {
-        tag = Kind::switch_case;
+        tag = BinKind::switch_case;
     } else if (*maybeName == "SwitchStatement") {
-        tag = Kind::switch_statement;
+        tag = BinKind::switch_statement;
     } else if (*maybeName == "ThisExpression") {
-        tag = Kind::this_expression;
+        tag = BinKind::this_expression;
     } else if (*maybeName == "ThrowStatement") {
-        tag = Kind::throw_statement;
+        tag = BinKind::throw_statement;
     } else if (*maybeName == "TryStatement") {
-        tag = Kind::try_statement;
+        tag = BinKind::try_statement;
     } else if (*maybeName == "UnaryExpression") {
-        tag = Kind::unary_expression;
+        tag = BinKind::unary_expression;
     } else if (*maybeName == "UnaryOperator") {
-        tag = Kind::unary_operator;
+        tag = BinKind::unary_operator;
     } else if (*maybeName == "UpdateExpression") {
-        tag = Kind::update_expression;
+        tag = BinKind::update_expression;
     } else if (*maybeName == "UpdateOperator") {
-        tag = Kind::update_operator;
+        tag = BinKind::update_operator;
     } else if (*maybeName == "VariableDeclaration") {
-        tag = Kind::variable_declaration;
+        tag = BinKind::variable_declaration;
     } else if (*maybeName == "VariableDeclarator") {
-        tag = Kind::variable_declarator;
+        tag = BinKind::variable_declarator;
     } else if (*maybeName == "VariableKind") {
-        tag = Kind::variable_kind;
+        tag = BinKind::variable_kind;
     } else if (*maybeName == "WhileStatement") {
-        tag = Kind::while_statement;
+        tag = BinKind::while_statement;
     } else if (*maybeName == "WithStatement") {
-        tag = Kind::with_statement;
+        tag = BinKind::with_statement;
     } else {
         return this->raiseError();
     }
 
     // Now fields.
     uint32_t fieldNum;
     if (!this->readInternalUint32(&fieldNum)) {
         return false;
@@ -443,93 +443,103 @@ SimpleTokenReader::taggedTuple(Kind& tag
             return false;
         }
         if (maybeString.isNothing()) {
             return false;
         }
 
         // This would probably be faster with a HashTable, but we don't
         // really care about the speed of SimpleTokenReader.
-        Field field;
+        BinField field;
         if (*maybeString == "alternate") {
-            field = Field::alternate;
+            field = BinField::alternate;
         } else if (*maybeString == "argument") {
-            field = Field::argument;
+            field = BinField::argument;
         } else if (*maybeString == "arguments") {
-            field = Field::arguments;
+            field = BinField::arguments;
         } else if (*maybeString == "BINJS:Scope") {
-            field = Field::binjs_scope;
+            field = BinField::binjs_scope;
+        } else if (*maybeString == "BINJS:VarDeclaredNames") {
+            field = BinField::var_decl_names;
+        } else if (*maybeString == "BINJS:LetDeclaredNames") {
+            field = BinField::let_decl_names;
+        } else if (*maybeString == "BINJS:ConstDeclaredNames") {
+            field = BinField::const_decl_names;
+        } else if (*maybeString == "BINJS:CapturedNames") {
+            field = BinField::captured_names;
+        } else if (*maybeString == "BINJS:HasDirectEval") {
+            field = BinField::has_direct_eval;
         } else if (*maybeString == "block") {
-            field = Field::block;
+            field = BinField::block;
         } else if (*maybeString == "callee") {
-            field = Field::callee;
+            field = BinField::callee;
         } else if (*maybeString == "cases") {
-            field = Field::cases;
+            field = BinField::cases;
         } else if (*maybeString == "consequent") {
-            field = Field::consequent;
+            field = BinField::consequent;
         } else if (*maybeString == "computed") {
-            field = Field::computed;
+            field = BinField::computed;
         } else if (*maybeString == "body") {
-            field = Field::body;
+            field = BinField::body;
         } else if (*maybeString == "declarations") {
-            field = Field::declarations;
+            field = BinField::declarations;
         } else if (*maybeString == "directives") {
-            field = Field::directives;
+            field = BinField::directives;
         } else if (*maybeString == "discriminant") {
-            field = Field::discriminant;
+            field = BinField::discriminant;
         } else if (*maybeString == "elements") {
-            field = Field::elements;
+            field = BinField::elements;
         } else if (*maybeString == "expression") {
-            field = Field::expression;
+            field = BinField::expression;
         } else if (*maybeString == "expressions") {
-            field = Field::expressions;
+            field = BinField::expressions;
         } else if (*maybeString == "finalizer") {
-            field = Field::finalizer;
+            field = BinField::finalizer;
         } else if (*maybeString == "flags") {
-            field = Field::flags;
+            field = BinField::flags;
         } else if (*maybeString == "handler") {
-            field = Field::handler;
+            field = BinField::handler;
         } else if (*maybeString == "id") {
-            field = Field::id;
+            field = BinField::id;
         } else if (*maybeString == "init") {
-            field = Field::init;
+            field = BinField::init;
         } else if (*maybeString == "key") {
-            field = Field::key;
+            field = BinField::key;
         } else if (*maybeString == "kind") {
-            field = Field::kind;
+            field = BinField::kind;
         } else if (*maybeString == "label") {
-            field = Field::label;
+            field = BinField::label;
         } else if (*maybeString == "left") {
-            field = Field::left;
+            field = BinField::left;
         } else if (*maybeString == "name") {
-            field = Field::name;
+            field = BinField::name;
         } else if (*maybeString == "object") {
-            field = Field::object;
+            field = BinField::object;
         } else if (*maybeString == "operator") {
-            field = Field::operator_;
+            field = BinField::operator_;
         } else if (*maybeString == "param") {
-            field = Field::param;
+            field = BinField::param;
         } else if (*maybeString == "params") {
-            field = Field::params;
+            field = BinField::params;
         } else if (*maybeString == "pattern") {
-            field = Field::pattern;
+            field = BinField::pattern;
         } else if (*maybeString == "prefix") {
-            field = Field::prefix;
+            field = BinField::prefix;
         } else if (*maybeString == "properties") {
-            field = Field::properties;
+            field = BinField::properties;
         } else if (*maybeString == "property") {
-            field = Field::property;
+            field = BinField::property;
         } else if (*maybeString == "right") {
-            field = Field::right;
+            field = BinField::right;
         } else if (*maybeString == "test") {
-            field = Field::test;
+            field = BinField::test;
         } else if (*maybeString == "update") {
-            field = Field::update;
+            field = BinField::update;
         } else if (*maybeString == "value") {
-            field = Field::value;
+            field = BinField::value;
         } else {
             return this->raiseError();
         }
         Unused << fields.append(field); // Already checked.
     }
 
     // End of header
 
--- a/js/src/frontend/BinTokenReader.h
+++ b/js/src/frontend/BinTokenReader.h
@@ -7,17 +7,17 @@
 #include <js/TypeDecls.h>
 
 namespace js {
 namespace frontend {
 
 using namespace mozilla;
 using namespace JS;
 
-enum class Kind {
+enum class BinKind {
     array_expression,
     assignment_expression,
     assignment_operator,
     binary_expression,
     binary_operator,
     binjs_scope,
     block_statement,
     boolean_literal,
@@ -73,66 +73,71 @@ enum class Kind {
     update_operator,
     variable_declaration,
     variable_declarator,
     variable_kind,
     while_statement,
     with_statement,
 };
 
-enum class Field {
+enum class BinField {
     alternate,
     argument,
     arguments,
     binjs_scope,
     block,
     callee,
     cases,
     consequent,
     computed,
     body,
+    captured_names,
+    const_decl_names,
     declarations,
     directives,
     discriminant,
     elements,
     expression,
     expressions,
     finalizer,
     flags,
     handler,
+    has_direct_eval,
     id,
     init,
     key,
     kind,
     label,
     left,
+    let_decl_names,
     name,
     object,
     operator_,
     param,
     params,
     pattern,
     prefix,
     properties,
     property,
     right,
     test,
     update,
     value,
+    var_decl_names,
 };
 
 /**
  * A simple, extremely sub-optimal TokenReader, used as scaffolding for testing
  * the implementation of binary parsing.
  */
 class SimpleTokenReader MOZ_STACK_CLASS
 {
 public:
     using Fields = Vector<std::string, 8>;
-    using BinFields = Vector<Field, 8>;
+    using BinFields = Vector<BinField, 8>;
 public:
     SimpleTokenReader(JSContext* cx_)
         : cx(cx_)
         , initialized(false)
         , parent(nullptr)
         , errored(false)
         , current(nullptr)
         , stop(nullptr)
@@ -288,17 +293,17 @@ public:
      *
      * Before destructing `subReader`, callers MUST reach the end of the
      * tagged tuple. Failure to do so may either raise an error or cause
      * an inconsistent sequence of tokens in the parent.
      *
      * @return out If the header of the tuple is invalid.
      */
     bool taggedTuple(std::string* tag, SimpleTokenReader::Fields *fields, SimpleTokenReader *subReader);
-    bool taggedTuple(Kind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader *subReader);
+    bool taggedTuple(BinKind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader *subReader);
 
     /**
      * Start reading an untagged tuple.
      * @param subReader (OUT) A token reader for the list. It does NOT
      * support `skip()`.
      *
      * Before destructing `subReader`, callers MUST reach the end of the
      * tuple. Failure to do so may either raise an error or cause