remove old files refactor_generator
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 13 Jul 2017 01:21:28 +0000 (18:21 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 13 Jul 2017 01:21:28 +0000 (18:21 -0700)
src/generate_spirv_parser/generate-old.cpp [deleted file]
src/generate_spirv_parser/generate-old.h [deleted file]

diff --git a/src/generate_spirv_parser/generate-old.cpp b/src/generate_spirv_parser/generate-old.cpp
deleted file mode 100644 (file)
index ab78874..0000000
+++ /dev/null
@@ -1,2342 +0,0 @@
-/*
- * Copyright 2017 Jacob Lifshay
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include "generate-old.h"
-#include "json/json.h"
-#include "util/optional.h"
-#include <limits>
-#include <algorithm>
-#include <cstdlib>
-#include <iostream>
-#include <unordered_set>
-
-namespace vulkan_cpu
-{
-namespace generate_spirv_parser
-{
-namespace generate
-{
-Generator::Generator_state::Generator_state(const Generator *generator,
-                                            Generator_args &generator_args,
-                                            const ast::Top_level &top_level)
-    : generator_args(generator_args),
-      indent_level(0),
-      full_output_file_name(generator_args.output_directory + "/"
-                            + generator->output_base_file_name),
-      guard_macro_name(get_guard_macro_name_from_file_name(full_output_file_name)),
-      os(),
-      top_level(top_level),
-      operand_kind_map(),
-      operand_has_any_parameters_map()
-{
-    os.exceptions(std::ios::badbit | std::ios::failbit);
-    for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
-    {
-        operand_kind_map.emplace(operand_kind.kind, &operand_kind);
-        bool &has_any_parameters = operand_has_any_parameters_map[&operand_kind];
-        has_any_parameters = false;
-        if(util::holds_alternative<ast::Operand_kinds::Operand_kind::Enumerants>(
-               operand_kind.value))
-        {
-            auto &enumerants =
-                util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
-            for(auto &enumerant : enumerants.enumerants)
-            {
-                if(!enumerant.parameters.empty())
-                {
-                    has_any_parameters = true;
-                    break;
-                }
-            }
-        }
-    }
-}
-
-void Generator::Generator_state::open_output_file()
-{
-    os.open(full_output_file_name);
-}
-
-constexpr Generator::Indent_t Generator::indent;
-constexpr const char *Generator::vulkan_cpu_namespace_name;
-constexpr const char *Generator::spirv_namespace_name;
-constexpr const char *Generator::spirv_namespace_names[];
-constexpr const char *Generator::extension_enum_name;
-constexpr const char *Generator::capability_enum_name;
-constexpr const char *Generator::op_enum_name;
-
-std::string Generator::get_guard_macro_name_from_file_name(std::string file_name)
-{
-    auto retval = std::move(file_name);
-    for(char &ch : retval)
-    {
-        if(ch >= 'a' && ch <= 'z')
-        {
-            ch = ch - 'a' + 'A'; // convert to uppercase
-            continue;
-        }
-        if(ch >= 'A' && ch <= 'Z')
-            continue;
-        if(ch >= '0' && ch <= '9')
-            continue;
-        ch = '_';
-    }
-    retval += '_';
-    if(retval[0] >= '0' && retval[0] <= '9')
-        retval.insert(0, 1, '_');
-    for(std::size_t double_underline_index = retval.find("__");
-        double_underline_index != std::string::npos;
-        double_underline_index = retval.find("__", double_underline_index + 1))
-    {
-        // insert a u in all pairs of underlines to prevent generating a reserved identifier
-        retval.insert(++double_underline_index, "u");
-    }
-    if(retval.size() >= 2 && retval[0] == '_' && retval[1] >= 'A' && retval[1] <= 'Z')
-    {
-        // insert a u to prevent generating a reserved identifier: starting with an underline and a
-        // capital letter
-        retval.insert(1, "u");
-    }
-    return retval;
-}
-
-namespace
-{
-constexpr bool is_uppercase_letter(char ch) noexcept
-{
-    if(ch >= 'A' && ch <= 'Z')
-        return true;
-    return false;
-}
-
-constexpr bool is_lowercase_letter(char ch) noexcept
-{
-    if(ch >= 'a' && ch <= 'z')
-        return true;
-    return false;
-}
-
-constexpr bool is_letter(char ch) noexcept
-{
-    return is_uppercase_letter(ch) || is_lowercase_letter(ch);
-}
-
-constexpr bool is_identifier_start(char ch) noexcept
-{
-    return is_letter(ch) || ch == '_';
-}
-
-constexpr bool is_digit(char ch) noexcept
-{
-    if(ch >= '0' && ch <= '9')
-        return true;
-    return false;
-}
-}
-
-std::string Generator::get_enumerant_name(const char *enumeration_name,
-                                          std::size_t enumeration_name_size,
-                                          std::string enumerant_name,
-                                          bool input_name_should_have_prefix)
-{
-    bool starts_with_enumeration_name =
-        enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size)
-        == 0;
-    bool starts_with_doubled_enumeration_name = false;
-    if(starts_with_enumeration_name)
-        starts_with_doubled_enumeration_name = enumerant_name.compare(enumeration_name_size,
-                                                                      enumeration_name_size,
-                                                                      enumeration_name,
-                                                                      enumeration_name_size)
-                                               == 0;
-    std::size_t needed_prefix_count;
-    if(input_name_should_have_prefix)
-    {
-        if(!starts_with_enumeration_name)
-            needed_prefix_count = 2;
-        else if(starts_with_doubled_enumeration_name)
-            needed_prefix_count = 1;
-        else
-            needed_prefix_count = 0;
-    }
-    else
-    {
-        if(starts_with_enumeration_name)
-            needed_prefix_count = 1; // ensure that we don't end up with name collisions
-        else if(enumerant_name.empty())
-            needed_prefix_count = 1; // return something other than the empty string
-        else
-            needed_prefix_count = is_identifier_start(enumerant_name[0]) ? 0 : 1;
-    }
-    for(std::size_t i = 0; i < needed_prefix_count; i++)
-        enumerant_name.insert(0, enumeration_name, enumeration_name_size);
-    return enumerant_name;
-}
-
-void Generator::write_indent_absolute(Generator_state &state, std::size_t amount)
-{
-    static constexpr auto indent_string = "    ";
-    for(std::size_t i = 0; i < amount; i++)
-        state << indent_string;
-}
-
-void Generator::write_indent_interpreted_text(Generator_state &state,
-                                              const char *text,
-                                              std::ptrdiff_t offset,
-                                              bool start_indented)
-{
-    bool did_indent = start_indented;
-    std::size_t indent_amount = offset + state.indent_level;
-    for(; *text; text++)
-    {
-        auto &ch = *text;
-        if(ch == '\n')
-        {
-            state << ch;
-            did_indent = false;
-            indent_amount = offset + state.indent_level;
-        }
-        else if(!did_indent && ch == '`')
-        {
-            indent_amount++;
-        }
-        else
-        {
-            if(!did_indent)
-            {
-                did_indent = true;
-                write_indent_absolute(state, indent_amount);
-            }
-            state << ch;
-        }
-    }
-}
-
-void Generator::write_automatically_generated_file_warning(Generator_state &state)
-{
-    state
-        << "/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */\n";
-}
-
-void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright &copyright)
-{
-    state << "/*\n";
-    for(auto &line : copyright.lines)
-    {
-        if(line.empty())
-        {
-            state << " *\n";
-            continue;
-        }
-        state << " * ";
-        bool was_last_star = false;
-        for(char ch : line)
-        {
-            if(was_last_star && ch == '/')
-                state << ' ';
-            was_last_star = (ch == '*');
-            state << ch;
-        }
-        state << "\n";
-    }
-    state << " */\n";
-}
-
-void Generator::write_file_guard_start(Generator_state &state)
-{
-    state << "#ifndef " << state.guard_macro_name << R"(
-#define )"
-          << state.guard_macro_name << "\n"
-                                       "\n";
-}
-
-void Generator::write_file_guard_end(Generator_state &state)
-{
-    state << "#endif /* " << state.guard_macro_name << " */\n";
-}
-
-void Generator::write_namespace_start(Generator_state &state, const char *namespace_name)
-{
-    state << "namespace " << namespace_name << "\n"
-                                               "{\n";
-}
-
-void Generator::write_namespace_start(Generator_state &state, const std::string &namespace_name)
-{
-    state << "namespace " << namespace_name << "\n"
-                                               "{\n";
-}
-
-void Generator::write_namespace_end(Generator_state &state)
-{
-    state << "}\n";
-}
-
-void Generator::write_unsigned_integer_literal(Generator_state &state,
-                                               std::uint64_t value,
-                                               Integer_literal_base base,
-                                               std::size_t minimum_digit_count)
-{
-    constexpr std::uint64_t max_unsigned_value = std::numeric_limits<std::uint16_t>::max();
-    constexpr std::uint64_t max_unsigned_long_value = std::numeric_limits<std::uint32_t>::max();
-    auto literal_type =
-        value <= max_unsigned_value ? "U" : value <= max_unsigned_long_value ? "UL" : "ULL";
-    auto number_prefix = "";
-    unsigned base_as_number = 10;
-    switch(base)
-    {
-    case Integer_literal_base::dec:
-        minimum_digit_count = 1;
-        break;
-    case Integer_literal_base::hex:
-        base_as_number = 0x10;
-        number_prefix = "0x";
-        break;
-    case Integer_literal_base::oct:
-        base_as_number = 010;
-        number_prefix = "0";
-        break;
-    }
-    auto number_string = json::ast::Number_value::append_unsigned_integer_to_string(
-                             value, number_prefix, base_as_number, minimum_digit_count)
-                         + literal_type;
-    state << number_string;
-}
-
-void Generator::write_signed_integer_literal(Generator_state &state, std::int64_t value)
-{
-    constexpr std::int64_t max_int_value = std::numeric_limits<std::int16_t>::max();
-    constexpr std::int64_t min_int_value = std::numeric_limits<std::int16_t>::min();
-    constexpr std::int64_t max_long_value = std::numeric_limits<std::int32_t>::max();
-    constexpr std::int64_t min_long_value = std::numeric_limits<std::int32_t>::min();
-    auto literal_type = "";
-    if(value < min_int_value || value > max_int_value)
-        literal_type = "L";
-    if(value < min_long_value || value > max_long_value)
-        literal_type = "LL";
-    state << value << literal_type;
-}
-
-struct Generator::Get_extensions_visitor
-{
-    std::unordered_set<std::string> &retval;
-    constexpr Get_extensions_visitor(std::unordered_set<std::string> &retval) noexcept
-        : retval(retval)
-    {
-    }
-    template <typename T>
-    void operator()(const T &)
-    {
-    }
-    void operator()(const ast::Extensions &extensions)
-    {
-        for(auto &extension : extensions.extensions)
-            retval.insert(extension);
-    }
-};
-
-std::unordered_set<std::string> Generator::get_extensions(const ast::Top_level &top_level)
-{
-    std::unordered_set<std::string> retval;
-    top_level.visit(Get_extensions_visitor(retval));
-    return retval;
-}
-
-void Generator::write_capabilities_set(Generator_state &state,
-                                       const ast::Capabilities &capabilities)
-{
-    state << "util::Enum_set<" << capability_enum_name << ">{";
-    auto separator = "";
-    for(auto &capability : capabilities.capabilities)
-    {
-        state << separator << capability_enum_name
-              << "::" << get_enumerant_name(capability_enum_name, capability, false);
-        separator = ", ";
-    }
-    state << "}";
-}
-
-void Generator::write_extensions_set(Generator_state &state, const ast::Extensions &extensions)
-{
-    state << "util::Enum_set<" << extension_enum_name << ">{";
-    auto separator = "";
-    for(auto &extension : extensions.extensions)
-    {
-        state << separator << extension_enum_name
-              << "::" << get_enumerant_name(extension_enum_name, extension, false);
-        separator = ", ";
-    }
-    state << "}";
-}
-
-std::string Generator::get_name_from_words(const std::string &words)
-{
-    enum class Char_class
-    {
-        Uppercase,
-        OtherIdentifier,
-        WordSeparator,
-    };
-    auto get_char_class = [](char ch) -> Char_class
-    {
-        if(is_uppercase_letter(ch))
-            return Char_class::Uppercase;
-        if(is_letter(ch) || is_digit(ch))
-            return Char_class::OtherIdentifier;
-        return Char_class::WordSeparator;
-    };
-    auto find_words = [&](auto found_word_callback) -> void
-    {
-        util::optional<std::size_t> word_start;
-        auto finish_word = [&](std::size_t index)
-        {
-            found_word_callback(util::string_view(words.data() + *word_start, index - *word_start));
-            word_start = {};
-        };
-        auto start_word = [&](std::size_t index)
-        {
-            word_start = index;
-        };
-        auto last_char_class = Char_class::WordSeparator;
-        for(std::size_t i = 0; i < words.size(); i++)
-        {
-            auto current_char_class = get_char_class(words[i]);
-            if(word_start)
-            {
-                switch(current_char_class)
-                {
-                case Char_class::WordSeparator:
-                    finish_word(i);
-                    break;
-                case Char_class::Uppercase:
-                    if(last_char_class != Char_class::Uppercase)
-                    {
-                        finish_word(i);
-                        start_word(i);
-                    }
-                    else if(i + 1 < words.size()
-                            && get_char_class(words[i + 1]) == Char_class::OtherIdentifier)
-                    {
-                        finish_word(i);
-                        start_word(i);
-                    }
-                    break;
-                case Char_class::OtherIdentifier:
-                    break;
-                }
-            }
-            else if(current_char_class != Char_class::WordSeparator)
-            {
-                start_word(i);
-            }
-            last_char_class = current_char_class;
-        }
-        if(word_start)
-            finish_word(words.size());
-    };
-    std::size_t retval_size = 0;
-    bool first = true;
-    find_words([&](util::string_view word)
-               {
-                   if(!first)
-                       retval_size++; // separating '_'
-                   first = false;
-                   retval_size += word.size();
-               });
-    std::string retval;
-    retval.reserve(retval_size);
-    first = true;
-    find_words([&](util::string_view word)
-               {
-                   if(!first)
-                       retval += '_';
-                   first = false;
-                   retval += word;
-               });
-    for(char &ch : retval)
-    {
-        if(is_uppercase_letter(ch))
-            ch = ch - 'A' + 'a'; // to lowercase
-    }
-    static constexpr const char *const reserved_words[] = {
-        "alignas",
-        "alignof",
-        "and",
-        "and_eq",
-        "asm",
-        "atomic_cancel",
-        "atomic_commit",
-        "atomic_noexcept",
-        "auto",
-        "bitand",
-        "bitor",
-        "bool",
-        "break",
-        "case",
-        "catch",
-        "char",
-        "char16_t",
-        "char32_t",
-        "class",
-        "compl",
-        "concept",
-        "concepts",
-        "const",
-        "const_cast",
-        "constexpr",
-        "continue",
-        "decltype",
-        "default",
-        "delete",
-        "do",
-        "double",
-        "dynamic_cast",
-        "else",
-        "enum",
-        "explicit",
-        "export",
-        "extern",
-        "false",
-        "float",
-        "for",
-        "friend",
-        "goto",
-        "if",
-        "import",
-        "inline",
-        "int",
-        "long",
-        "module",
-        "modules",
-        "mutable",
-        "namespace",
-        "new",
-        "noexcept",
-        "not",
-        "not_eq",
-        "nullptr",
-        "operator",
-        "or",
-        "or_eq",
-        "private",
-        "protected",
-        "public",
-        "register",
-        "reinterpret_cast",
-        "requires",
-        "return",
-        "short",
-        "signed",
-        "sizeof",
-        "static",
-        "static_assert",
-        "static_cast",
-        "struct",
-        "switch",
-        "synchronized",
-        "template",
-        "this",
-        "thread_local",
-        "throw",
-        "true",
-        "try",
-        "typedef",
-        "typeid",
-        "typename",
-        "union",
-        "unsigned",
-        "using",
-        "virtual",
-        "void",
-        "volatile",
-        "wchar_t",
-        "while",
-        "xor",
-        "xor_eq",
-    };
-    for(const char *reserved_word : reserved_words)
-    {
-        if(retval == reserved_word)
-        {
-            retval += '_';
-            break;
-        }
-    }
-    return retval;
-}
-
-#if 0
-#warning testing Generator::get_name_from_words
-struct Generator::Tester
-{
-    struct Test_runner
-    {
-        Test_runner()
-        {
-            test();
-            std::exit(1);
-        }
-    };
-    static Test_runner test_runner;
-    static void test()
-    {
-        for(auto &input : {
-                    "abc  def", "AbcDef", "ABCDef", "'abc, def'",
-                })
-        {
-            std::cout << "\"" << input << "\" -> " << get_name_from_words(input)
-                      << std::endl;
-        }
-    }
-};
-
-Generator::Tester::Test_runner Generator::Tester::test_runner;
-#endif
-
-std::string Generator::get_member_name_from_operand(
-    const ast::Instructions::Instruction::Operands::Operand &operand)
-{
-    if(!operand.name.empty())
-        return get_name_from_words(operand.name);
-    util::string_view id_str = "Id";
-    if(util::string_view(operand.kind).compare(0, id_str.size(), id_str) == 0
-       && id_str.size() < operand.kind.size()
-       && is_uppercase_letter(operand.kind[id_str.size()]))
-        return get_name_from_words(operand.kind.substr(id_str.size()));
-    return get_name_from_words(operand.kind);
-}
-
-std::string Generator::get_member_name_from_parameter(
-    const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter &parameter)
-{
-    if(!parameter.name.empty())
-        return get_name_from_words(parameter.name);
-    return get_name_from_words(parameter.kind);
-}
-
-std::string Generator::get_member_name_from_enumerant(
-    const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant &enumerant)
-{
-    return get_name_from_words(enumerant.enumerant + " parameters");
-}
-
-std::string Generator::get_operand_with_parameters_name(
-    Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind)
-{
-    if(get_operand_has_any_parameters(state, operand_kind))
-        return operand_kind.kind + "_with_parameters";
-    return operand_kind.kind;
-}
-
-void Generator::write_struct_nonstatic_members_and_constructors(Generator_state &state,
-                                                                const std::string &struct_name,
-                                                                const std::string *member_types,
-                                                                const std::string *member_names,
-                                                                std::size_t member_count)
-{
-    for(std::size_t i = 0; i < member_count; i++)
-        state << indent << member_types[i] << " " << member_names[i] << ";\n";
-    state << indent << struct_name << "()\n";
-    {
-        auto push_indent = state.pushed_indent();
-        for(std::size_t i = 0; i < member_count; i++)
-        {
-            state << indent;
-            if(i == 0)
-                state << ": ";
-            else
-                state << "  ";
-            state << member_names[i] << "()";
-            if(i != member_count - 1)
-                state << ",";
-            state << "\n";
-        }
-    }
-    state << indent(R"({
-}
-)");
-    if(member_count != 0)
-    {
-        state << indent;
-        if(member_count == 1)
-            state << "explicit ";
-        state << struct_name << "(";
-        for(std::size_t i = 0; i < member_count; i++)
-        {
-            state << member_types[i] << " " << member_names[i];
-            if(i != member_count - 1)
-                state << ", ";
-        }
-        state << ")\n";
-        {
-            auto push_indent = state.pushed_indent();
-            for(std::size_t i = 0; i < member_count; i++)
-            {
-                state << indent;
-                if(i == 0)
-                    state << ": ";
-                else
-                    state << "  ";
-                state << member_names[i] << "(std::move(" << member_names[i] << "))";
-                if(i != member_count - 1)
-                    state << ",";
-                state << "\n";
-            }
-        }
-        state << indent(R"({
-}
-)");
-    }
-}
-
-std::vector<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant>
-    Generator::get_unique_enumerants(
-        std::vector<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant> enumerants)
-{
-    std::unordered_set<std::uint32_t> values;
-    std::size_t output_index = 0;
-    for(std::size_t input_index = 0; input_index < enumerants.size(); input_index++)
-    {
-        if(std::get<1>(values.insert(enumerants[input_index].value)))
-        {
-            if(output_index != input_index)
-                enumerants[output_index] = std::move(enumerants[input_index]);
-            output_index++;
-        }
-    }
-    enumerants.erase(enumerants.begin() + output_index, enumerants.end());
-    return enumerants;
-}
-
-struct Spirv_header_generator final : public Generator
-{
-    Spirv_header_generator() : Generator("spirv.h")
-    {
-    }
-    enum class Enum_priority
-    {
-        default_priority = 0,
-        capability = 1,
-    };
-    static Enum_priority get_enum_priority(const std::string &enum_name) noexcept
-    {
-        if(enum_name == capability_enum_name)
-            return Enum_priority::capability;
-        return Enum_priority::default_priority;
-    }
-    static bool compare_enum_names(const std::string &l, const std::string &r) noexcept
-    {
-        auto l_priority = get_enum_priority(l);
-        auto r_priority = get_enum_priority(r);
-        if(l_priority > r_priority)
-            return true; // higher priority sorts first
-        if(l_priority < r_priority)
-            return false;
-        return l < r;
-    }
-    /** lower priority means that the operand kind is declared first */
-    static int get_operand_category_priority(
-        ast::Operand_kinds::Operand_kind::Category category) noexcept
-    {
-        switch(category)
-        {
-        case ast::Operand_kinds::Operand_kind::Category::bit_enum:
-        case ast::Operand_kinds::Operand_kind::Category::value_enum:
-            return 1;
-        case ast::Operand_kinds::Operand_kind::Category::id:
-            return 0;
-        case ast::Operand_kinds::Operand_kind::Category::literal:
-            return 0;
-        case ast::Operand_kinds::Operand_kind::Category::composite:
-            return 2;
-        }
-        return 0;
-    }
-    static bool compare_operand_kinds(const ast::Operand_kinds::Operand_kind &l,
-                                      const ast::Operand_kinds::Operand_kind &r)
-    {
-        auto l_priority = get_operand_category_priority(l.category);
-        auto r_priority = get_operand_category_priority(r.category);
-        if(l_priority != r_priority)
-            return l_priority < r_priority;
-        return compare_enum_names(l.kind, r.kind);
-    }
-    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
-    {
-        Generator_state state(this, generator_args, top_level);
-        state.open_output_file();
-        write_file_comments(state, top_level.copyright);
-        write_file_guard_start(state);
-        state << indent(R"(#include <cstdint>
-#include "util/enum.h"
-#include "util/optional.h"
-#include "util/variant.h"
-#include <vector>
-
-)");
-        write_namespaces_start(state, spirv_namespace_names);
-        state << indent(R"(typedef std::uint32_t Word;
-typedef Word Id;
-enum class Op : Word;
-constexpr Word magic_number = )")
-              << unsigned_hex_integer_literal(top_level.magic_number, 8)
-              << indent(true,
-                        ";\n"
-                        "constexpr std::uint32_t major_version = ")
-              << unsigned_dec_integer_literal(top_level.major_version)
-              << indent(true,
-                        ";\n"
-                        "constexpr std::uint32_t minor_version = ")
-              << unsigned_dec_integer_literal(top_level.minor_version)
-              << indent(true,
-                        ";\n"
-                        "constexpr std::uint32_t revision = ")
-              << unsigned_dec_integer_literal(top_level.revision) << ";\n";
-        auto extensions_set = get_extensions(top_level);
-        std::vector<std::string> extensions_list;
-        extensions_list.reserve(extensions_set.size());
-        for(auto &extension : extensions_set)
-            extensions_list.push_back(extension);
-        std::sort(extensions_list.begin(), extensions_list.end());
-        state << indent(
-                     "\n"
-                     "enum class ")
-              << extension_enum_name << indent(true,
-                                               " : std::size_t\n"
-                                               "{\n");
-        {
-            auto push_indent = state.pushed_indent();
-            for(auto &extension : extensions_list)
-                state << indent << get_enumerant_name(extension_enum_name, extension, false)
-                      << ",\n";
-        }
-        state << indent(
-                     "};\n"
-                     "\n"
-                     "vulkan_cpu_util_generate_enum_traits(")
-              << extension_enum_name;
-        {
-            auto push_indent = state.pushed_indent();
-            for(auto &extension : extensions_list)
-                state << ",\n" << indent << extension_enum_name
-                      << "::" << get_enumerant_name(extension_enum_name, extension, false);
-            state << ");\n";
-        }
-        state << indent(
-                     "\n"
-                     "constexpr const char *get_enumerant_name(")
-              << extension_enum_name << indent(true,
-                                               " v) noexcept\n"
-                                               "{\n");
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(
-                "switch(v)\n"
-                "{\n");
-            for(auto &extension : extensions_list)
-            {
-                state << indent("case ") << extension_enum_name
-                      << "::" << get_enumerant_name(extension_enum_name, extension, false)
-                      << indent(true,
-                                ":\n"
-                                "`return \"")
-                      << extension << "\";\n";
-            }
-            state << indent(
-                "}\n"
-                "return \"\";\n");
-        }
-        state << "}\n";
-        std::vector<const ast::Operand_kinds::Operand_kind *> operand_kinds;
-        operand_kinds.reserve(top_level.operand_kinds.operand_kinds.size());
-        for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
-            operand_kinds.push_back(&operand_kind);
-        std::sort(
-            operand_kinds.begin(),
-            operand_kinds.end(),
-            [](const ast::Operand_kinds::Operand_kind *a, const ast::Operand_kinds::Operand_kind *b)
-            {
-                return compare_operand_kinds(*a, *b);
-            });
-        for(auto *operand_kind : operand_kinds)
-        {
-            switch(operand_kind->category)
-            {
-            case ast::Operand_kinds::Operand_kind::Category::bit_enum:
-            case ast::Operand_kinds::Operand_kind::Category::value_enum:
-            {
-                bool is_bit_enum =
-                    operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum;
-                auto &enumerants =
-                    util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind->value);
-                auto unique_enumerants = get_unique_enumerants(enumerants.enumerants);
-                state << "\n"
-                         "enum class "
-                      << get_enum_name(*operand_kind) << " : Word\n"
-                                                         "{\n";
-                {
-                    auto push_indent = state.pushed_indent();
-                    for(auto &enumerant : enumerants.enumerants)
-                    {
-                        state << indent
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
-                              << " = ";
-                        if(is_bit_enum)
-                            state << unsigned_hex_integer_literal(enumerant.value);
-                        else
-                            state << unsigned_dec_integer_literal(enumerant.value);
-                        state << ",\n";
-                    }
-                }
-                state << "};\n"
-                         "\n"
-                         "vulkan_cpu_util_generate_enum_traits("
-                      << get_enum_name(*operand_kind);
-                {
-                    auto push_indent = state.pushed_indent();
-                    for(auto &enumerant : unique_enumerants)
-                        state << ",\n" << indent << get_enum_name(*operand_kind) << "::"
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false);
-                    state << ");\n";
-                }
-                state << "\n"
-                         "constexpr const char *get_enumerant_name("
-                      << get_enum_name(*operand_kind) << " v) noexcept\n"
-                                                         "{\n";
-                {
-                    auto push_indent = state.pushed_indent();
-                    state << indent(
-                        "switch(v)\n"
-                        "{\n");
-                    for(auto &enumerant : unique_enumerants)
-                    {
-                        state << indent("case ") << get_enum_name(*operand_kind) << "::"
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
-                              << indent(true,
-                                        ":\n"
-                                        "`return \"")
-                              << enumerant.enumerant << "\";\n";
-                    }
-                    state << indent(
-                        "}\n"
-                        "return \"\";\n");
-                }
-                state << "}\n";
-                state << "\n"
-                         "constexpr util::Enum_set<"
-                      << capability_enum_name << "> get_directly_required_capability_set("
-                      << get_enum_name(*operand_kind) << " v) noexcept\n"
-                                                         "{\n";
-                {
-                    auto push_indent = state.pushed_indent();
-                    state << indent(
-                        "switch(v)\n"
-                        "{\n");
-                    for(auto &enumerant : unique_enumerants)
-                    {
-                        state << indent("case ") << get_enum_name(*operand_kind) << "::"
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
-                              << indent(true,
-                                        ":\n"
-                                        "`return ")
-                              << enumerant.capabilities << ";\n";
-                    }
-                    state << indent(
-                        "}\n"
-                        "return {};\n");
-                }
-                state << "}\n"
-                         "\n"
-                         "constexpr util::Enum_set<"
-                      << extension_enum_name << "> get_directly_required_extension_set("
-                      << get_enum_name(*operand_kind) << " v) noexcept\n"
-                                                         "{\n";
-                {
-                    auto push_indent = state.pushed_indent();
-                    state << indent(
-                        "switch(v)\n"
-                        "{\n");
-                    for(auto &enumerant : unique_enumerants)
-                    {
-                        state << indent("case ") << get_enum_name(*operand_kind) << "::"
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
-                              << indent(true,
-                                        ":\n"
-                                        "`return ")
-                              << enumerant.extensions << ";\n";
-                    }
-                    state << indent(
-                        "}\n"
-                        "return {};\n");
-                }
-                state << "}\n";
-                break;
-            }
-            case ast::Operand_kinds::Operand_kind::Category::composite:
-            {
-                auto &bases =
-                    util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind->value);
-                state << "\n"
-                         "struct "
-                      << operand_kind->kind << "\n"
-                                               "{\n";
-                auto push_indent = state.pushed_indent();
-                std::vector<std::string> member_types;
-                std::vector<std::string> member_names;
-                member_types.reserve(bases.values.size());
-                member_names.reserve(bases.values.size());
-                for(std::size_t i = 0; i < bases.values.size(); i++)
-                {
-                    member_types.push_back(
-                        get_operand_with_parameters_name(state, bases.values[i]));
-                    member_names.push_back(
-                        json::ast::Number_value::append_unsigned_integer_to_string(i + 1, "part_"));
-                }
-                write_struct_nonstatic_members_and_constructors(state,
-                                                                operand_kind->kind,
-                                                                member_types.data(),
-                                                                member_names.data(),
-                                                                bases.values.size());
-                push_indent.finish();
-                state << "};\n";
-                break;
-            }
-            case ast::Operand_kinds::Operand_kind::Category::id:
-            {
-                auto &doc = util::get<ast::Operand_kinds::Operand_kind::Doc>(operand_kind->value);
-                state << "\n"
-                         "/** ";
-                bool was_last_star = false;
-                for(char ch : doc.value)
-                {
-                    if(was_last_star && ch == '/')
-                        state << ' ';
-                    was_last_star = (ch == '*');
-                    state << ch;
-                }
-                state << " */\n"
-                         "typedef Id "
-                      << operand_kind->kind << ";\n";
-                break;
-            }
-            case ast::Operand_kinds::Operand_kind::Category::literal:
-            {
-                auto &doc = util::get<ast::Operand_kinds::Operand_kind::Doc>(operand_kind->value);
-                auto literal_kind =
-                    ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
-                        operand_kind->kind);
-                if(!literal_kind)
-                    throw Generate_error("bad literal kind");
-                auto base_type = "std::vector<Word>";
-                switch(*literal_kind)
-                {
-                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
-                    // TODO: fix after determining if LiteralInteger can be multiple words
-                    base_type = "std::uint32_t";
-                    break;
-                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
-                    base_type = "std::string";
-                    break;
-                case ast::Operand_kinds::Operand_kind::Literal_kind::
-                    literal_context_dependent_number:
-                    break;
-                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
-                    base_type = "Word";
-                    break;
-                case ast::Operand_kinds::Operand_kind::Literal_kind::
-                    literal_spec_constant_op_integer:
-                    base_type = "Op";
-                    break;
-                }
-                state << "\n"
-                         "/** ";
-                bool was_last_star = false;
-                for(char ch : doc.value)
-                {
-                    if(was_last_star && ch == '/')
-                        state << ' ';
-                    was_last_star = (ch == '*');
-                    state << ch;
-                }
-                state << " */\n"
-                         "typedef "
-                      << base_type << " " << operand_kind->kind << ";\n";
-                break;
-            }
-            }
-        }
-        for(auto *operand_kind : operand_kinds)
-        {
-            switch(operand_kind->category)
-            {
-            case ast::Operand_kinds::Operand_kind::Category::bit_enum:
-            case ast::Operand_kinds::Operand_kind::Category::value_enum:
-            {
-                bool is_bit_enum =
-                    operand_kind->category == ast::Operand_kinds::Operand_kind::Category::bit_enum;
-                auto &enumerants =
-                    util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind->value);
-                auto unique_enumerants = get_unique_enumerants(enumerants.enumerants);
-                if(get_operand_has_any_parameters(state, *operand_kind))
-                {
-                    for(auto &enumerant : unique_enumerants)
-                    {
-                        if(enumerant.parameters.empty())
-                            continue;
-                        auto struct_name = get_enumerant_parameters_struct_name(
-                            operand_kind->kind, enumerant.enumerant, false);
-                        state << "\n"
-                                 "struct "
-                              << struct_name << indent(true, R"(
-{
-`static constexpr )") << get_enum_name(*operand_kind)
-                              << indent(true, R"( get_enumerant() noexcept
-`{
-``return )") << get_enum_name(*operand_kind)
-                              << "::"
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
-                              << indent(true, R"(;
-`}
-)");
-                        std::vector<std::string> member_types;
-                        std::vector<std::string> member_names;
-                        member_types.reserve(enumerant.parameters.parameters.size());
-                        member_names.reserve(enumerant.parameters.parameters.size());
-                        for(auto &parameter : enumerant.parameters.parameters)
-                        {
-                            member_types.push_back(
-                                get_operand_with_parameters_name(state, parameter.kind));
-                            member_names.push_back(get_member_name_from_parameter(parameter));
-                        }
-                        auto push_indent = state.pushed_indent();
-                        write_struct_nonstatic_members_and_constructors(
-                            state,
-                            struct_name,
-                            member_types.data(),
-                            member_names.data(),
-                            enumerant.parameters.parameters.size());
-                        push_indent.finish();
-                        state << "};\n";
-                    }
-                    if(is_bit_enum)
-                    {
-                        auto struct_name = get_operand_with_parameters_name(state, *operand_kind);
-                        state << indent(R"(
-struct )") << struct_name << indent(true, R"(
-{
-)");
-                        std::vector<std::string> member_types;
-                        std::vector<std::string> member_names;
-                        member_types.push_back(get_enum_name(*operand_kind));
-                        member_names.push_back("value");
-                        for(auto &enumerant : unique_enumerants)
-                        {
-                            if(enumerant.parameters.empty())
-                                continue;
-                            member_types.push_back(
-                                "util::optional<"
-                                + get_enumerant_parameters_struct_name(
-                                      operand_kind->kind, enumerant.enumerant, false)
-                                + ">");
-                            member_names.push_back(get_member_name_from_enumerant(enumerant));
-                        }
-                        auto push_indent = state.pushed_indent();
-                        write_struct_nonstatic_members_and_constructors(state,
-                                                                        struct_name,
-                                                                        member_types.data(),
-                                                                        member_names.data(),
-                                                                        member_types.size());
-                        push_indent.finish();
-                        state << "};\n";
-                    }
-                    else
-                    {
-                        auto struct_name = get_operand_with_parameters_name(state, *operand_kind);
-                        state << indent(R"(
-struct )") << struct_name << indent(true, R"(
-{
-`typedef util::variant<util::monostate)");
-                        for(auto &enumerant : unique_enumerants)
-                        {
-                            if(enumerant.parameters.empty())
-                                continue;
-                            state << ",\n" << indent(2)
-                                  << get_enumerant_parameters_struct_name(
-                                         operand_kind->kind, enumerant.enumerant, false);
-                        }
-                        state << indent(true, R"(> Parameters;
-)");
-                        auto push_indent = state.pushed_indent();
-                        constexpr std::size_t member_count = 2;
-                        std::string member_types[member_count] = {
-                            get_enum_name(*operand_kind), "Parameters",
-                        };
-                        std::string member_names[member_count] = {
-                            "value", "parameters",
-                        };
-                        write_struct_nonstatic_members_and_constructors(
-                            state, struct_name, member_types, member_names, member_count);
-                        push_indent.finish();
-                        state << "};\n";
-                    }
-                }
-                break;
-            }
-            case ast::Operand_kinds::Operand_kind::Category::composite:
-            case ast::Operand_kinds::Operand_kind::Category::id:
-            case ast::Operand_kinds::Operand_kind::Category::literal:
-                break;
-            }
-        }
-        std::vector<const ast::Instructions::Instruction *> instructions;
-        instructions.reserve(top_level.instructions.instructions.size());
-        for(auto &instruction : top_level.instructions.instructions)
-            instructions.push_back(&instruction);
-        std::sort(
-            instructions.begin(),
-            instructions.end(),
-            [](const ast::Instructions::Instruction *a, const ast::Instructions::Instruction *b)
-            {
-                return a->opcode < b->opcode;
-            });
-        state << "\n"
-                 "enum class "
-              << op_enum_name << " : Word\n"
-                                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                state << indent << get_enumerant_name(op_enum_name, instruction.opname, true)
-                      << " = " << unsigned_dec_integer_literal(instruction.opcode) << ",\n";
-            }
-        }
-        state << "};\n";
-        state << "\n"
-                 "vulkan_cpu_util_generate_enum_traits("
-              << op_enum_name;
-        {
-            auto push_indent = state.pushed_indent();
-            for(auto &instruction : top_level.instructions.instructions)
-                state << ",\n" << indent << op_enum_name
-                      << "::" << get_enumerant_name(op_enum_name, instruction.opname, true);
-            state << ");\n";
-        }
-        state << "\n"
-                 "constexpr const char *get_enumerant_name("
-              << op_enum_name << " v) noexcept\n"
-                                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(
-                "switch(v)\n"
-                "{\n");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                state << indent("case ") << op_enum_name
-                      << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
-                      << indent(true,
-                                ":\n"
-                                "return \"")
-                      << instruction.opname << "\";\n";
-            }
-            state << indent(
-                "}\n"
-                "return \"\";\n");
-        }
-        state << "}\n"
-                 "\n"
-                 "constexpr util::Enum_set<"
-              << capability_enum_name << "> get_directly_required_capability_set(" << op_enum_name
-              << " v) noexcept\n"
-                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(
-                "switch(v)\n"
-                "{\n");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                state << indent("case ") << op_enum_name
-                      << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
-                      << indent(true,
-                                ":\n"
-                                "return ")
-                      << instruction.capabilities << ";\n";
-            }
-            state << indent(
-                "}\n"
-                "return {};\n");
-        }
-        state << "}\n"
-                 "\n"
-                 "constexpr util::Enum_set<"
-              << extension_enum_name << "> get_directly_required_extension_set(" << op_enum_name
-              << " v) noexcept\n"
-                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(
-                "switch(v)\n"
-                "{\n");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                state << indent("case ") << op_enum_name
-                      << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
-                      << ":\n";
-                auto push_indent2 = state.pushed_indent();
-                state << indent("return ") << instruction.extensions << ";\n";
-            }
-            state << indent(
-                "}\n"
-                "return {};\n");
-        }
-        state << "}\n";
-        for(auto &instruction : top_level.instructions.instructions)
-        {
-            auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-            state << "\n"
-                     "struct "
-                  << struct_name << "\n"
-                                    "{\n";
-            {
-                auto push_indent = state.pushed_indent();
-                state << indent("static constexpr ") << op_enum_name << " get_opcode() noexcept\n"
-                      << indent("{\n");
-                {
-                    auto push_indent2 = state.pushed_indent();
-                    state << indent("return ") << op_enum_name
-                          << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
-                          << ";\n";
-                }
-                state << indent("}\n");
-                std::vector<std::string> member_names;
-                std::vector<std::string> member_types;
-                member_names.reserve(instruction.operands.operands.size());
-                member_types.reserve(instruction.operands.operands.size());
-                for(auto &operand : instruction.operands.operands)
-                {
-                    std::string member_type;
-                    switch(operand.quantifier)
-                    {
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::none:
-                    {
-                        member_type = get_operand_with_parameters_name(state, operand);
-                        break;
-                    }
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
-                    {
-                        member_type = "util::optional<"
-                                      + get_operand_with_parameters_name(state, operand) + ">";
-                        break;
-                    }
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
-                    {
-                        member_type =
-                            "std::vector<" + get_operand_with_parameters_name(state, operand) + ">";
-                        break;
-                    }
-                    }
-                    member_types.push_back(std::move(member_type));
-                    member_names.push_back(get_member_name_from_operand(operand));
-                }
-                write_struct_nonstatic_members_and_constructors(state,
-                                                                struct_name,
-                                                                member_types.data(),
-                                                                member_names.data(),
-                                                                member_types.size());
-            }
-            state << "};\n";
-        }
-        write_namespaces_end(state, spirv_namespace_names);
-        write_file_guard_end(state);
-    }
-};
-
-struct Spirv_source_generator final : public Generator
-{
-    Spirv_source_generator() : Generator("spirv.cpp")
-    {
-    }
-    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
-    {
-        Generator_state state(this, generator_args, top_level);
-        state.open_output_file();
-        write_file_comments(state, top_level.copyright);
-        state << "#include \"spirv.h\"\n";
-    }
-};
-
-struct Parser_header_generator final : public Generator
-{
-    Parser_header_generator() : Generator("parser.h")
-    {
-    }
-    static std::string get_dump_operand_function_name(std::string kind)
-    {
-        return "dump_operand_" + std::move(kind);
-    }
-    static std::string get_dump_operand_function_name(
-        const ast::Operand_kinds::Operand_kind &operand_kind)
-    {
-        return get_dump_operand_function_name(operand_kind.kind);
-    }
-    static std::string get_dump_operand_function_name(
-        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter
-            &parameter)
-    {
-        return get_dump_operand_function_name(parameter.kind);
-    }
-    static std::string get_parse_operand_function_name(std::string kind)
-    {
-        return "parse_operand_" + std::move(kind);
-    }
-    static std::string get_parse_operand_function_name(
-        const ast::Operand_kinds::Operand_kind &operand_kind)
-    {
-        return get_parse_operand_function_name(operand_kind.kind);
-    }
-    static std::string get_parse_operand_function_name(
-        const ast::Instructions::Instruction::Operands::Operand &operand)
-    {
-        return get_parse_operand_function_name(operand.kind);
-    }
-    static std::string get_parse_operand_function_name(
-        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter
-            &parameter)
-    {
-        return get_parse_operand_function_name(parameter.kind);
-    }
-    static std::string get_parse_instruction_function_name(std::string opname)
-    {
-        return "parse_instruction_" + get_enumerant_name(op_enum_name, opname, true);
-    }
-    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
-    {
-        Generator_state state(this, generator_args, top_level);
-        state.open_output_file();
-        write_file_comments(state, top_level.copyright);
-        write_file_guard_start(state);
-        state << R"(#include "spirv.h"
-#include <memory>
-#include <ostream>
-#include "util/optional.h"
-#include "json/json.h"
-#include <vector>
-
-)";
-        write_namespaces_start(state, spirv_namespace_names);
-        state << indent(R"(struct Parse_error
-{
-`std::size_t word_index;
-`std::size_t instruction_word_index;
-`std::string message;
-`Parse_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) noexcept
-``: word_index(word_index),
-``  instruction_word_index(instruction_word_index),
-``  message(std::move(message))
-`{
-`}
-`virtual ~Parse_error() = default;
-};
-
-)");
-        state << "struct Parse_semantics_generic\n"
-                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(R"(virtual ~Parse_semantics_generic() = default;
-virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) = 0;
-virtual void handle_spirv_version(unsigned major, unsigned minor) = 0;
-virtual void handle_generator_magic_number(Word value) = 0;
-virtual void handle_id_bound(Word id_bound) = 0;
-)");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-                state << indent("virtual void handle_instruction(") << struct_name
-                      << " instruction) = 0;\n";
-            }
-        }
-        state << indent(R"(};
-
-struct Parse_dump final : public Parse_semantics_generic
-{
-`std::ostream &os;
-`explicit constexpr Parse_dump(std::ostream &os) noexcept : os(os)
-`{
-`}
-)");
-        {
-            auto push_indent = state.pushed_indent();
-            state << indent(
-                R"(virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) override;
-virtual void handle_spirv_version(unsigned major, unsigned minor) override;
-virtual void handle_generator_magic_number(Word value) override;
-virtual void handle_id_bound(Word id_bound) override;
-)");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-                state << indent("virtual void handle_instruction(") << struct_name
-                      << " instruction) override;\n";
-            }
-            for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
-            {
-                auto dump_function_name = get_dump_operand_function_name(operand_kind);
-                state << indent("void ") << dump_function_name << "(const "
-                      << get_operand_with_parameters_name(state, operand_kind) << " &value);\n";
-                state << indent("void ") << dump_function_name << "(const util::optional<"
-                      << get_operand_with_parameters_name(state, operand_kind) << "> &value);\n";
-                state << indent("void ") << dump_function_name << "(const std::vector<"
-                      << get_operand_with_parameters_name(state, operand_kind) << "> &values);\n";
-            }
-        }
-        state << "};\n"
-                 "\n"
-                 "template <typename Semantics = Parse_semantics_generic>\n"
-                 "struct Parser\n"
-                 "{\n";
-        {
-            auto push_indent = state.pushed_indent();
-            for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
-            {
-                auto parse_function_name = get_parse_operand_function_name(operand_kind);
-                state
-                    << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
-                    << indent(
-                           true,
-                           R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index, std::size_t &word_index, )")
-                    << get_operand_with_parameters_name(state, operand_kind) << indent(true,
-                                                                                       R"( &value)
-{
-`if(word_index >= word_count)
-``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "instruction missing operand");
-)");
-                auto push_indent = state.pushed_indent();
-                switch(operand_kind.category)
-                {
-                case ast::Operand_kinds::Operand_kind::Category::bit_enum:
-                {
-                    auto enum_name = get_enum_name(operand_kind);
-                    if(get_operand_has_any_parameters(state, operand_kind))
-                    {
-                        state << indent(R"(value.value = static_cast<)") << enum_name
-                              << indent(true, R"(>(words[word_index++]);
-)");
-                        auto &enumerants = util::get<ast::Operand_kinds::Operand_kind::Enumerants>(
-                            operand_kind.value);
-                        for(auto &enumerant : enumerants.enumerants)
-                        {
-                            if(enumerant.parameters.empty())
-                                continue;
-                            auto enumerant_member_name = get_member_name_from_enumerant(enumerant);
-                            auto enumerant_name =
-                                get_enumerant_name(operand_kind.kind, enumerant.enumerant, false);
-                            state
-                                << indent(
-                                       R"(if((static_cast<Word>(value.value) & static_cast<Word>()")
-                                << enum_name << "::" << enumerant_name
-                                << indent(true, R"()) == static_cast<Word>()") << enum_name
-                                << "::" << enumerant_name << indent(true, R"())
-{
-`value.)") << enumerant_member_name
-                                << indent(true, R"(.emplace();
-)");
-                            bool first = true;
-                            for(auto &parameter : enumerant.parameters.parameters)
-                            {
-                                auto parameter_member_name =
-                                    get_member_name_from_parameter(parameter);
-                                auto parameter_parse_function =
-                                    get_parse_operand_function_name(parameter);
-                                state << indent(1);
-                                if(first)
-                                {
-                                    state << indent(true, "auto ");
-                                    first = false;
-                                }
-                                state << indent(true, "parse_error = ") << parameter_parse_function
-                                      << "(words, word_count, semantics, error_instruction_index, "
-                                         "word_index, value."
-                                      << enumerant_member_name << "->" << parameter_member_name
-                                      << indent(true, R"();
-`if(parse_error)
-``return parse_error;
-)");
-                            }
-                            state << indent(R"(}
-)");
-                        }
-                    }
-                    else
-                    {
-                        state << indent(R"(value = static_cast<)") << enum_name
-                              << indent(true, R"(>(words[word_index++]);
-)");
-                    }
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::value_enum:
-                {
-                    auto enum_name = get_enum_name(operand_kind);
-                    if(get_operand_has_any_parameters(state, operand_kind))
-                    {
-                        state << indent(R"(value.value = static_cast<)") << enum_name
-                              << indent(true, R"(>(words[word_index++]);
-switch(value.value)
-{
-)");
-                        auto &enumerants = util::get<ast::Operand_kinds::Operand_kind::Enumerants>(
-                            operand_kind.value);
-                        for(auto &enumerant : enumerants.enumerants)
-                        {
-                            auto enumerant_name =
-                                get_enumerant_name(operand_kind.kind, enumerant.enumerant, false);
-                            state << indent("case ") << enum_name << "::" << enumerant_name
-                                  << indent(true, R"(:
-)");
-                            if(enumerant.parameters.empty())
-                            {
-                                state << indent(R"(`break;
-)");
-                                continue;
-                            }
-                            auto enumerant_parameters_struct_name =
-                                get_enumerant_parameters_struct_name(
-                                    operand_kind.kind, enumerant.enumerant, false);
-                            state << indent(R"({
-`value.parameters.emplace<)") << enumerant_parameters_struct_name
-                                  << indent(true, R"(>();
-`auto &parameters = util::get<)") << enumerant_parameters_struct_name
-                                  << indent(true, R"(>(value.parameters);
-)");
-                            bool first = true;
-                            for(auto &parameter : enumerant.parameters.parameters)
-                            {
-                                auto parameter_member_name =
-                                    get_member_name_from_parameter(parameter);
-                                auto parameter_parse_function =
-                                    get_parse_operand_function_name(parameter);
-                                state << indent(1);
-                                if(first)
-                                {
-                                    state << indent(true, "auto ");
-                                    first = false;
-                                }
-                                state << indent(true, "parse_error = ") << parameter_parse_function
-                                      << "(words, word_count, semantics, error_instruction_index, "
-                                         "word_index, parameters."
-                                      << parameter_member_name << indent(true, R"();
-`if(parse_error)
-``return parse_error;
-)");
-                            }
-                            state << indent(R"(`break;
-}
-)");
-                        }
-                        state << indent(R"(default:
-`word_index--;
-`return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "invalid enum value");
-}
-)");
-                    }
-                    else
-                    {
-                        state << indent(R"(value = static_cast<)") << enum_name
-                              << indent(true, R"(>(words[word_index]);
-if(util::Enum_traits<)") << enum_name
-                              << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
-                              << enum_name << indent(true, R"(>::npos)
-`return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "invalid enum value");
-word_index++;
-)");
-                    }
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::composite:
-                {
-                    auto &bases =
-                        util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
-                    for(std::size_t i = 0; i < bases.values.size(); i++)
-                    {
-                        state << indent;
-                        if(i == 0)
-                            state << indent(true, "auto ");
-                        state << indent(true, "parse_error = ")
-                              << get_parse_operand_function_name(bases.values[i])
-                              << "(words, word_count, semantics, error_instruction_index, "
-                                 "word_index, value."
-                              << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
-                                                                                            "part_")
-                              << indent(true, R"();
-if(parse_error)
-`return parse_error;
-)");
-                    }
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::id:
-                {
-                    state << indent(R"(value = static_cast<Id>(words[word_index++]);
-)");
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::literal:
-                {
-                    auto literal_kind =
-                        ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
-                            operand_kind.kind);
-                    if(!literal_kind)
-                        throw Generate_error("bad literal kind");
-                    switch(*literal_kind)
-                    {
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
-                        // TODO: fix after determining if LiteralInteger can be multiple words
-                        state << indent(R"(value = words[word_index++];
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
-                        state << indent(
-                            R"(value.clear();
-bool done = false;
-while(!done)
-{
-`if(word_index >= word_count)
-``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string missing terminating null");
-`Word word = words[word_index++];
-`for(std::size_t i = 0; i < 4; i++)
-`{
-``unsigned char ch = word & 0xFFU;
-``word >>= 8;
-``if(ch == '\0')
-``{
-```done = true;
-```if(word != 0)
-````return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string has non-zero padding");
-``}
-``else
-``{
-```value += ch;
-``}
-`}
-}
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::
-                        literal_context_dependent_number:
-                        state << indent(
-                            R"(static_assert(std::is_same<decltype(value), std::vector<Word> &>::value, "missing parse code for operand kind");
-value.clear();
-value.reserve(word_count - word_index);
-while(word_index < word_count)
-`value.push_back(words[word_index++]);
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
-                        state << indent(R"(value = words[word_index++];
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::
-                        literal_spec_constant_op_integer:
-                        state << indent(R"(value = static_cast<)") << op_enum_name
-                              << indent(true, R"(>(words[word_index++]);
-)");
-                        break;
-                    }
-                    break;
-                }
-                }
-                push_indent.finish();
-                state << indent(R"(`return nullptr;
-}
-)");
-            }
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-                auto parse_function_name = get_parse_instruction_function_name(instruction.opname);
-                state
-                    << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
-                    << indent(
-                           true,
-                           R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
-{
-`std::size_t word_index = 1; // skip opcode
-)");
-                auto push_indent2 = state.pushed_indent();
-                state << indent << struct_name << " instruction;\n";
-                if(!instruction.operands.empty())
-                    state << indent("std::unique_ptr<Parse_error> parse_error;\n");
-                for(auto &operand : instruction.operands.operands)
-                {
-                    auto parse_operand_function_name = get_parse_operand_function_name(operand);
-                    auto member_name = get_member_name_from_operand(operand);
-                    switch(operand.quantifier)
-                    {
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::none:
-                    {
-                        state
-                            << indent(R"(parse_error = )") << parse_operand_function_name
-                            << indent(
-                                   true,
-                                   R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
-                            << member_name << indent(true, R"();
-if(parse_error)
-`return parse_error;
-)");
-                        break;
-                    }
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
-                    {
-                        state
-                            << indent(R"(if(word_index < word_count)
-{
-`instruction.)") << member_name
-                            << indent(true, R"(.emplace();
-`parse_error = )") << parse_operand_function_name
-                            << indent(
-                                   true,
-                                   R"((words, word_count, semantics, error_instruction_index, word_index, *instruction.)")
-                            << member_name << indent(true, R"();
-`if(parse_error)
-``return parse_error;
-}
-)");
-                        break;
-                    }
-                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
-                    {
-                        state
-                            << indent(R"(while(word_index < word_count)
-{
-`instruction.)") << member_name
-                            << indent(true, R"(.emplace_back();
-`parse_error = )") << parse_operand_function_name
-                            << indent(
-                                   true,
-                                   R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
-                            << member_name << indent(true, R"(.back());
-`if(parse_error)
-``return parse_error;
-}
-)");
-                    }
-                    }
-                }
-                push_indent2.finish();
-                state << indent(R"(`if(word_index < word_count)
-``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "extra words at end of instruction");
-`semantics.handle_instruction(std::move(instruction));
-`return nullptr;
-}
-)");
-            }
-            state << indent(
-                R"(static std::unique_ptr<Parse_error> parse_instruction(const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
-{
-`Op op = static_cast<Op>(words[0] & 0xFFFFU);
-`switch(op)
-`{
-)");
-            for(auto &instruction : top_level.instructions.instructions)
-            {
-                auto push_indent2 = state.pushed_indent(2);
-                auto enumerant_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-                auto parse_function_name = get_parse_instruction_function_name(instruction.opname);
-                state << indent("case ") << op_enum_name << "::" << enumerant_name
-                      << indent(true, R"(:
-`return )") << parse_function_name
-                      << indent(true, R"((words, word_count, semantics, error_instruction_index);
-)");
-            }
-            state << indent(R"(`}
-`return semantics.handle_error(error_instruction_index, error_instruction_index, json::ast::Number_value::append_unsigned_integer_to_string(static_cast<Word>(op), "unknown instruction: 0x", 0x10));
-}
-static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_count, Semantics &semantics)
-{
-`std::size_t word_index = 0;
-`if(word_index >= word_count)
-``return semantics.handle_error(word_index, 0, "hit EOF when parsing magic number");
-`if(words[word_index] != magic_number)
-``return semantics.handle_error(word_index, 0, "invalid magic number");
-`word_index++;
-`if(word_index >= word_count)
-``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V version");
-`if(words[word_index] & ~0xFFFF00UL)
-``return semantics.handle_error(word_index, 0, "invalid SPIR-V version");
-`auto input_major_version = words[word_index] >> 16;
-`auto input_minor_version = (words[word_index] >> 8) & 0xFFU;
-`semantics.handle_spirv_version(input_major_version, input_minor_version);
-`if(input_major_version != major_version || input_minor_version > minor_version)
-``return semantics.handle_error(word_index, 0, "SPIR-V version not supported");
-`word_index++;
-`if(word_index >= word_count)
-``return semantics.handle_error(word_index, 0, "hit EOF when parsing generator's magic number");
-`semantics.handle_generator_magic_number(words[word_index++]);
-`if(word_index >= word_count)
-``return semantics.handle_error(word_index, 0, "hit EOF when parsing id bound");
-`semantics.handle_id_bound(words[word_index++]);
-`if(word_index >= word_count)
-``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V shader header");
-`if(words[word_index] != 0)
-``return semantics.handle_error(word_index, 0, "nonzero reserved word in SPIR-V shader header");
-`word_index++;
-`// now we've finished reading the shader header, the rest of the shader is just instructions
-`while(word_index < word_count)
-`{
-``auto instruction_word_count = words[word_index] >> 16;
-``if(instruction_word_count == 0)
-```return semantics.handle_error(word_index, word_index, "invalid instruction");
-``if(word_index + instruction_word_count > word_count)
-```return semantics.handle_error(word_index, word_index, "instruction longer than rest of shader");
-``auto parse_error = parse_instruction(words + word_index, instruction_word_count, semantics, word_index);
-``if(parse_error)
-```return parse_error;
-``word_index += instruction_word_count;
-`}
-`return nullptr;
-}
-)");
-        }
-        state << "};\n";
-        write_namespaces_end(state, spirv_namespace_names);
-        write_file_guard_end(state);
-    }
-};
-
-struct Parser_source_generator final : public Generator
-{
-    Parser_source_generator() : Generator("parser.cpp")
-    {
-    }
-    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
-    {
-        Generator_state state(this, generator_args, top_level);
-        state.open_output_file();
-        write_file_comments(state, top_level.copyright);
-        state << "#include \"parser.h\"\n"
-                 "#include <type_traits>\n"
-                 "\n";
-        write_namespaces_start(state, spirv_namespace_names);
-        state << indent(R"(namespace
-{
-/** instantiate Parser with Parse_semantics_generic to help catch bugs */
-[[gnu::unused]] auto parser_test(const Word *words, std::size_t word_count, Parse_semantics_generic &semantics)
-{
-`return Parser<>::parse(words, word_count, semantics);
-}
-}
-
-std::unique_ptr<Parse_error> Parse_dump::handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message)
-{
-`return std::unique_ptr<Parse_error>(new Parse_error(word_index, instruction_word_index, std::move(message)));
-}
-
-void Parse_dump::handle_spirv_version(unsigned major, unsigned minor)
-{
-`os << "SPIR-V version " << major << "." << minor << "\n";
-}
-
-void Parse_dump::handle_generator_magic_number(Word value)
-{
-`os << "generator magic number: " << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10) << "\n";
-}
-
-void Parse_dump::handle_id_bound(Word id_bound)
-{
-`os << "id bound: " << json::ast::Number_value::unsigned_integer_to_string(id_bound) << "\n";
-}
-)");
-        for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
-        {
-            auto dump_function_name =
-                Parser_header_generator::get_dump_operand_function_name(operand_kind);
-            {
-                state << indent(R"(
-void Parse_dump::)") << dump_function_name
-                      << "(const " << get_operand_with_parameters_name(state, operand_kind)
-                      << R"( &value)
-{
-)";
-                auto push_indent = state.pushed_indent();
-                switch(operand_kind.category)
-                {
-                case ast::Operand_kinds::Operand_kind::Category::bit_enum:
-                {
-                    bool operand_has_any_parameters =
-                        get_operand_has_any_parameters(state, operand_kind);
-                    state << indent(R"(Word bits = static_cast<Word>(value)")
-                          << (operand_has_any_parameters ? ".value" : "") << indent(true, R"();
-bool first = true;
-)");
-                    auto enum_name = get_enum_name(operand_kind);
-                    auto &enumerants =
-                        util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
-                    const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant *zero_enumerant =
-                        nullptr;
-                    for(auto &enumerant : enumerants.enumerants)
-                    {
-                        if(enumerant.value == 0)
-                        {
-                            zero_enumerant = &enumerant;
-                            continue;
-                        }
-                        auto enumerant_name =
-                            get_enumerant_name(operand_kind.kind, enumerant.enumerant, false);
-                        auto scoped_enumerant_name = enum_name + "::" + enumerant_name;
-                        state << indent(R"(if((bits & static_cast<Word>()") << scoped_enumerant_name
-                              << indent(true, R"()) == static_cast<Word>()")
-                              << scoped_enumerant_name << indent(true, R"())
-{
-`bits &= ~static_cast<Word>()")
-                              << scoped_enumerant_name << indent(true, R"();
-`if(first)
-``first = false;
-`else
-``os << " | ";
-`os << get_enumerant_name()") << scoped_enumerant_name
-                              << indent(true, R"();
-)");
-                        if(!enumerant.parameters.empty())
-                        {
-                            auto enumerant_member_name = get_member_name_from_enumerant(enumerant);
-                            state << indent(R"(`os << "(";
-`if(value.)") << enumerant_member_name
-                                  << indent(true, R"()
-`{
-``auto &parameters = *value.)") << enumerant_member_name
-                                  << indent(true, R"(;
-)");
-                            bool first = true;
-                            for(auto &parameter : enumerant.parameters.parameters)
-                            {
-                                if(first)
-                                    first = false;
-                                else
-                                    state << indent(R"(``os << ", ";
-)");
-                                state << indent(2)
-                                      << Parser_header_generator::get_dump_operand_function_name(
-                                             parameter)
-                                      << "(parameters." << get_member_name_from_parameter(parameter)
-                                      << ");\n";
-                            }
-                            state << indent(R"a(`}
-`os << ")";
-)a");
-                        }
-                        state << indent(R"(}
-)");
-                    }
-                    std::string zero_enumerant_name_code;
-                    if(zero_enumerant)
-                    {
-                        zero_enumerant_name_code =
-                            "get_enumerant_name(" + enum_name + "::"
-                            + get_enumerant_name(
-                                  operand_kind.kind, zero_enumerant->enumerant, false)
-                            + ")";
-                    }
-                    else
-                    {
-                        zero_enumerant_name_code = "\"0\"";
-                    }
-                    state << indent(R"(if(bits != 0)
-{
-`if(!first)
-``os << " | ";
-`os << json::ast::Number_value::append_unsigned_integer_to_string(bits, "0x", 0x10);
-}
-else if(first)
-{
-`os << )") << zero_enumerant_name_code
-                          << indent(true, R"(;
-}
-)");
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::value_enum:
-                {
-                    auto enum_name = get_enum_name(operand_kind);
-                    if(get_operand_has_any_parameters(state, operand_kind))
-                    {
-                        state << indent(R"(switch(value.value)
-{
-)");
-                        auto &enumerants = util::get<ast::Operand_kinds::Operand_kind::Enumerants>(
-                            operand_kind.value);
-                        bool any_parameterless_enumerants = false;
-                        for(auto &enumerant : enumerants.enumerants)
-                        {
-                            if(!enumerant.parameters.empty())
-                                continue;
-                            any_parameterless_enumerants = true;
-                            state << indent("case ") << enum_name
-                                  << "::" << get_enumerant_name(
-                                                 operand_kind.kind, enumerant.enumerant, false)
-                                  << ":\n";
-                        }
-                        if(any_parameterless_enumerants)
-                        {
-                            state << indent(R"(`os << get_enumerant_name(value.value);
-`break;
-)");
-                        }
-                        for(auto &enumerant : enumerants.enumerants)
-                        {
-                            if(enumerant.parameters.empty())
-                                continue;
-                            auto enumerant_name =
-                                get_enumerant_name(operand_kind.kind, enumerant.enumerant, false);
-                            auto scoped_enumerant_name = enum_name + "::" + enumerant_name;
-                            auto enumerant_parameters_struct_name =
-                                get_enumerant_parameters_struct_name(
-                                    operand_kind.kind, enumerant.enumerant, false);
-                            state << indent("case ") << scoped_enumerant_name << indent(true, R"(:
-{
-`os << get_enumerant_name()") << scoped_enumerant_name
-                                  << indent(true, R"() << "(";
-`auto *parameters = util::get_if<)")
-                                  << enumerant_parameters_struct_name
-                                  << indent(true, R"(>(&value.parameters);
-`if(parameters)
-`{
-)");
-                            bool first = true;
-                            for(auto &parameter : enumerant.parameters.parameters)
-                            {
-                                if(first)
-                                    first = false;
-                                else
-                                    state << indent(R"(``os << ", ";
-)");
-                                state << indent(2)
-                                      << Parser_header_generator::get_dump_operand_function_name(
-                                             parameter)
-                                      << "(parameters->"
-                                      << get_member_name_from_parameter(parameter) << ");\n";
-                            }
-                            state << indent(R"a(`}
-`os << ")";
-`break;
-}
-)a");
-                        }
-                        state << indent(R"(default:
-`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(value.value));
-}
-)");
-                    }
-                    else
-                    {
-                        state << indent(R"(if(util::Enum_traits<)") << enum_name
-                              << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
-                              << enum_name << indent(true, R"(>::npos)
-`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(value));
-else
-`os << get_enumerant_name(value);
-)");
-                    }
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::composite:
-                {
-                    auto &bases =
-                        util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
-                    state << indent("os << \"{\";\n");
-                    for(std::size_t i = 0; i < bases.values.size(); i++)
-                    {
-                        if(i != 0)
-                        {
-                            state << indent("os << \", \";\n");
-                        }
-                        state << indent << Parser_header_generator::get_dump_operand_function_name(
-                                               bases.values[i])
-                              << "(value."
-                              << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
-                                                                                            "part_")
-                              << ");\n";
-                    }
-                    state << indent("os << \"}\";\n");
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::id:
-                {
-                    state << indent(
-                        R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "#");
-)");
-                    break;
-                }
-                case ast::Operand_kinds::Operand_kind::Category::literal:
-                {
-                    auto literal_kind =
-                        ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
-                            operand_kind.kind);
-                    if(!literal_kind)
-                        throw Generate_error("bad literal kind");
-                    switch(*literal_kind)
-                    {
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
-                        state << indent(
-                            R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x");
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
-                        state << indent(
-                            R"(json::ast::String_value::write(os, value);
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::
-                        literal_context_dependent_number:
-                        state << indent(
-                            R"(static_assert(std::is_same<decltype(value), const std::vector<Word> &>::value, "missing dump code for operand kind");
-auto separator = "";
-os << "{";
-for(Word word : value)
-{
-`os << separator;
-`separator = ", ";
-`os << json::ast::Number_value::append_unsigned_integer_to_string(word, "0x", 0x10, 8);
-}
-os << "}";
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
-                        state << indent(
-                            R"(os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x");
-)");
-                        break;
-                    case ast::Operand_kinds::Operand_kind::Literal_kind::
-                        literal_spec_constant_op_integer:
-                        state << indent(R"(if(util::Enum_traits<)") << op_enum_name
-                              << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
-                              << op_enum_name << indent(true, R"(>::npos)
-`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(value));
-else
-`os << get_enumerant_name(value);
-)");
-                        break;
-                    }
-                    break;
-                }
-                }
-                push_indent.finish();
-                state << indent("}\n");
-            }
-            state << indent(R"(
-void Parse_dump::)")
-                  << dump_function_name << "(const util::optional<"
-                  << get_operand_with_parameters_name(state, operand_kind)
-                  << indent(true, R"(> &value)
-{
-`if(value)
-)") << indent(2) << dump_function_name
-                  << indent(true, R"((*value);
-`else
-``os << "nullopt";
-}
-
-void Parse_dump::)")
-                  << dump_function_name << "(const std::vector<"
-                  << get_operand_with_parameters_name(state, operand_kind)
-                  << indent(true, R"(> &values)
-{
-`auto separator = "";
-`os << "{";
-`for(auto &value : values)
-`{
-``os << separator;
-``separator = ", ";
-)") << indent(2) << dump_function_name
-                  << indent(true, R"((value);
-`}
-`os << "}";
-}
-)");
-        }
-        for(auto &instruction : top_level.instructions.instructions)
-        {
-            auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
-            state << indent(
-                         "\n"
-                         "void Parse_dump::handle_instruction(")
-                  << struct_name << indent(true, R"( instruction)
-{
-`os << ")") << instruction.opname
-                  << indent(true, R"(\n";
-)");
-            for(auto &operand : instruction.operands.operands)
-            {
-                auto push_indent = state.pushed_indent();
-                auto member_name = get_member_name_from_operand(operand);
-                state << indent("os << \"    ") << member_name << indent(true, R"(:";
-)") << indent << Parser_header_generator::get_dump_operand_function_name(operand.kind)
-                      << indent(true, R"((instruction.)") << member_name << indent(true, R"();
-os << "\n";
-)");
-            }
-            state << indent("}\n");
-        }
-        write_namespaces_end(state, spirv_namespace_names);
-    }
-};
-
-std::unique_ptr<Generator> Generators::make_spirv_header_generator()
-{
-    return std::unique_ptr<Generator>(new Spirv_header_generator);
-}
-
-std::unique_ptr<Generator> Generators::make_spirv_source_generator()
-{
-    return std::unique_ptr<Generator>(new Spirv_source_generator);
-}
-
-std::unique_ptr<Generator> Generators::make_parser_header_generator()
-{
-    return std::unique_ptr<Generator>(new Parser_header_generator);
-}
-
-std::unique_ptr<Generator> Generators::make_parser_source_generator()
-{
-    return std::unique_ptr<Generator>(new Parser_source_generator);
-}
-
-std::vector<std::unique_ptr<Generator>> Generators::make_all_generators()
-{
-    std::unique_ptr<Generator> generators_array[] = {
-        make_spirv_header_generator(),
-        make_spirv_source_generator(),
-        make_parser_header_generator(),
-        make_parser_source_generator(),
-    };
-    // use array then move because you can't move out of an std::initializer_list
-    std::vector<std::unique_ptr<Generator>> retval;
-    retval.reserve(sizeof(generators_array) / sizeof(generators_array[0]));
-    for(auto &generator : generators_array)
-        retval.push_back(std::move(generator));
-    return retval;
-}
-}
-}
-}
diff --git a/src/generate_spirv_parser/generate-old.h b/src/generate_spirv_parser/generate-old.h
deleted file mode 100644 (file)
index 1a40f76..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright 2017 Jacob Lifshay
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef GENERATE_SPIRV_PARSER_GENERATE_OLD_H_
-#define GENERATE_SPIRV_PARSER_GENERATE_OLD_H_
-
-#include "ast.h"
-#include "util/string_view.h"
-#include <fstream>
-#include <memory>
-#include <string>
-#include <cassert>
-#include <type_traits>
-#include <cstdint>
-#include <unordered_set>
-#include <unordered_map>
-#include <vector>
-#include <stdexcept>
-
-namespace vulkan_cpu
-{
-namespace generate_spirv_parser
-{
-namespace generate
-{
-struct Generate_error : public std::runtime_error
-{
-    using runtime_error::runtime_error;
-};
-
-class Generator
-{
-private:
-    struct Tester;
-
-public:
-    struct Generator_args
-    {
-        std::string output_directory;
-        explicit Generator_args(std::string output_directory) noexcept
-            : output_directory(std::move(output_directory))
-        {
-        }
-        Generator_args(Generator_args &&) = default;
-        Generator_args &operator=(Generator_args &&) = default;
-        Generator_args(const Generator_args &) = delete;
-        Generator_args &operator=(const Generator_args &) = delete;
-    };
-
-protected:
-    class Push_indent;
-    struct Generator_state
-    {
-        Generator_args &generator_args;
-        std::size_t indent_level;
-        std::string full_output_file_name;
-        std::string guard_macro_name;
-        std::ofstream os;
-        const ast::Top_level &top_level;
-        std::unordered_map<std::string, const ast::Operand_kinds::Operand_kind *> operand_kind_map;
-        std::unordered_map<const ast::Operand_kinds::Operand_kind *, bool>
-            operand_has_any_parameters_map;
-        explicit Generator_state(const Generator *generator,
-                                 Generator_args &generator_args,
-                                 const ast::Top_level &top_level);
-        void open_output_file();
-        template <typename T, typename = decltype(os << std::declval<T>())>
-        Generator_state &operator<<(T &&v)
-        {
-            os << std::forward<T>(v);
-            return *this;
-        }
-        Generator_state &operator<<(const ast::Capabilities &v)
-        {
-            write_capabilities_set(*this, v);
-            return *this;
-        }
-        Generator_state &operator<<(const ast::Extensions &v)
-        {
-            write_extensions_set(*this, v);
-            return *this;
-        }
-        Push_indent pushed_indent(std::ptrdiff_t amount = 1) noexcept;
-    };
-    class Push_indent final
-    {
-        Push_indent(const Push_indent &) = delete;
-        Push_indent &operator=(const Push_indent &) = delete;
-
-    private:
-        Generator_state *state;
-        std::ptrdiff_t amount;
-
-    public:
-        explicit Push_indent(Generator_state &state, std::ptrdiff_t amount = 1) noexcept
-            : state(&state),
-              amount(amount)
-        {
-            state.indent_level += amount;
-        }
-        Push_indent(Push_indent &&rt) noexcept : state(rt.state), amount(rt.amount)
-        {
-            rt.state = nullptr;
-        }
-        void finish() noexcept
-        {
-            assert(state);
-            state->indent_level -= amount;
-            state = nullptr;
-        }
-        ~Push_indent()
-        {
-            if(state)
-                state->indent_level -= amount;
-        }
-    };
-    // translates initial '`' (backtick) characters to indentations
-    struct Indent_interpreted_text
-    {
-        const char *text;
-        std::ptrdiff_t indent_offset;
-        bool start_indented;
-        constexpr explicit Indent_interpreted_text(const char *text,
-                                                   std::ptrdiff_t indent_offset,
-                                                   bool start_indented) noexcept
-            : text(text),
-              indent_offset(indent_offset),
-              start_indented(start_indented)
-        {
-        }
-        friend Generator_state &operator<<(Generator_state &state, Indent_interpreted_text v)
-        {
-            write_indent_interpreted_text(state, v.text, v.indent_offset, v.start_indented);
-            return state;
-        }
-    };
-    struct Indent_t
-    {
-        std::ptrdiff_t offset;
-        explicit Indent_t() = default;
-        constexpr Indent_t operator()(std::ptrdiff_t additional_offset) const noexcept
-        {
-            return Indent_t{offset + additional_offset};
-        }
-        constexpr Indent_interpreted_text operator()(const char *text) const noexcept
-        {
-            return Indent_interpreted_text(text, offset, false);
-        }
-        constexpr Indent_interpreted_text operator()(bool start_indented, const char *text) const
-            noexcept
-        {
-            return Indent_interpreted_text(text, offset, start_indented);
-        }
-        friend Generator_state &operator<<(Generator_state &state, Indent_t indent)
-        {
-            write_indent(state, indent.offset);
-            return state;
-        }
-    };
-    static constexpr auto indent = Indent_t{0};
-    enum class Integer_literal_base
-    {
-        dec = 0,
-        hex,
-        oct
-    };
-    struct Unsigned_integer_literal
-    {
-        std::uint64_t value;
-        Integer_literal_base base;
-        std::size_t minimum_digit_count;
-        constexpr Unsigned_integer_literal(std::uint64_t value,
-                                           Integer_literal_base base,
-                                           std::size_t minimum_digit_count = 1) noexcept
-            : value(value),
-              base(base),
-              minimum_digit_count(minimum_digit_count)
-        {
-        }
-        friend Generator_state &operator<<(Generator_state &state, Unsigned_integer_literal v)
-        {
-            write_unsigned_integer_literal(state, v.value, v.base, v.minimum_digit_count);
-            return state;
-        }
-    };
-    static constexpr Unsigned_integer_literal unsigned_dec_integer_literal(
-        std::uint64_t value) noexcept
-    {
-        return Unsigned_integer_literal(value, Integer_literal_base::dec);
-    }
-    static constexpr Unsigned_integer_literal unsigned_hex_integer_literal(
-        std::uint64_t value, std::size_t minimum_digit_count = 1) noexcept
-    {
-        return Unsigned_integer_literal(value, Integer_literal_base::hex, minimum_digit_count);
-    }
-    static constexpr Unsigned_integer_literal unsigned_oct_integer_literal(
-        std::uint64_t value, std::size_t minimum_digit_count = 1) noexcept
-    {
-        return Unsigned_integer_literal(value, Integer_literal_base::oct, minimum_digit_count);
-    }
-    struct Signed_integer_literal
-    {
-        std::int64_t value;
-        constexpr explicit Signed_integer_literal(std::int64_t value) noexcept : value(value)
-        {
-        }
-        friend Generator_state &operator<<(Generator_state &state, Signed_integer_literal v)
-        {
-            write_signed_integer_literal(state, v.value);
-            return state;
-        }
-    };
-    static constexpr Signed_integer_literal signed_integer_literal(std::int64_t value) noexcept
-    {
-        return Signed_integer_literal(value);
-    }
-
-protected:
-    const char *const output_base_file_name;
-
-protected:
-    static std::string get_guard_macro_name_from_file_name(std::string file_name);
-    static std::string get_enumerant_name(util::string_view enumeration_name,
-                                          std::string enumerant_name,
-                                          bool input_name_should_have_prefix)
-    {
-        return get_enumerant_name(enumeration_name.data(),
-                                  enumeration_name.size(),
-                                  std::move(enumerant_name),
-                                  input_name_should_have_prefix);
-    }
-    static std::string get_enumerant_name(const char *enumeration_name,
-                                          std::size_t enumeration_name_size,
-                                          std::string enumerant_name,
-                                          bool input_name_should_have_prefix);
-    static void write_indent_absolute(Generator_state &state, std::size_t amount);
-    static void write_indent(Generator_state &state, std::ptrdiff_t offset)
-    {
-        write_indent_absolute(state, state.indent_level + offset);
-    }
-    static void write_indent_interpreted_text(Generator_state &state,
-                                              const char *text,
-                                              std::ptrdiff_t offset,
-                                              bool start_indented);
-    static void write_automatically_generated_file_warning(Generator_state &state);
-    static void write_copyright_comment(Generator_state &state, const ast::Copyright &copyright);
-    static void write_file_comments(Generator_state &state, const ast::Copyright &copyright)
-    {
-        write_automatically_generated_file_warning(state);
-        write_copyright_comment(state, copyright);
-    }
-    static void write_file_guard_start(Generator_state &state);
-    static void write_file_guard_end(Generator_state &state);
-    static void write_namespace_start(Generator_state &state, const char *namespace_name);
-    static void write_namespace_start(Generator_state &state, const std::string &namespace_name);
-
-private:
-    static void write_namespace_end(Generator_state &state);
-
-protected:
-    static void write_namespace_end(Generator_state &state, const char *namespace_name)
-    {
-        write_namespace_end(state);
-    }
-    static void write_namespace_end(Generator_state &state, const std::string &namespace_name)
-    {
-        write_namespace_end(state);
-    }
-    static void write_namespaces_start(Generator_state &state,
-                                       const char *const *namespace_names,
-                                       std::size_t namespace_name_count)
-    {
-        for(std::size_t i = 0; i < namespace_name_count; i++)
-            write_namespace_start(state, namespace_names[i]);
-    }
-    static void write_namespaces_start(Generator_state &state,
-                                       const std::string *namespace_names,
-                                       std::size_t namespace_name_count)
-    {
-        for(std::size_t i = 0; i < namespace_name_count; i++)
-            write_namespace_start(state, namespace_names[i]);
-    }
-    static void write_namespaces_end(Generator_state &state,
-                                     const char *const *namespace_names,
-                                     std::size_t namespace_name_count)
-    {
-        for(std::size_t i = 0; i < namespace_name_count; i++)
-            write_namespace_end(state, namespace_names[namespace_name_count - i - 1]);
-        state << '\n';
-    }
-    static void write_namespaces_end(Generator_state &state,
-                                     const std::string *namespace_names,
-                                     std::size_t namespace_name_count)
-    {
-        for(std::size_t i = 0; i < namespace_name_count; i++)
-            write_namespace_end(state, namespace_names[namespace_name_count - i - 1]);
-        state << '\n';
-    }
-    template <typename T, std::size_t N>
-    static void write_namespaces_start(Generator_state &state, const T(&namespace_names)[N])
-    {
-        write_namespaces_start(state, namespace_names, N);
-    }
-    template <typename T, std::size_t N>
-    static void write_namespaces_end(Generator_state &state, const T(&namespace_names)[N])
-    {
-        write_namespaces_end(state, namespace_names, N);
-    }
-    static void write_namespaces_start(Generator_state &state,
-                                       std::initializer_list<std::string> namespace_names)
-    {
-        write_namespaces_start(state, namespace_names.begin(), namespace_names.size());
-    }
-    static void write_namespaces_start(Generator_state &state,
-                                       std::initializer_list<const char *> namespace_names)
-    {
-        write_namespaces_start(state, namespace_names.begin(), namespace_names.size());
-    }
-    static void write_namespaces_end(Generator_state &state,
-                                     std::initializer_list<std::string> namespace_names)
-    {
-        write_namespaces_end(state, namespace_names.begin(), namespace_names.size());
-    }
-    static void write_namespaces_end(Generator_state &state,
-                                     std::initializer_list<const char *> namespace_names)
-    {
-        write_namespaces_end(state, namespace_names.begin(), namespace_names.size());
-    }
-    static void write_unsigned_integer_literal(Generator_state &state,
-                                               std::uint64_t value,
-                                               Integer_literal_base base,
-                                               std::size_t minimum_digit_count);
-    static void write_signed_integer_literal(Generator_state &state, std::int64_t value);
-
-private:
-    struct Get_extensions_visitor;
-
-protected:
-    static std::unordered_set<std::string> get_extensions(const ast::Top_level &top_level);
-    static void write_capabilities_set(Generator_state &state,
-                                       const ast::Capabilities &capabilities);
-    static void write_extensions_set(Generator_state &state, const ast::Extensions &extensions);
-    static std::string get_name_from_words(const std::string &words);
-    static std::string get_member_name_from_operand(
-        const ast::Instructions::Instruction::Operands::Operand &operand);
-    static std::string get_member_name_from_parameter(
-        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter
-            &parameter);
-    static std::string get_member_name_from_enumerant(
-        const ast::Operand_kinds::Operand_kind::Enumerants::Enumerant
-            &enumerant);
-    static const ast::Operand_kinds::Operand_kind &get_operand_kind_from_string(
-        Generator_state &state, const std::string &operand_kind_str)
-    {
-        auto *retval = state.operand_kind_map[operand_kind_str];
-        if(!retval)
-            throw Generate_error("operand kind not found: " + operand_kind_str);
-        return *retval;
-    }
-    static bool get_operand_has_any_parameters(Generator_state &state,
-                                               const ast::Operand_kinds::Operand_kind &operand_kind)
-    {
-        return state.operand_has_any_parameters_map[&operand_kind];
-    }
-    static std::string get_enumerant_parameters_struct_name(util::string_view enumeration_name,
-                                                            std::string enumerant_name,
-                                                            bool input_name_should_have_prefix)
-    {
-        auto retval = "_" + get_enumerant_name(
-                                enumeration_name, enumerant_name, input_name_should_have_prefix)
-                      + "_parameters";
-        retval.insert(retval.begin(), enumeration_name.begin(), enumeration_name.end());
-        return retval;
-    }
-    static std::string get_operand_with_parameters_name(
-        Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind);
-    static std::string get_operand_with_parameters_name(Generator_state &state,
-                                                        const std::string &operand_kind_str)
-    {
-        return get_operand_with_parameters_name(
-            state, get_operand_kind_from_string(state, operand_kind_str));
-    }
-    static std::string get_operand_with_parameters_name(
-        Generator_state &state, const ast::Instructions::Instruction::Operands::Operand &operand)
-    {
-        return get_operand_with_parameters_name(state,
-                                                get_operand_kind_from_string(state, operand.kind));
-    }
-    static std::string get_enum_name(std::string operand_kind_str)
-    {
-        return operand_kind_str;
-    }
-    static std::string get_enum_name(const ast::Operand_kinds::Operand_kind &operand_kind)
-    {
-        return get_enum_name(operand_kind.kind);
-    }
-    static void write_struct_nonstatic_members_and_constructors(Generator_state &state,
-                                                                const std::string &struct_name,
-                                                                const std::string *member_types,
-                                                                const std::string *member_names,
-                                                                std::size_t member_count);
-    static std::vector<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant>
-        get_unique_enumerants(
-            std::vector<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant> enumerants);
-
-protected:
-    static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu";
-    static constexpr const char *spirv_namespace_name = "spirv";
-    static constexpr const char *spirv_namespace_names[] = {
-        vulkan_cpu_namespace_name, spirv_namespace_name,
-    };
-    static constexpr const char *capability_enum_name = "Capability";
-    static constexpr const char *extension_enum_name = "Extension";
-    static constexpr const char *op_enum_name = "Op";
-
-public:
-    explicit Generator(const char *output_base_file_name) noexcept
-        : output_base_file_name(output_base_file_name)
-    {
-    }
-    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const = 0;
-    void run(Generator_args &&generator_args, const ast::Top_level &top_level) const
-    {
-        run(generator_args, top_level);
-    }
-
-public:
-    virtual ~Generator() = default;
-};
-
-inline Generator::Push_indent Generator::Generator_state::pushed_indent(
-    std::ptrdiff_t amount) noexcept
-{
-    return Push_indent(*this, amount);
-}
-
-struct Spirv_header_generator;
-struct Spirv_source_generator;
-struct Parser_header_generator;
-struct Parser_source_generator;
-
-struct Generators
-{
-    static std::unique_ptr<Generator> make_spirv_header_generator();
-    static std::unique_ptr<Generator> make_spirv_source_generator();
-    static std::unique_ptr<Generator> make_parser_header_generator();
-    static std::unique_ptr<Generator> make_parser_source_generator();
-    static std::vector<std::unique_ptr<Generator>> make_all_generators();
-};
-}
-}
-}
-
-#endif /* GENERATE_SPIRV_PARSER_GENERATE_OLD_H_ */