working on refactoring generate_spirv_parser
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 4 Jul 2017 14:43:39 +0000 (07:43 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 4 Jul 2017 14:43:39 +0000 (07:43 -0700)
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h

index a537c2dae1346cadbb8ef7472d75466f5d8bd8a0..bbbbba272d04ebceadbac017d009565bd5846be7 100644 (file)
@@ -23,6 +23,7 @@
 #include "generate.h"
 #include "json/json.h"
 #include <fstream>
+#include <iostream>
 #include <cassert>
 #include <limits>
 #include <unordered_map>
@@ -291,115 +292,442 @@ struct Spirv_and_parser_generator : public Generator
 
 using namespace util::string_view_literals;
 
-struct Spirv_and_parser_generator::State
+namespace
 {
-private:
-    const ast::Top_level &top_level;
-    detail::Generated_output_stream spirv_h;
-    detail::Generated_output_stream spirv_cpp;
-    detail::Generated_output_stream parser_h;
-    detail::Generated_output_stream parser_cpp;
+enum class Output_part
+{
+    file_comments,
+    include_guard_start,
+    includes,
+    namespaces_start,
+    basic_types,
+    basic_constants,
+    id_types,
+    enum_definitions,
+    enum_properties_definitions,
+    literal_types,
+    namespaces_end,
+    include_guard_end
+};
 
-public:
-    State(const util::filesystem::path &output_directory, const ast::Top_level &top_level)
-        : top_level(top_level),
-          spirv_h(output_directory / "spirv.h"),
-          spirv_cpp(output_directory / "spirv.cpp"),
-          parser_h(output_directory / "parser.h"),
-          parser_cpp(output_directory / "parser.cpp")
-    {
-    }
+vulkan_cpu_util_generate_enum_traits(Output_part,
+                                     Output_part::file_comments,
+                                     Output_part::include_guard_start,
+                                     Output_part::includes,
+                                     Output_part::namespaces_start,
+                                     Output_part::basic_types,
+                                     Output_part::basic_constants,
+                                     Output_part::id_types,
+                                     Output_part::enum_definitions,
+                                     Output_part::enum_properties_definitions,
+                                     Output_part::literal_types,
+                                     Output_part::namespaces_end,
+                                     Output_part::include_guard_end);
+
+static_assert(util::Enum_traits<Output_part>::is_compact,
+              "mismatch between declaration and generate enum traits");
+}
 
+struct Spirv_and_parser_generator::State
+{
 private:
-    void write_file_comments()
+    struct Output_file_base
     {
-        constexpr auto automatically_generated_file_warning_comment =
-            R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */
+        util::Enum_map<Output_part, detail::Generated_output_stream Output_file_base::*>
+            output_parts;
+        template <typename Derived_class>
+        void register_output_part(Output_part part,
+                                  detail::Generated_output_stream Derived_class::*variable)
+        {
+            static_assert(std::is_base_of<Output_file_base, Derived_class>::value, "");
+            assert(dynamic_cast<Derived_class *>(this));
+            output_parts.insert_or_assign(
+                part, static_cast<detail::Generated_output_stream Output_file_base::*>(variable));
+        }
+        const util::filesystem::path file_path;
+        detail::Generated_output_stream file_comments;
+        detail::Generated_output_stream includes;
+        detail::Generated_output_stream namespaces_start;
+        detail::Generated_output_stream namespaces_end;
+        explicit Output_file_base(const util::filesystem::path &file_path)
+            : file_path(file_path),
+              file_comments(file_path),
+              includes(file_path),
+              namespaces_start(file_path),
+              namespaces_end(file_path)
+        {
+            register_output_part(Output_part::file_comments, &Output_file_base::file_comments);
+            register_output_part(Output_part::includes, &Output_file_base::includes);
+            register_output_part(Output_part::namespaces_start,
+                                 &Output_file_base::namespaces_start);
+            register_output_part(Output_part::namespaces_end, &Output_file_base::namespaces_end);
+        }
+        virtual void fill_output(State &state)
+        {
+            constexpr auto automatically_generated_file_warning_comment =
+                R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */
 )"_sv;
-        spirv_h << automatically_generated_file_warning_comment << top_level.copyright;
-        spirv_cpp << automatically_generated_file_warning_comment << top_level.copyright;
-        parser_h << automatically_generated_file_warning_comment << top_level.copyright;
-        parser_cpp << automatically_generated_file_warning_comment << top_level.copyright;
-    }
-    static void write_opening_inclusion_guard(detail::Generated_output_stream &os)
+            file_comments << automatically_generated_file_warning_comment
+                          << state.top_level.copyright;
+            namespaces_start << R"(
+namespace vulkan_cpu
+{
+namespace spirv
+{
+)";
+            namespaces_end << R"(}
+}
+)";
+        }
+        detail::Generated_output_stream get_whole_output() const
+        {
+            detail::Generated_output_stream retval(file_path);
+            for(auto &part : output_parts)
+                retval << this->*std::get<1>(part);
+            return retval;
+        }
+        virtual void write_to_file() const
+        {
+            get_whole_output().write_to_file();
+        }
+        void write_local_include_string(util::string_view header_file)
+        {
+            includes << R"(#include ")" << header_file << R"("
+)";
+        }
+        void write_local_include_path(util::filesystem::path header_file)
+        {
+            auto dir_path = file_path;
+            dir_path.remove_filename();
+            write_local_include_string(header_file.lexically_proximate(dir_path).generic_string());
+        }
+        void write_system_include(util::string_view header_file)
+        {
+            includes << R"(#include <)" << header_file << R"(>
+)";
+        }
+    };
+    struct Header_file_base : public Output_file_base
     {
-        using detail::guard_macro;
-        os << R"(#ifndef )" << guard_macro << R"(
-#define )" << guard_macro
-           << R"(
+        detail::Generated_output_stream include_guard_start;
+        detail::Generated_output_stream include_guard_end;
+        explicit Header_file_base(const util::filesystem::path &file_path)
+            : Output_file_base(file_path),
+              include_guard_start(file_path),
+              include_guard_end(file_path)
+        {
+            register_output_part(Output_part::include_guard_start,
+                                 &Header_file_base::include_guard_start);
+            register_output_part(Output_part::include_guard_end,
+                                 &Header_file_base::include_guard_end);
+        }
+        virtual void fill_output(State &state) override
+        {
+            using detail::guard_macro;
+            Output_file_base::fill_output(state);
+            include_guard_start << R"(#ifndef )" << guard_macro << R"(
+#define )" << guard_macro << R"(
 
 )";
-    }
-    static void write_closing_inclusion_guard(detail::Generated_output_stream &os)
-    {
-        using detail::guard_macro;
-        os << R"(
-#endif /* )"
-           << guard_macro << R"( */
+            include_guard_end << R"(
+#endif /* )" << guard_macro << R"( */
 )";
-    }
-    void write_opening_inclusion_guards()
-    {
-        write_opening_inclusion_guard(spirv_h);
-        write_opening_inclusion_guard(parser_h);
-    }
-    void write_closing_inclusion_guards()
+        }
+    };
+    struct Source_file_base : public Output_file_base
     {
-        write_closing_inclusion_guard(spirv_h);
-        write_closing_inclusion_guard(parser_h);
-    }
-    static void write_local_include(detail::Generated_output_stream &os, util::string_view file)
+        const Header_file_base *const header;
+        explicit Source_file_base(const util::filesystem::path &file_path,
+                                  const Header_file_base *header)
+            : Output_file_base(file_path), header(header)
+        {
+        }
+        virtual void fill_output(State &state) override
+        {
+            using detail::guard_macro;
+            Output_file_base::fill_output(state);
+            write_local_include_path(header->file_path);
+        }
+    };
+    struct Spirv_h : public Header_file_base
     {
-        os << R"(#include ")" << file << R"("
+        detail::Generated_output_stream basic_types;
+        detail::Generated_output_stream basic_constants;
+        detail::Generated_output_stream id_types;
+        detail::Generated_output_stream enum_definitions;
+        detail::Generated_output_stream enum_properties_definitions;
+        detail::Generated_output_stream literal_types;
+        explicit Spirv_h(const util::filesystem::path &file_path)
+            : Header_file_base(file_path),
+              basic_types(file_path),
+              basic_constants(file_path),
+              id_types(file_path),
+              enum_definitions(file_path),
+              enum_properties_definitions(file_path),
+              literal_types(file_path)
+        {
+            register_output_part(Output_part::basic_types, &Spirv_h::basic_types);
+            register_output_part(Output_part::basic_constants, &Spirv_h::basic_constants);
+            register_output_part(Output_part::id_types, &Spirv_h::id_types);
+            register_output_part(Output_part::enum_definitions, &Spirv_h::enum_definitions);
+            register_output_part(Output_part::enum_properties_definitions,
+                                 &Spirv_h::enum_properties_definitions);
+            register_output_part(Output_part::literal_types, &Spirv_h::literal_types);
+        }
+        void write_literal_kinds(State &state)
+        {
+            for(auto &operand_kind : state.top_level.operand_kinds.operand_kinds)
+            {
+                if(operand_kind.category != ast::Operand_kinds::Operand_kind::Category::literal)
+                    continue;
+                auto literal_kind =
+                    ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
+                        operand_kind.kind);
+                if(!literal_kind)
+                    throw Generate_error("unknown literal kind: " + operand_kind.kind);
+                auto underlying_type = "<<<<<Unknown>>>>>"_sv;
+                switch(*literal_kind)
+                {
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
+                    underlying_type = "std::uint64_t"_sv;
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
+                    // Literal_string is defined in write_basic_types
+                    continue;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::
+                    literal_context_dependent_number:
+                    underlying_type = "std::vector<Word>"_sv;
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
+                    underlying_type = "Word"_sv;
+                    break;
+                case ast::Operand_kinds::Operand_kind::Literal_kind::
+                    literal_spec_constant_op_integer:
+                    underlying_type = state.op_enumeration.value()->cpp_name;
+                    break;
+                }
+                auto &descriptor = state.literal_type_descriptors.at(*literal_kind);
+                literal_types << R"(
+typedef )" << underlying_type << " "
+                              << descriptor.cpp_name << R"(;
 )";
-    }
-    static void write_system_include(detail::Generated_output_stream &os, util::string_view file)
-    {
-        os << R"(#include <)" << file << R"(>
+            }
+        }
+        void write_basic_constants(State &state)
+        {
+            using detail::unsigned_integer;
+            basic_constants << R"(
+constexpr Word magic_number = 0x)"
+                            << unsigned_integer(state.top_level.magic_number, 0x10, 8) << R"(UL;
+constexpr std::uint32_t major_version = )"
+                            << unsigned_integer(state.top_level.major_version) << R"(UL;
+constexpr std::uint32_t minor_version = )"
+                            << unsigned_integer(state.top_level.minor_version) << R"(UL;
+constexpr std::uint32_t revision = )"
+                            << unsigned_integer(state.top_level.revision) << R"(UL;
 )";
-    }
-    void write_includes()
-    {
-        write_local_include(spirv_cpp, spirv_h.get_file_path().filename().string());
-        write_local_include(parser_h, spirv_h.get_file_path().filename().string());
-        write_local_include(parser_cpp, parser_h.get_file_path().filename().string());
-        write_system_include(spirv_h, "cstdint");
-        write_system_include(spirv_h, "vector");
-        write_system_include(spirv_h, "string");
-        write_system_include(spirv_h, "iterator");
-        write_local_include(spirv_h, "util/string_view.h");
-        write_local_include(spirv_h, "util/enum.h");
-        write_local_include(spirv_h, "spirv/word.h");
-        write_local_include(spirv_h, "spirv/literal_string.h");
-    }
-    static void write_opening_namespaces(detail::Generated_output_stream &os)
-    {
-        os << R"(
-namespace vulkan_cpu
+            for(auto &instruction_set : state.top_level.extension_instruction_sets)
+            {
+                basic_constants << R"(
+constexpr std::uint32_t )" << instruction_set_version_name(instruction_set)
+                                << R"( = )" << unsigned_integer(instruction_set.version) << R"(UL;
+constexpr std::uint32_t )" << instruction_set_revision_name(instruction_set)
+                                << R"( = )" << unsigned_integer(instruction_set.revision) << R"(UL;
+)";
+            }
+        }
+        void write_enums(State &state)
+        {
+            using detail::unsigned_integer;
+            for(auto &enumeration : state.enumerations_list)
+            {
+                enum_definitions << R"(
+enum class )" << enumeration.cpp_name
+                                 << R"( : Word
 {
-namespace spirv
+@+)";
+                enum_properties_definitions << R"(
+constexpr util::string_view get_enumerant_name()"
+                                            << enumeration.cpp_name << R"( v) noexcept
 {
+    using namespace util::string_view_literals;
+    switch(v)
+    {
+@+@+)";
+                for(auto &enumerant : enumeration.enumerants)
+                {
+                    enum_definitions << enumerant.cpp_name << " = ";
+                    if(enumeration.is_bitwise)
+                        enum_definitions << "0x" << unsigned_integer(enumerant.value, 0x10) << "UL";
+                    else
+                        enum_definitions << unsigned_integer(enumerant.value, 10) << "UL";
+                    enum_definitions << ",\n";
+                }
+                enum_definitions << R"(@-};
+
+vulkan_cpu_util_generate_enum_traits()"
+                                 << enumeration.cpp_name;
+                std::unordered_set<std::uint32_t> values;
+                for(auto &enumerant : enumeration.enumerants)
+                {
+                    enum_definitions << R"(,
+`````````````````````````````````````)"
+                                     << enumeration.cpp_name << "::" << enumerant.cpp_name;
+                    if(std::get<1>(values.insert(enumerant.value)))
+                    {
+                        enum_properties_definitions << "case " << enumeration.cpp_name
+                                                    << "::" << enumerant.cpp_name << R"(:
+    return ")" << enumerant.json_name << R"("_sv;
 )";
-    }
-    void write_opening_namespaces()
+                    }
+                }
+                enum_definitions << R"();
+)";
+                enum_properties_definitions << R"(@-@_}
+    return ""_sv;
+}
+
+constexpr util::Enum_set<)" << state.capability_enumeration.value()->cpp_name
+                                            << R"(> get_directly_required_capabilities()"
+                                            << enumeration.cpp_name << R"( v) noexcept
+{
+    switch(v)
     {
-        write_opening_namespaces(spirv_h);
-        write_opening_namespaces(spirv_cpp);
-        write_opening_namespaces(parser_h);
-        write_opening_namespaces(parser_cpp);
-    }
-    static void write_closing_namespaces(detail::Generated_output_stream &os)
+@+@+)";
+                values.clear();
+                for(auto &enumerant : enumeration.enumerants)
+                {
+                    if(std::get<1>(values.insert(enumerant.value)))
+                    {
+                        enum_properties_definitions << "case " << enumeration.cpp_name
+                                                    << "::" << enumerant.cpp_name << R"(:
+    return {)";
+                        auto separator = ""_sv;
+                        for(auto &capability : enumerant.capabilities.capabilities)
+                        {
+                            enum_properties_definitions << separator;
+                            separator = ", "_sv;
+                            enum_properties_definitions
+                                << state.capability_enumeration.value()->cpp_name
+                                << "::" << state.get_capability(capability).cpp_name;
+                        }
+                        enum_properties_definitions << R"(};
+)";
+                    }
+                }
+                enum_properties_definitions << R"(@-@_}
+    return {};
+}
+
+constexpr util::Enum_set<)" << state.extension_enumeration.value()->cpp_name
+                                            << R"(> get_directly_required_extensions()"
+                                            << enumeration.cpp_name << R"( v) noexcept
+{
+    switch(v)
     {
-        os << R"(}
+@+@+)";
+                values.clear();
+                for(auto &enumerant : enumeration.enumerants)
+                {
+                    if(std::get<1>(values.insert(enumerant.value)))
+                    {
+                        enum_properties_definitions << "case " << enumeration.cpp_name
+                                                    << "::" << enumerant.cpp_name << R"(:
+    return {)";
+                        auto separator = ""_sv;
+                        for(auto &extension : enumerant.extensions.extensions)
+                        {
+                            enum_properties_definitions << separator;
+                            separator = ", "_sv;
+                            enum_properties_definitions
+                                << state.extension_enumeration.value()->cpp_name
+                                << "::" << state.get_extension(extension).cpp_name;
+                        }
+                        enum_properties_definitions << R"(};
+)";
+                    }
+                }
+                enum_properties_definitions << R"(@-@_}
+    return {};
 }
 )";
-    }
-    void write_closing_namespaces()
+            }
+#warning add writing enum parameters
+        }
+        void write_id_types(State &state)
+        {
+            id_types << "\n";
+            for(auto &id_type : state.id_type_list)
+            {
+                id_types << "typedef Id " << id_type.cpp_name
+                         << R"(;
+)";
+            }
+        }
+        virtual void fill_output(State &state) override
+        {
+            Header_file_base::fill_output(state);
+            write_system_include("cstdint");
+            write_system_include("vector");
+            write_system_include("string");
+            write_system_include("iterator");
+            write_local_include_string("util/string_view.h");
+            write_local_include_string("util/enum.h");
+            write_local_include_string("spirv/word.h");
+            write_local_include_string("spirv/literal_string.h");
+            basic_types << R"(typedef Word Id;
+)";
+#warning finish
+            include_guard_start << R"(#error generator not finished being implemented
+
+)";
+            write_literal_kinds(state);
+            write_basic_constants(state);
+            write_enums(state);
+            write_id_types(state);
+        }
+    };
+    struct Spirv_cpp : public Source_file_base
+    {
+        explicit Spirv_cpp(const util::filesystem::path &file_path, const Spirv_h *header)
+            : Source_file_base(file_path, header)
+        {
+        }
+    };
+    struct Parser_h : public Header_file_base
+    {
+        explicit Parser_h(const util::filesystem::path &file_path) : Header_file_base(file_path)
+        {
+        }
+        virtual void fill_output(State &state) override
+        {
+            Header_file_base::fill_output(state);
+            write_local_include_path(state.spirv_h.file_path);
+        }
+    };
+    struct Parser_cpp : public Source_file_base
+    {
+        explicit Parser_cpp(const util::filesystem::path &file_path, const Parser_h *header)
+            : Source_file_base(file_path, header)
+        {
+        }
+    };
+
+private:
+    const ast::Top_level &top_level;
+    Spirv_h spirv_h;
+    Spirv_cpp spirv_cpp;
+    Parser_h parser_h;
+    Parser_cpp parser_cpp;
+
+public:
+    State(const util::filesystem::path &output_directory, const ast::Top_level &top_level)
+        : top_level(top_level),
+          spirv_h(output_directory / "spirv.h"),
+          spirv_cpp(output_directory / "spirv.cpp", &spirv_h),
+          parser_h(output_directory / "parser.h"),
+          parser_cpp(output_directory / "parser.cpp", &parser_h)
     {
-        write_closing_namespaces(spirv_h);
-        write_closing_namespaces(spirv_cpp);
-        write_closing_namespaces(parser_h);
-        write_closing_namespaces(parser_cpp);
     }
 
 private:
@@ -606,11 +934,6 @@ private:
         if(!capability_enumeration)
             throw Generate_error("missing " + std::string(capability_enum_json_name) + " enum");
     }
-    void write_basic_types()
-    {
-        spirv_h << R"(typedef Word Id;
-)";
-    }
     static std::string instruction_set_version_name(const ast::Extension_instruction_set &v)
     {
         using detail::name_from_words_all_lowercase;
@@ -621,68 +944,6 @@ private:
         using detail::name_from_words_all_lowercase;
         return name_from_words_all_lowercase("revision"_sv, v.import_name).to_string();
     }
-    void write_basic_constants()
-    {
-        using detail::unsigned_integer;
-        spirv_h << R"(
-constexpr Word magic_number = 0x)"
-                << unsigned_integer(top_level.magic_number, 0x10, 8) << R"(UL;
-constexpr std::uint32_t major_version = )"
-                << unsigned_integer(top_level.major_version) << R"(UL;
-constexpr std::uint32_t minor_version = )"
-                << unsigned_integer(top_level.minor_version) << R"(UL;
-constexpr std::uint32_t revision = )"
-                << unsigned_integer(top_level.revision) << R"(UL;
-)";
-        for(auto &instruction_set : top_level.extension_instruction_sets)
-        {
-            spirv_h << R"(
-constexpr std::uint32_t )"
-                    << instruction_set_version_name(instruction_set) << R"( = )"
-                    << unsigned_integer(instruction_set.version) << R"(UL;
-constexpr std::uint32_t )"
-                    << instruction_set_revision_name(instruction_set) << R"( = )"
-                    << unsigned_integer(instruction_set.revision) << R"(UL;
-)";
-        }
-    }
-    void write_enum_declarations()
-    {
-        spirv_h << "\n";
-        for(auto &enumeration : enumerations_list)
-            spirv_h << "enum class " << enumeration.cpp_name << " : Word;\n";
-    }
-    void write_enum_definitions()
-    {
-        using detail::unsigned_integer;
-        for(auto &enumeration : enumerations_list)
-        {
-            spirv_h << R"(
-enum class )" << enumeration.cpp_name
-                    << R"( : Word
-{
-@+)";
-            for(auto &enumerant : enumeration.enumerants)
-            {
-                spirv_h << enumerant.cpp_name << " = ";
-                if(enumeration.is_bitwise)
-                    spirv_h << "0x" << unsigned_integer(enumerant.value, 0x10) << "UL";
-                else
-                    spirv_h << unsigned_integer(enumerant.value, 10) << "UL";
-                spirv_h << ",\n";
-            }
-            spirv_h << R"(@-};
-
-vulkan_cpu_util_generate_enum_traits()"
-                    << enumeration.cpp_name;
-            for(auto &enumerant : enumeration.enumerants)
-                spirv_h << R"(,
-`````````````````````````````````````)"
-                        << enumeration.cpp_name << "::" << enumerant.cpp_name;
-            spirv_h << R"();
-)";
-        }
-    }
     const Enumerant_descriptor &get_capability(const std::string &capability)
     {
         auto &enumerant_map = capability_enumeration.value()->json_name_to_enumerant_map;
@@ -699,97 +960,6 @@ vulkan_cpu_util_generate_enum_traits()"
             throw Generate_error("unknown extension: " + extension);
         return *std::get<1>(*iter);
     }
-    void write_enum_properties_definitions()
-    {
-        for(auto &enumeration : enumerations_list)
-        {
-            spirv_h << R"(
-constexpr util::string_view get_enumerant_name()"
-                    << enumeration.cpp_name << R"( v) noexcept
-{
-    using namespace util::string_view_literals;
-    switch(v)
-    {
-@+@+)";
-            std::unordered_set<std::uint32_t> values;
-            for(auto &enumerant : enumeration.enumerants)
-            {
-                if(std::get<1>(values.insert(enumerant.value)))
-                {
-                    spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
-    return ")" << enumerant.json_name
-                            << R"("_sv;
-)";
-                }
-            }
-            spirv_h << R"(@-@_}
-    return ""_sv;
-}
-
-constexpr util::Enum_set<)"
-                    << capability_enumeration.value()->cpp_name
-                    << R"(> get_directly_required_capabilities()" << enumeration.cpp_name
-                    << R"( v) noexcept
-{
-    switch(v)
-    {
-@+@+)";
-            values.clear();
-            for(auto &enumerant : enumeration.enumerants)
-            {
-                if(std::get<1>(values.insert(enumerant.value)))
-                {
-                    spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
-    return {)";
-                    auto separator = ""_sv;
-                    for(auto &capability : enumerant.capabilities.capabilities)
-                    {
-                        spirv_h << separator;
-                        separator = ", "_sv;
-                        spirv_h << capability_enumeration.value()->cpp_name
-                                << "::" << get_capability(capability).cpp_name;
-                    }
-                    spirv_h << R"(};
-)";
-                }
-            }
-            spirv_h << R"(@-@_}
-    return {};
-}
-
-constexpr util::Enum_set<)"
-                    << extension_enumeration.value()->cpp_name
-                    << R"(> get_directly_required_extensions()" << enumeration.cpp_name
-                    << R"( v) noexcept
-{
-    switch(v)
-    {
-@+@+)";
-            values.clear();
-            for(auto &enumerant : enumeration.enumerants)
-            {
-                if(std::get<1>(values.insert(enumerant.value)))
-                {
-                    spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
-    return {)";
-                    auto separator = ""_sv;
-                    for(auto &extension : enumerant.extensions.extensions)
-                    {
-                        spirv_h << separator;
-                        separator = ", "_sv;
-                        spirv_h << extension_enumeration.value()->cpp_name
-                                << "::" << get_extension(extension).cpp_name;
-                    }
-                    spirv_h << R"(};
-)";
-                }
-            }
-            spirv_h << R"(@-@_}
-    return {};
-}
-)";
-        }
-    }
 
 private:
     struct Literal_type_descriptor
@@ -812,8 +982,8 @@ private:
     };
 
 private:
-    util::Enum_map<ast::Operand_kinds::Operand_kind::Literal_kind,
-                       Literal_type_descriptor> literal_type_descriptors;
+    util::Enum_map<ast::Operand_kinds::Operand_kind::Literal_kind, Literal_type_descriptor>
+        literal_type_descriptors;
 
 private:
     void fill_literal_type_descriptors()
@@ -824,40 +994,167 @@ private:
             literal_type_descriptors.emplace(literal_kind, Literal_type_descriptor(literal_kind));
         }
     }
-    void write_literal_kinds()
+    static ast::Operand_kinds::Operand_kind::Literal_kind get_literal_kind(
+        util::string_view json_name)
+    {
+        auto retval = ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(json_name);
+        if(!retval)
+            throw Generate_error("unknown literal kind: " + std::string(json_name));
+        return *retval;
+    }
+
+private:
+    struct Id_type_descriptor
+    {
+        std::string cpp_name;
+        std::string json_name;
+        static std::string get_cpp_name(util::string_view json_name)
+        {
+            using detail::name_from_words_initial_capital;
+            return name_from_words_initial_capital(json_name).to_string();
+        }
+        explicit Id_type_descriptor(std::string json_name)
+            : cpp_name(get_cpp_name(json_name)), json_name(std::move(json_name))
+        {
+        }
+    };
+
+private:
+    std::list<Id_type_descriptor> id_type_list;
+    std::unordered_map<std::string, std::list<Id_type_descriptor>::const_iterator> id_type_map;
+
+private:
+    std::list<Id_type_descriptor>::const_iterator add_id_type_descriptor(
+        Id_type_descriptor &&id_type_descriptor)
+    {
+        auto name = id_type_descriptor.json_name;
+        auto iter = id_type_list.insert(id_type_list.end(), std::move(id_type_descriptor));
+        if(!std::get<1>(id_type_map.emplace(name, iter)))
+            throw Generate_error("duplicate id type: " + name);
+        return iter;
+    }
+    void fill_id_type_descriptors()
     {
         for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
         {
-            if(operand_kind.category != ast::Operand_kinds::Operand_kind::Category::literal)
+            if(operand_kind.category != ast::Operand_kinds::Operand_kind::Category::id)
                 continue;
-            auto literal_kind = ast::Operand_kinds::Operand_kind::get_literal_kind_from_json_name(
-                operand_kind.kind);
-            if(!literal_kind)
-                throw Generate_error("unknown literal kind: " + operand_kind.kind);
-            auto underlying_type = "<<<<<Unknown>>>>>"_sv;
-            switch(*literal_kind)
+            add_id_type_descriptor(Id_type_descriptor(operand_kind.kind));
+        }
+    }
+    std::list<Id_type_descriptor>::const_iterator get_id_type(const std::string &json_name)
+    {
+        auto iter = id_type_map.find(json_name);
+        if(iter == id_type_map.end())
+            throw Generate_error("unknown id type: " + json_name);
+        return std::get<1>(*iter);
+    }
+
+private:
+    struct Operand_kind_descriptor
+    {
+        std::string json_name;
+        util::variant<util::monostate,
+                      std::list<Enumeration_descriptor>::const_iterator,
+                      std::list<Id_type_descriptor>::const_iterator,
+                      ast::Operand_kinds::Operand_kind::Literal_kind> value;
+        std::string make_cpp_name() const
+        {
+            std::string retval;
+            struct Visitor
             {
-            case ast::Operand_kinds::Operand_kind::Literal_kind::literal_integer:
-                underlying_type = "std::uint64_t"_sv;
-                break;
-            case ast::Operand_kinds::Operand_kind::Literal_kind::literal_string:
-                // Literal_string is defined in write_basic_types
+                std::string &retval;
+                const std::string &json_name;
+                void operator()(util::monostate)
+                {
+                    retval = detail::name_from_words_initial_capital(json_name).to_string();
+                }
+                void operator()(std::list<Enumeration_descriptor>::const_iterator iter)
+                {
+                    retval = iter->cpp_name;
+                }
+                void operator()(std::list<Id_type_descriptor>::const_iterator iter)
+                {
+                    retval = iter->cpp_name;
+                }
+                void operator()(ast::Operand_kinds::Operand_kind::Literal_kind literal_kind)
+                {
+                    retval = Literal_type_descriptor::get_cpp_name(literal_kind);
+                }
+            };
+            util::visit(Visitor{retval, json_name}, value);
+            return retval;
+        }
+        std::string make_cpp_name_with_parameters() const
+        {
+            auto *iter = util::get_if<std::list<Enumeration_descriptor>::const_iterator>(&value);
+            if(iter)
+            {
+                bool need_parameters = false;
+#warning finish
+                if(need_parameters)
+                    return detail::name_from_words_initial_capital(json_name, "with parameters"_sv)
+                        .to_string();
+            }
+            return cpp_name;
+        }
+        std::string cpp_name;
+        std::string cpp_name_with_parameters;
+        explicit Operand_kind_descriptor(std::string json_name)
+            : Operand_kind_descriptor(std::move(json_name), util::monostate{})
+        {
+        }
+        template <typename T>
+        Operand_kind_descriptor(std::string json_name, T arg)
+            : json_name(std::move(json_name)),
+              value(std::move(arg)),
+              cpp_name(make_cpp_name()),
+              cpp_name_with_parameters(make_cpp_name_with_parameters())
+        {
+        }
+    };
+
+private:
+    std::list<Operand_kind_descriptor> operand_kind_list;
+    std::unordered_map<std::string, std::list<Operand_kind_descriptor>::const_iterator>
+        operand_kind_map;
+
+private:
+    std::list<Operand_kind_descriptor>::const_iterator add_operand_kind(
+        Operand_kind_descriptor &&operand_kind_descriptor)
+    {
+        auto name = operand_kind_descriptor.json_name;
+        auto iter =
+            operand_kind_list.insert(operand_kind_list.end(), std::move(operand_kind_descriptor));
+        if(!std::get<1>(operand_kind_map.emplace(name, iter)))
+            throw Generate_error("duplicate operand kind: " + name);
+        return iter;
+    }
+    void fill_operand_kinds()
+    {
+        for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+        {
+            switch(operand_kind.category)
+            {
+            case ast::Operand_kinds::Operand_kind::Category::bit_enum:
+            case ast::Operand_kinds::Operand_kind::Category::value_enum:
+                add_operand_kind(Operand_kind_descriptor(operand_kind.kind,
+                                                         enumerations_map.at(operand_kind.kind)));
+                continue;
+            case ast::Operand_kinds::Operand_kind::Category::id:
+                add_operand_kind(Operand_kind_descriptor(operand_kind.kind,
+                                                         id_type_map.at(operand_kind.kind)));
+                continue;
+            case ast::Operand_kinds::Operand_kind::Category::literal:
+                add_operand_kind(Operand_kind_descriptor(operand_kind.kind,
+                                                         get_literal_kind(operand_kind.kind)));
+                continue;
+            case ast::Operand_kinds::Operand_kind::Category::composite:
+#warning finish
+                add_operand_kind(Operand_kind_descriptor(operand_kind.kind));
                 continue;
-            case ast::Operand_kinds::Operand_kind::Literal_kind::literal_context_dependent_number:
-                underlying_type = "std::vector<Word>"_sv;
-                break;
-            case ast::Operand_kinds::Operand_kind::Literal_kind::literal_ext_inst_integer:
-                underlying_type = "Word"_sv;
-                break;
-            case ast::Operand_kinds::Operand_kind::Literal_kind::literal_spec_constant_op_integer:
-                underlying_type = op_enumeration.value()->cpp_name;
-                break;
             }
-            auto &descriptor = literal_type_descriptors.at(*literal_kind);
-            spirv_h << R"(
-typedef )" << underlying_type
-                    << " " << descriptor.cpp_name << R"(;
-)";
+            assert(false);
         }
     }
 
@@ -866,26 +1163,14 @@ public:
     {
         fill_literal_type_descriptors();
         fill_enumerations();
-        write_file_comments();
-        write_opening_inclusion_guards();
-#warning finish
-        spirv_h << R"(#error generator not finished being implemented
-
-)";
-        write_includes();
-        write_opening_namespaces();
-        write_basic_types();
-        write_basic_constants();
-        write_enum_declarations();
-        write_enum_definitions();
-        write_enum_properties_definitions();
-        write_literal_kinds();
-        write_closing_namespaces();
-        write_closing_inclusion_guards();
-        spirv_h.write_to_file();
-        spirv_cpp.write_to_file();
-        parser_h.write_to_file();
-        parser_cpp.write_to_file();
+        fill_id_type_descriptors();
+        fill_operand_kinds();
+        for(auto *file :
+            std::initializer_list<Output_file_base *>{&spirv_h, &spirv_cpp, &parser_h, &parser_cpp})
+            file->fill_output(*this);
+        for(auto *file :
+            std::initializer_list<Output_file_base *>{&spirv_h, &spirv_cpp, &parser_h, &parser_cpp})
+            file->write_to_file();
     }
 };
 
index 34aa3dcbfdde13be4c19a355ebabe27a221ed569..453b72df1c4c8ff50edb38f17495eb243caba6f4 100644 (file)
 #include "util/filesystem.h"
 #include "util/string_view.h"
 #include "word_iterator.h"
+#include "util/enum.h"
 #include <stdexcept>
 #include <deque>
 #include <cstdint>
 #include <string>
 #include <utility>
+#include <cassert>
 
 namespace vulkan_cpu
 {
@@ -212,6 +214,12 @@ public:
         value.push_back(ch);
         return *this;
     }
+    Generated_output_stream &operator<<(const Generated_output_stream &s)
+    {
+        assert(this != &s);
+        value.insert(value.end(), s.value.begin(), s.value.end());
+        return *this;
+    }
     Generated_output_stream &operator<<(util::string_view sv)
     {
         for(char ch : sv)
@@ -396,12 +404,10 @@ public:
     }
     template <typename... Args>
     static constexpr Name_from_words_holder<sizeof...(Args)>
-        name_from_words(Name_format name_format, Args &&... args) noexcept(
-            noexcept(Name_from_words_holder<sizeof...(Args)>(name_format,
-                                                             std::forward<Args>(args)...)))
+        name_from_words(Name_format name_format, Args &&... args) noexcept(noexcept(
+            Name_from_words_holder<sizeof...(Args)>(name_format, std::forward<Args>(args)...)))
     {
-        return Name_from_words_holder<sizeof...(Args)>(name_format,
-                                                       std::forward<Args>(args)...);
+        return Name_from_words_holder<sizeof...(Args)>(name_format, std::forward<Args>(args)...);
     }
 };
 
@@ -438,38 +444,51 @@ constexpr auto signed_integer(std::int64_t value, unsigned base) noexcept
 constexpr Generated_output_stream::Guard_macro guard_macro{};
 
 template <typename... Args>
-constexpr auto name_from_words(Generated_output_stream::Name_format name_format, Args &&... args) noexcept(
-    noexcept(Generated_output_stream::name_from_words(name_format, std::forward<Args>(args)...)))
+constexpr auto name_from_words(
+    Generated_output_stream::Name_format name_format,
+    Args &&... args) noexcept(noexcept(Generated_output_stream::name_from_words(name_format,
+                                                                                std::forward<Args>(
+                                                                                    args)...)))
 {
     return Generated_output_stream::name_from_words(name_format, std::forward<Args>(args)...);
 }
 
 template <typename... Args>
 constexpr auto name_from_words_all_lowercase(Args &&... args) noexcept(
-    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase, std::forward<Args>(args)...)))
+    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase,
+                                                      std::forward<Args>(args)...)))
 {
-    return Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase, std::forward<Args>(args)...);
+    return Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase,
+                                                    std::forward<Args>(args)...);
 }
 
 template <typename... Args>
 constexpr auto name_from_words_all_uppercase(Args &&... args) noexcept(
-    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase, std::forward<Args>(args)...)))
+    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase,
+                                                      std::forward<Args>(args)...)))
 {
-    return Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase, std::forward<Args>(args)...);
+    return Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase,
+                                                    std::forward<Args>(args)...);
 }
 
 template <typename... Args>
 constexpr auto name_from_words_initial_capital(Args &&... args) noexcept(
-    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::initial_capital, std::forward<Args>(args)...)))
+    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::initial_capital,
+                                                      std::forward<Args>(args)...)))
 {
-    return Generated_output_stream::name_from_words(Generated_output_stream::initial_capital, std::forward<Args>(args)...);
+    return Generated_output_stream::name_from_words(Generated_output_stream::initial_capital,
+                                                    std::forward<Args>(args)...);
 }
 
 template <typename... Args>
 constexpr auto name_from_words_all_uppercase_with_trailing_underline(Args &&... args) noexcept(
-    noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase_with_trailing_underline, std::forward<Args>(args)...)))
+    noexcept(Generated_output_stream::name_from_words(
+        Generated_output_stream::all_uppercase_with_trailing_underline,
+        std::forward<Args>(args)...)))
 {
-    return Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase_with_trailing_underline, std::forward<Args>(args)...);
+    return Generated_output_stream::name_from_words(
+        Generated_output_stream::all_uppercase_with_trailing_underline,
+        std::forward<Args>(args)...);
 }
 }