code to generate spirv.h is pretty much complete
authorJacob Lifshay <programmerjake@gmail.com>
Sat, 17 Jun 2017 00:33:33 +0000 (17:33 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Sat, 17 Jun 2017 00:33:33 +0000 (17:33 -0700)
.gitignore
src/generate_spirv_parser/ast.cpp
src/generate_spirv_parser/ast.h
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h
src/generate_spirv_parser/generate_spirv_parser.cpp
src/generate_spirv_parser/parser.cpp

index 11f41bafdede133e2e3402f51952461f781b7534..2244dde3e48aa82997cbdbb958d3251242533556 100644 (file)
@@ -6,3 +6,4 @@ Makefile
 /.settings/
 /test-files/test.spv
 out.json
+compile_commands.json
index 9e14428fa8c3cf67f4d0579a3e2ce7d1a6d8dccc..12dc6f104b9934a7af1251168e67737decd032a9 100644 (file)
@@ -83,6 +83,8 @@ json::ast::Value Instructions::Instruction::to_json() const
         retval.values["operands"] = operands.to_json();
     if(!capabilities.empty())
         retval.values["capabilities"] = capabilities.to_json();
+    if(!extensions.empty())
+        retval.values["extensions"] = extensions.to_json();
     return json::ast::Value(make_empty_location(), std::move(retval));
 }
 
index 81e650ee3068047d49c4189846327f37d3979a32..0d1a1c941680dd251be420ca6e9f59a8023f8da9 100644 (file)
@@ -164,13 +164,16 @@ struct Instructions
         std::uint32_t opcode;
         Operands operands;
         Capabilities capabilities;
+        Extensions extensions;
         Instruction(std::string opname,
                     std::uint32_t opcode,
                     Operands operands,
-                    Capabilities capabilities) noexcept : opname(std::move(opname)),
-                                                          opcode(opcode),
-                                                          operands(std::move(operands)),
-                                                          capabilities(std::move(capabilities))
+                    Capabilities capabilities,
+                    Extensions extensions) noexcept : opname(std::move(opname)),
+                                                      opcode(opcode),
+                                                      operands(std::move(operands)),
+                                                      capabilities(std::move(capabilities)),
+                                                      extensions(std::move(extensions))
         {
         }
         json::ast::Value to_json() const;
@@ -180,6 +183,7 @@ struct Instructions
             fn(*this);
             operands.visit(fn);
             capabilities.visit(fn);
+            extensions.visit(fn);
         }
     };
     std::vector<Instruction> instructions;
@@ -203,11 +207,13 @@ struct Operand_kinds
     {
         enum class Category
         {
-            bit_enum,
+            bit_enum, // enum categories must be first
             value_enum,
+
             id,
             literal,
-            composite,
+
+            composite, // composite must be last
         };
         Category category;
         static constexpr const char *get_json_name_from_category(Category category) noexcept
index 115e2372deff73f4dee3d7228271512049fa202b..85e3968c6b93b21ee40e8fba0d42ee0fd71c64b8 100644 (file)
  *
  */
 #include "generate.h"
-#include "../json/json.h"
+#include "json/json.h"
+#include "util/string_view.h"
+#include "util/optional.h"
 #include <limits>
 #include <algorithm>
+#include <cstdlib>
+#include <iostream>
 
 namespace vulkan_cpu
 {
@@ -54,6 +58,7 @@ 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)
 {
@@ -92,30 +97,79 @@ std::string Generator::get_guard_macro_name_from_file_name(std::string file_name
 
 namespace
 {
-constexpr bool is_identifier_start(char ch) noexcept
+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 ch == '_';
+    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;
+}
+
+constexpr bool is_identifier_continue(char ch) noexcept
+{
+    return is_identifier_start(ch) || is_digit(ch);
 }
 }
 
 std::string Generator::get_enumerant_name(const char *enumeration_name,
                                           std::size_t enumeration_name_size,
-                                          std::string enumerant_name)
-{
-    bool need_prefix;
-    if(enumerant_name.compare(0, enumeration_name_size, enumeration_name, enumeration_name_size)
-       == 0)
-        need_prefix = true; // ensure that we don't end up with name collisions
-    else if(enumerant_name.empty())
-        need_prefix = true; // return something other than the empty string
+                                          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
-        need_prefix = !is_identifier_start(enumerant_name[0]);
-    if(need_prefix)
-        return std::move(enumerant_name.insert(0, enumeration_name, enumeration_name_size));
+    {
+        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;
 }
 
@@ -260,7 +314,7 @@ void Generator::write_capabilities_set(Generator_state &state,
     for(auto &capability : capabilities.capabilities)
     {
         state << separator << capability_enum_name
-              << "::" << get_enumerant_name(capability_enum_name, capability);
+              << "::" << get_enumerant_name(capability_enum_name, capability, false);
         separator = ", ";
     }
     state << "}";
@@ -273,12 +327,204 @@ void Generator::write_extensions_set(Generator_state &state, const ast::Extensio
     for(auto &extension : extensions.extensions)
     {
         state << separator << extension_enum_name
-              << "::" << get_enumerant_name(extension_enum_name, extension);
+              << "::" << get_enumerant_name(extension_enum_name, extension, false);
         separator = ", ";
     }
     state << "}";
 }
 
+std::string Generator::get_member_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
+    }
+    return retval;
+}
+
+#if 0
+#warning testing Generator::get_member_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_member_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_member_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_member_name_from_words(operand.kind.substr(id_str.size()));
+    return get_member_name_from_words(operand.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 << "{\n";
+    state << indent << "}\n";
+    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 << "{\n";
+        state << indent << "}\n";
+    }
+}
+
 struct Spirv_header_generator final : public Generator
 {
     Spirv_header_generator() : Generator("spirv.h")
@@ -305,6 +551,20 @@ struct Spirv_header_generator final : public Generator
             return false;
         return l < r;
     }
+    static bool compare_operand_kinds(const ast::Operand_kinds::Operand_kind &l,
+                                      const ast::Operand_kinds::Operand_kind &r)
+    {
+        // treat both enum categories as equivalent
+        auto l_category = l.category == ast::Operand_kinds::Operand_kind::Category::bit_enum ?
+                              ast::Operand_kinds::Operand_kind::Category::value_enum :
+                              l.category;
+        auto r_category = r.category == ast::Operand_kinds::Operand_kind::Category::bit_enum ?
+                              ast::Operand_kinds::Operand_kind::Category::value_enum :
+                              r.category;
+        if(l_category != r_category)
+            return l_category < r_category;
+        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);
@@ -312,10 +572,13 @@ struct Spirv_header_generator final : public Generator
         write_file_comments(state, top_level.copyright);
         write_file_guard_start(state);
         state << "#include <cstdint>\n"
-                 "#include \"util/enum.h\"\n";
+                 "#include \"util/enum.h\"\n"
+                 "#include \"util/optional.h\"\n"
+                 "#include <vector>\n";
         state << "\n";
         write_namespaces_start(state, spirv_namespace_names);
         state << "typedef std::uint32_t Word;\n";
+        state << "typedef Word Id;\n";
         state << "constexpr Word magic_number = "
               << unsigned_hex_integer_literal(top_level.magic_number, 8) << ";\n";
         state << "constexpr std::uint32_t major_version = "
@@ -337,7 +600,8 @@ struct Spirv_header_generator final : public Generator
         {
             auto push_indent = state.pushed_indent();
             for(auto &extension : extensions_list)
-                state << indent << get_enumerant_name(extension_enum_name, extension) << ",\n";
+                state << indent << get_enumerant_name(extension_enum_name, extension, false)
+                      << ",\n";
         }
         state << "};\n"
                  "\n"
@@ -347,7 +611,7 @@ struct Spirv_header_generator final : public Generator
             auto push_indent = state.pushed_indent();
             for(auto &extension : extensions_list)
                 state << ",\n" << indent << extension_enum_name
-                      << "::" << get_enumerant_name(extension_enum_name, extension);
+                      << "::" << get_enumerant_name(extension_enum_name, extension, false);
             state << ");\n";
         }
         state << "\n"
@@ -360,7 +624,7 @@ struct Spirv_header_generator final : public Generator
             for(auto &extension : extensions_list)
             {
                 state << indent << "case " << extension_enum_name
-                      << "::" << get_enumerant_name(extension_enum_name, extension) << ":\n";
+                      << "::" << get_enumerant_name(extension_enum_name, extension, false) << ":\n";
                 auto push_indent2 = state.pushed_indent();
                 state << indent << "return \"" << extension << "\";\n";
             }
@@ -376,12 +640,14 @@ struct Spirv_header_generator final : public Generator
             operand_kinds.end(),
             [](const ast::Operand_kinds::Operand_kind *a, const ast::Operand_kinds::Operand_kind *b)
             {
-                return compare_enum_names(a->kind, b->kind);
+                return compare_operand_kinds(*a, *b);
             });
         for(auto *operand_kind : operand_kinds)
         {
-            if(util::holds_alternative<ast::Operand_kinds::Operand_kind::Enumerants>(
-                   operand_kind->value))
+            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;
@@ -396,7 +662,7 @@ struct Spirv_header_generator final : public Generator
                     for(auto &enumerant : enumerants.enumerants)
                     {
                         state << indent
-                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
                               << " = ";
                         if(is_bit_enum)
                             state << unsigned_hex_integer_literal(enumerant.value);
@@ -414,8 +680,9 @@ struct Spirv_header_generator final : public Generator
                     {
                         auto push_indent = state.pushed_indent();
                         for(auto &enumerant : enumerants.enumerants)
-                            state << ",\n" << indent << operand_kind->kind << "::"
-                                  << get_enumerant_name(operand_kind->kind, enumerant.enumerant);
+                            state << ",\n" << indent << operand_kind->kind
+                                  << "::" << get_enumerant_name(
+                                                 operand_kind->kind, enumerant.enumerant, false);
                         state << ");\n";
                     }
                 }
@@ -428,8 +695,8 @@ struct Spirv_header_generator final : public Generator
                     state << indent << "switch(v)\n" << indent << "{\n";
                     for(auto &enumerant : enumerants.enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind
-                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                        state << indent << "case " << operand_kind->kind << "::"
+                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
                               << ":\n";
                         auto push_indent2 = state.pushed_indent();
                         state << indent << "return \"" << enumerant.enumerant << "\";\n";
@@ -447,8 +714,8 @@ struct Spirv_header_generator final : public Generator
                     state << indent << "switch(v)\n" << indent << "{\n";
                     for(auto &enumerant : enumerants.enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind
-                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                        state << indent << "case " << operand_kind->kind << "::"
+                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
                               << ":\n";
                         auto push_indent2 = state.pushed_indent();
                         state << indent << "return " << enumerant.capabilities << ";\n";
@@ -466,8 +733,8 @@ struct Spirv_header_generator final : public Generator
                     state << indent << "switch(v)\n" << indent << "{\n";
                     for(auto &enumerant : enumerants.enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind
-                              << "::" << get_enumerant_name(operand_kind->kind, enumerant.enumerant)
+                        state << indent << "case " << operand_kind->kind << "::"
+                              << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false)
                               << ":\n";
                         auto push_indent2 = state.pushed_indent();
                         state << indent << "return " << enumerant.extensions << ";\n";
@@ -475,9 +742,223 @@ struct Spirv_header_generator final : public Generator
                     state << indent << "}\n" << indent << "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_names;
+                member_names.reserve(bases.values.size());
+                for(std::size_t i = 0; i < bases.values.size(); 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,
+                                                                bases.values.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 base_type = "std::vector<Word>";
+                if(operand_kind->kind == "LiteralInteger")
+                    base_type = "std::uint64_t";
+                else if(operand_kind->kind == "LiteralString")
+                    base_type = "std::string";
+                else if(operand_kind->kind == "LiteralExtInstInteger")
+                    base_type = "Word";
+                else if(operand_kind->kind == "LiteralSpecConstantOpInteger")
+                    base_type = "Op";
+#warning finish
+                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;
+            }
             }
         }
-
+        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" << indent << "{\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.opname << "\";\n";
+            }
+            state << indent << "}\n" << indent << "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" << indent << "{\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.capabilities << ";\n";
+            }
+            state << indent << "}\n" << indent << "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" << indent << "{\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" << indent << "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 = operand.kind;
+                        break;
+                    }
+                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
+                    {
+                        member_type = "util::optional<" + operand.kind + ">";
+                        break;
+                    }
+                    case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
+                    {
+                        member_type = "std::vector<" + operand.kind + ">";
+                        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";
+        }
 
 #warning finish
         write_namespaces_end(state, spirv_namespace_names);
@@ -489,6 +970,19 @@ std::unique_ptr<Generator> Generators::make_spirv_header_generator()
 {
     return std::unique_ptr<Generator>(new Spirv_header_generator);
 }
+
+std::vector<std::unique_ptr<Generator>> Generators::make_all_generators()
+{
+    std::unique_ptr<Generator> generators_array[] = {
+        make_spirv_header_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;
+}
 }
 }
 }
index 908050c48101202a67c2f745cbf8041d50945aae..84d8fbfd66e5827e0b5c7c734acae07812c50aff 100644 (file)
@@ -32,6 +32,7 @@
 #include <type_traits>
 #include <cstdint>
 #include <unordered_set>
+#include <vector>
 
 namespace vulkan_cpu
 {
@@ -41,6 +42,9 @@ namespace generate
 {
 class Generator
 {
+private:
+    struct Tester;
+
 public:
     struct Generator_args
     {
@@ -186,20 +190,27 @@ protected:
 protected:
     static std::string get_guard_macro_name_from_file_name(std::string file_name);
     static std::string get_enumerant_name(const std::string &enumeration_name,
-                                          std::string enumerant_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));
+        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::string enumerant_name)
+    static std::string get_enumerant_name(const char *enumeration_name,
+                                          std::string enumerant_name,
+                                          bool input_name_should_have_prefix)
     {
         return get_enumerant_name(enumeration_name,
                                   std::char_traits<char>::length(enumeration_name),
-                                  std::move(enumerant_name));
+                                  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);
+                                          std::string enumerant_name,
+                                          bool input_name_should_have_prefix);
     static void write_indent(Generator_state &state);
     static void write_automatically_generated_file_warning(Generator_state &state);
     static void write_copyright_comment(Generator_state &state, const ast::Copyright &copyright);
@@ -299,6 +310,14 @@ protected:
     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_member_name_from_words(const std::string &words);
+    static std::string get_member_name_from_operand(
+        const ast::Instructions::Instruction::Operands::Operand &operand);
+    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);
 
 protected:
     static constexpr const char *vulkan_cpu_namespace_name = "vulkan_cpu";
@@ -308,6 +327,7 @@ protected:
     };
     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
@@ -334,6 +354,7 @@ struct Spirv_header_generator;
 struct Generators
 {
     static std::unique_ptr<Generator> make_spirv_header_generator();
+    static std::vector<std::unique_ptr<Generator>> make_all_generators();
 };
 }
 }
index 4a88efe0d8eb13badfdab67f8babfed6f9a0670b..ca8141fa195114d88735c8f432e7a161ad3b7885 100644 (file)
@@ -53,9 +53,7 @@ int generate_spirv_parser_main(int argc, char **argv)
         {
             auto json_in = json::parse(&source);
             auto ast = parser::parse(json_in.duplicate());
-            for(auto &generator : {
-                    generate::Generators::make_spirv_header_generator(),
-                })
+            for(auto &generator : generate::Generators::make_all_generators())
             {
                 generator->run(generate::Generator::Generator_args(output_directory), ast);
             }
index 8c96b89a6061e0577197fed4b16f3539700d27d1..d1bd5439d0e3719ed20bfa13b6c1a88faeee6edf 100644 (file)
@@ -682,6 +682,7 @@ ast::Instructions::Instruction parse_instructions_instruction(
         });
     ast::Instructions::Instruction::Operands operands;
     ast::Capabilities capabilities;
+    ast::Extensions extensions;
     for(auto &entry : instruction_object.values)
     {
         const auto &key = std::get<0>(entry);
@@ -696,13 +697,20 @@ ast::Instructions::Instruction parse_instructions_instruction(
         {
             capabilities = parse_capabilities(std::move(entry_value), &path_builder);
         }
+        else if(key == "extensions")
+        {
+            extensions = parse_extensions(std::move(entry_value), &path_builder);
+        }
         else if(key != opname_name && key != opcode_name)
         {
             throw Parse_error(entry_value.location, path_builder.path(), "unknown key");
         }
     }
-    return ast::Instructions::Instruction(
-        std::move(opname), opcode, std::move(operands), std::move(capabilities));
+    return ast::Instructions::Instruction(std::move(opname),
+                                          opcode,
+                                          std::move(operands),
+                                          std::move(capabilities),
+                                          std::move(extensions));
 }
 
 ast::Instructions parse_instructions(json::ast::Value value,
@@ -823,4 +831,4 @@ struct Test
 #endif
 }
 }
-}
\ No newline at end of file
+}