working on generate_spirv_parser -- generates parser cpp/h
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 20 Jun 2017 06:06:56 +0000 (23:06 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 20 Jun 2017 06:06:56 +0000 (23:06 -0700)
.gitignore
src/demo/demo.cpp
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h
src/generate_spirv_parser/generate_spirv_parser.cpp
src/spirv/CMakeLists.txt
src/spirv/spirv.cpp [deleted file]
src/util/constexpr_array.h
src/util/enum.h

index 2244dde3e48aa82997cbdbb958d3251242533556..fd1cf38bda2e1c73a60ce6b6a36472f28255a442 100644 (file)
@@ -7,3 +7,5 @@ Makefile
 /test-files/test.spv
 out.json
 compile_commands.json
+/.kdev4/
+*.kdev4
index 2ef361664a03bf3a0ee5c9a68c460cfda50d774c..616ef9591c0e686da49767bd777f53991fd4ee86 100644 (file)
  */
 #include <fstream>
 #include <iostream>
+#include <sstream>
 #include <vector>
 #include <array>
 #include <type_traits>
 #include <string>
 #include "spirv/spirv.h"
+#include "spirv/parser.h"
 #include "util/optional.h"
 
 namespace vulkan_cpu
@@ -202,7 +204,22 @@ int test_main(int argc, char **argv)
 {
     auto file = load_file("test-files/test.spv");
     if(file)
+    {
         dump_words(*file);
+        std::ostringstream os;
+        spirv::Parse_dump semantics(os);
+        auto parse_error = spirv::Parser<>::parse(file->data(), file->size(), semantics);
+        if(parse_error)
+        {
+            std::cerr << "error: " << std::hex << std::uppercase << std::showbase
+                      << parse_error->word_index << ": " << parse_error->message << std::endl;
+            return 1;
+        }
+        else
+        {
+            std::cout << os.str() << std::flush;
+        }
+    }
     return 0;
 }
 }
index 85e3968c6b93b21ee40e8fba0d42ee0fd71c64b8..4389960b2329fd8e24af678c1b19dec8848fd5db 100644 (file)
@@ -28,6 +28,7 @@
 #include <algorithm>
 #include <cstdlib>
 #include <iostream>
+#include <unordered_set>
 
 namespace vulkan_cpu
 {
@@ -173,17 +174,49 @@ std::string Generator::get_enumerant_name(const char *enumeration_name,
     return enumerant_name;
 }
 
-void Generator::write_indent(Generator_state &state)
+void Generator::write_indent_absolute(Generator_state &state, std::size_t amount)
 {
     static constexpr auto indent_string = "    ";
-    for(std::size_t i = state.indent_level; i > 0; i--)
+    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";
+    state << R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */
+)";
 }
 
 void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright &copyright)
@@ -212,8 +245,10 @@ void Generator::write_copyright_comment(Generator_state &state, const ast::Copyr
 
 void Generator::write_file_guard_start(Generator_state &state)
 {
-    state << "#ifdef " << state.guard_macro_name << "\n#define " << state.guard_macro_name
-          << "\n\n";
+    state << "#ifndef " << state.guard_macro_name << R"(
+#define )"
+          << state.guard_macro_name << "\n"
+                                       "\n";
 }
 
 void Generator::write_file_guard_end(Generator_state &state)
@@ -223,12 +258,14 @@ void Generator::write_file_guard_end(Generator_state &state)
 
 void Generator::write_namespace_start(Generator_state &state, const char *namespace_name)
 {
-    state << "namespace " << namespace_name << "\n{\n";
+    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";
+    state << "namespace " << namespace_name << "\n"
+                                               "{\n";
 }
 
 void Generator::write_namespace_end(Generator_state &state)
@@ -422,6 +459,109 @@ std::string Generator::get_member_name_from_words(const std::string &words)
         if(is_uppercase_letter(ch))
             ch = ch - 'A' + 'a'; // to lowercase
     }
+    for(const char *reserved_word : {
+            "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",
+        })
+    {
+        if(retval == reserved_word)
+        {
+            retval += '_';
+            break;
+        }
+    }
     return retval;
 }
 
@@ -490,8 +630,9 @@ void Generator::write_struct_nonstatic_members_and_constructors(Generator_state
             state << "\n";
         }
     }
-    state << indent << "{\n";
-    state << indent << "}\n";
+    state << indent(R"({
+}
+)");
     if(member_count != 0)
     {
         state << indent;
@@ -520,11 +661,31 @@ void Generator::write_struct_nonstatic_members_and_constructors(Generator_state
                 state << "\n";
             }
         }
-        state << indent << "{\n";
-        state << indent << "}\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")
@@ -571,21 +732,28 @@ struct Spirv_header_generator final : public Generator
         state.open_output_file();
         write_file_comments(state, top_level.copyright);
         write_file_guard_start(state);
-        state << "#include <cstdint>\n"
-                 "#include \"util/enum.h\"\n"
-                 "#include \"util/optional.h\"\n"
-                 "#include <vector>\n";
-        state << "\n";
+        state << indent(R"(#include <cstdint>
+#include "util/enum.h"
+#include "util/optional.h"
+#include <vector>
+)");
         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 = "
-              << unsigned_dec_integer_literal(top_level.major_version) << ";\n";
-        state << "constexpr std::uint32_t minor_version = "
-              << unsigned_dec_integer_literal(top_level.minor_version) << ";\n";
-        state << "constexpr std::uint32_t revision = "
+        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;
@@ -593,19 +761,22 @@ struct Spirv_header_generator final : public Generator
         for(auto &extension : extensions_set)
             extensions_list.push_back(extension);
         std::sort(extensions_list.begin(), extensions_list.end());
-        state << "\n"
-                 "enum class "
-              << extension_enum_name << " : std::size_t\n"
-                                        "{\n";
+        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 << "};\n"
-                 "\n"
-                 "vulkan_cpu_util_generate_enum_traits("
+        state << indent(
+                     "};\n"
+                     "\n"
+                     "vulkan_cpu_util_generate_enum_traits(")
               << extension_enum_name;
         {
             auto push_indent = state.pushed_indent();
@@ -614,21 +785,29 @@ struct Spirv_header_generator final : public Generator
                       << "::" << get_enumerant_name(extension_enum_name, extension, false);
             state << ");\n";
         }
-        state << "\n"
-                 "constexpr const char *get_enumerant_name("
-              << extension_enum_name << " v) noexcept\n"
-                                        "{\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" << indent << "{\n";
+            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) << ":\n";
-                auto push_indent2 = state.pushed_indent();
-                state << indent << "return \"" << extension << "\";\n";
+                state << indent("case ") << extension_enum_name
+                      << "::" << get_enumerant_name(extension_enum_name, extension, false)
+                      << indent(true,
+                                ":\n"
+                                "`return \"")
+                      << extension << "\";\n";
             }
-            state << indent << "}\n" << indent << "return \"\";\n";
+            state << indent(
+                "}\n"
+                "return \"\";\n");
         }
         state << "}\n";
         std::vector<const ast::Operand_kinds::Operand_kind *> operand_kinds;
@@ -653,6 +832,7 @@ struct Spirv_header_generator final : public Generator
                     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 "
                       << operand_kind->kind << " : Word\n"
@@ -679,7 +859,7 @@ struct Spirv_header_generator final : public Generator
                           << operand_kind->kind;
                     {
                         auto push_indent = state.pushed_indent();
-                        for(auto &enumerant : enumerants.enumerants)
+                        for(auto &enumerant : unique_enumerants)
                             state << ",\n" << indent << operand_kind->kind
                                   << "::" << get_enumerant_name(
                                                  operand_kind->kind, enumerant.enumerant, false);
@@ -692,16 +872,21 @@ struct Spirv_header_generator final : public Generator
                                                "{\n";
                 {
                     auto push_indent = state.pushed_indent();
-                    state << indent << "switch(v)\n" << indent << "{\n";
-                    for(auto &enumerant : enumerants.enumerants)
+                    state << indent(
+                        "switch(v)\n"
+                        "{\n");
+                    for(auto &enumerant : unique_enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind << "::"
+                        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";
+                              << indent(true,
+                                        ":\n"
+                                        "`return \"")
+                              << enumerant.enumerant << "\";\n";
                     }
-                    state << indent << "}\n" << indent << "return \"\";\n";
+                    state << indent(
+                        "}\n"
+                        "return \"\";\n");
                 }
                 state << "}\n"
                          "\n"
@@ -711,16 +896,21 @@ struct Spirv_header_generator final : public Generator
                                                "{\n";
                 {
                     auto push_indent = state.pushed_indent();
-                    state << indent << "switch(v)\n" << indent << "{\n";
-                    for(auto &enumerant : enumerants.enumerants)
+                    state << indent(
+                        "switch(v)\n"
+                        "{\n");
+                    for(auto &enumerant : unique_enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind << "::"
+                        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";
+                              << indent(true,
+                                        ":\n"
+                                        "return ")
+                              << enumerant.capabilities << ";\n";
                     }
-                    state << indent << "}\n" << indent << "return {};\n";
+                    state << indent(
+                        "}\n"
+                        "return {};\n");
                 }
                 state << "}\n"
                          "\n"
@@ -730,16 +920,21 @@ struct Spirv_header_generator final : public Generator
                                                "{\n";
                 {
                     auto push_indent = state.pushed_indent();
-                    state << indent << "switch(v)\n" << indent << "{\n";
-                    for(auto &enumerant : enumerants.enumerants)
+                    state << indent(
+                        "switch(v)\n"
+                        "{\n");
+                    for(auto &enumerant : unique_enumerants)
                     {
-                        state << indent << "case " << operand_kind->kind << "::"
+                        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";
+                              << indent(true,
+                                        ":\n"
+                                        "return ")
+                              << enumerant.extensions << ";\n";
                     }
-                    state << indent << "}\n" << indent << "return {};\n";
+                    state << indent(
+                        "}\n"
+                        "return {};\n");
                 }
                 state << "}\n";
                 break;
@@ -855,16 +1050,21 @@ struct Spirv_header_generator final : public Generator
                                  "{\n";
         {
             auto push_indent = state.pushed_indent();
-            state << indent << "switch(v)\n" << indent << "{\n";
+            state << indent(
+                "switch(v)\n"
+                "{\n");
             for(auto &instruction : top_level.instructions.instructions)
             {
-                state << indent << "case " << op_enum_name
+                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";
+                      << indent(true,
+                                ":\n"
+                                "return \"")
+                      << instruction.opname << "\";\n";
             }
-            state << indent << "}\n" << indent << "return \"\";\n";
+            state << indent(
+                "}\n"
+                "return \"\";\n");
         }
         state << "}\n"
                  "\n"
@@ -874,16 +1074,21 @@ struct Spirv_header_generator final : public Generator
                  "{\n";
         {
             auto push_indent = state.pushed_indent();
-            state << indent << "switch(v)\n" << indent << "{\n";
+            state << indent(
+                "switch(v)\n"
+                "{\n");
             for(auto &instruction : top_level.instructions.instructions)
             {
-                state << indent << "case " << op_enum_name
+                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";
+                      << indent(true,
+                                ":\n"
+                                "return ")
+                      << instruction.capabilities << ";\n";
             }
-            state << indent << "}\n" << indent << "return {};\n";
+            state << indent(
+                "}\n"
+                "return {};\n");
         }
         state << "}\n"
                  "\n"
@@ -893,16 +1098,20 @@ struct Spirv_header_generator final : public Generator
                  "{\n";
         {
             auto push_indent = state.pushed_indent();
-            state << indent << "switch(v)\n" << indent << "{\n";
+            state << indent(
+                "switch(v)\n"
+                "{\n");
             for(auto &instruction : top_level.instructions.instructions)
             {
-                state << indent << "case " << op_enum_name
+                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("return ") << instruction.extensions << ";\n";
             }
-            state << indent << "}\n" << indent << "return {};\n";
+            state << indent(
+                "}\n"
+                "return {};\n");
         }
         state << "}\n";
         for(auto &instruction : top_level.instructions.instructions)
@@ -914,15 +1123,15 @@ struct Spirv_header_generator final : public Generator
                                     "{\n";
             {
                 auto push_indent = state.pushed_indent();
-                state << indent << "static constexpr " << op_enum_name << " get_opcode() noexcept\n"
-                      << indent << "{\n";
+                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
+                    state << indent("return ") << op_enum_name
                           << "::" << get_enumerant_name(op_enum_name, instruction.opname, true)
                           << ";\n";
                 }
-                state << indent << "}\n";
+                state << indent("}\n");
                 std::vector<std::string> member_names;
                 std::vector<std::string> member_types;
                 member_names.reserve(instruction.operands.operands.size());
@@ -966,15 +1175,289 @@ struct Spirv_header_generator final : public Generator
     }
 };
 
+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);
+        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_function_name(std::string kind)
+    {
+        return "dump_operand_" + std::move(kind);
+    }
+    virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
+    {
+        Generator_state state(this, generator_args);
+        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 <vector>
+
+)";
+        write_namespaces_start(state, spirv_namespace_names);
+        state << indent(R"(struct Parse_error
+{
+`std::size_t word_index;
+`std::string message;
+`Parse_error(std::size_t word_index, std::string message) noexcept
+``: word_index(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::string message) = 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";
+            }
+#warning finish
+        }
+        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::string message) 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_function_name(operand_kind.kind);
+                state << indent("void ") << dump_function_name << "(const " << operand_kind.kind
+                      << " &v);\n";
+                state << indent("void ") << dump_function_name << "(const util::optional<"
+                      << operand_kind.kind << "> &v);\n";
+                state << indent("void ") << dump_function_name << "(const std::vector<"
+                      << operand_kind.kind << "> &v);\n";
+            }
+#warning finish
+        }
+        state << "};\n"
+                 "\n"
+                 "template <typename Semantics = Parse_semantics_generic>\n"
+                 "struct Parser\n"
+                 "{\n";
+        {
+            auto push_indent = state.pushed_indent();
+            state << indent(
+                R"(static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_count, Semantics &semantics)
+{
+)");
+            {
+                auto push_indent2 = state.pushed_indent();
+                state << indent(R"(std::size_t word_index = 0;
+if(word_index >= word_count)
+`return semantics.handle_error(word_index, "hit EOF when parsing magic number");
+if(words[word_index] != magic_number)
+`return semantics.handle_error(word_index, "invalid magic number");
+return nullptr;
+)");
+            }
+            state << indent("}\n");
+#warning finish
+        }
+        state << "};\n";
+#warning finish
+        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);
+        state.open_output_file();
+        write_file_comments(state, top_level.copyright);
+        state << "#include \"parser.h\"\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::string message)
+{
+`return std::unique_ptr<Parse_error>(new Parse_error(word_index, std::move(message)));
+}
+)");
+        for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+        {
+            auto dump_function_name =
+                Parser_header_generator::get_dump_function_name(operand_kind.kind);
+            {
+                state << indent(R"(
+void Parse_dump::)") << dump_function_name
+                      << "(const " << operand_kind.kind << R"( &v)
+{
+)";
+                auto push_indent = state.pushed_indent();
+                switch(operand_kind.category)
+                {
+                case ast::Operand_kinds::Operand_kind::Category::bit_enum:
+                {
+                    auto &enumerants =
+                        util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
+#warning finish
+                    break;
+                }
+                case ast::Operand_kinds::Operand_kind::Category::value_enum:
+                {
+#warning finish
+                    break;
+                }
+                case ast::Operand_kinds::Operand_kind::Category::composite:
+                {
+#warning finish
+                    break;
+                }
+                case ast::Operand_kinds::Operand_kind::Category::id:
+                {
+#warning finish
+                    break;
+                }
+                case ast::Operand_kinds::Operand_kind::Category::literal:
+                {
+#warning finish
+                    break;
+                }
+                }
+                push_indent.finish();
+                state << indent("}\n");
+            }
+            state << indent(R"(
+void Parse_dump::)")
+                  << dump_function_name << "(const util::optional<" << operand_kind.kind
+                  << indent(true, R"(> &v)
+{
+`if(v)
+)") << indent(2) << dump_function_name
+                  << indent(true, R"((*v);
+`else
+``os << "nullopt";
+}
+
+void Parse_dump::)")
+                  << dump_function_name << "(const std::vector<" << operand_kind.kind
+                  << indent(true, R"(> &v)
+{
+`auto separator = "";
+`os << "{";
+`for(auto &value : v)
+`{
+``os << separator;
+``separator = ", ";
+)") << indent(2) << dump_function_name
+                  << indent(true, R"((value);
+`}
+`os << "}";
+}
+)");
+#warning finish
+        }
+        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_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;
index 84d8fbfd66e5827e0b5c7c734acae07812c50aff..04aadfcac92231765b24017880667d1aad9e89c4 100644 (file)
@@ -86,7 +86,7 @@ protected:
             write_extensions_set(*this, v);
             return *this;
         }
-        Push_indent pushed_indent() noexcept;
+        Push_indent pushed_indent(std::ptrdiff_t amount = 1) noexcept;
     };
     class Push_indent final
     {
@@ -95,38 +95,75 @@ protected:
 
     private:
         Generator_state *state;
+        std::ptrdiff_t amount;
 
     public:
-        explicit Push_indent(Generator_state &state) noexcept : state(&state)
+        explicit Push_indent(Generator_state &state, std::ptrdiff_t amount = 1) noexcept
+            : state(&state),
+              amount(amount)
         {
-            state.indent_level++;
+            state.indent_level += amount;
         }
-        Push_indent(Push_indent &&rt) noexcept : state(rt.state)
+        Push_indent(Push_indent &&rt) noexcept : state(rt.state), amount(rt.amount)
         {
             rt.state = nullptr;
         }
         void finish() noexcept
         {
             assert(state);
-            state->indent_level--;
+            state->indent_level -= amount;
             state = nullptr;
         }
         ~Push_indent()
         {
             if(state)
-                state->indent_level--;
+                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;
-        friend Generator_state &operator<<(Generator_state &state, Indent_t)
+        constexpr Indent_t operator()(std::ptrdiff_t additional_offset) const noexcept
         {
-            write_indent(state);
+            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 Indent_t indent{};
+    static constexpr auto indent = Indent_t{0};
     enum class Integer_literal_base
     {
         dec = 0,
@@ -211,7 +248,15 @@ protected:
                                           std::size_t enumeration_name_size,
                                           std::string enumerant_name,
                                           bool input_name_should_have_prefix);
-    static void write_indent(Generator_state &state);
+    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)
@@ -318,6 +363,9 @@ protected:
                                                                 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";
@@ -344,16 +392,23 @@ public:
     virtual ~Generator() = default;
 };
 
-inline Generator::Push_indent Generator::Generator_state::pushed_indent() noexcept
+inline Generator::Push_indent Generator::Generator_state::pushed_indent(
+    std::ptrdiff_t amount) noexcept
 {
-    return Push_indent(*this);
+    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();
 };
 }
index ca8141fa195114d88735c8f432e7a161ad3b7885..05e1579fe10ee964c94ba76cc6987f51579e715f 100644 (file)
@@ -59,7 +59,7 @@ int generate_spirv_parser_main(int argc, char **argv)
             }
 #warning finish
             std::cerr << "generate_spirv_parser is not finished being implemented" << std::endl;
-            return 1;
+            return 0;
         }
         catch(parser::Parse_error &e)
         {
index 5e0542fbcd15e3863ceeef9b2618f220946325af..31995bcc85eafb90c889bdf79ad3bf2389d127d7 100644 (file)
 #
 cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
-set(sources spirv.cpp)
+set(sources)
 
 set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/generated)
 set(spirv_parser_generated_dir ${spirv_parser_generated_include_dir}/spirv)
-set(spirv_parser_sources ${spirv_parser_generated_dir}/parser.cpp)
+set(spirv_parser_sources ${spirv_parser_generated_dir}/parser.cpp ${spirv_parser_generated_dir}/spirv.cpp)
 set(spirv_parser_headers ${spirv_parser_generated_dir}/parser.h ${spirv_parser_generated_dir}/spirv.h)
 set(spirv_core_grammar_json ${CMAKE_CURRENT_SOURCE_DIR}/../khronos-spirv/spirv.core.grammar.json)
 message(STATUS "spirv_parser_generated_dir: " ${spirv_parser_generated_dir})
diff --git a/src/spirv/spirv.cpp b/src/spirv/spirv.cpp
deleted file mode 100644 (file)
index 1abdc51..0000000
+++ /dev/null
@@ -1,23 +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 "spirv.h"
index 14e62f785f090087458b8ec9c40d97be6dd1b2cf..5182c1e1b5e3443cfd4e96109aeb27462ebabd86 100644 (file)
@@ -34,10 +34,56 @@ namespace vulkan_cpu
 {
 namespace util
 {
+namespace detail
+{
+template <typename T, std::size_t N>
+struct Constexpr_array_helper
+{
+    typedef T values_type[N];
+    static constexpr T *get_values_pointer(values_type &values) noexcept
+    {
+        return values;
+    }
+    static constexpr const T *get_values_pointer(const values_type &values) noexcept
+    {
+        return values;
+    }
+};
+
+template <typename T>
+struct Constexpr_array_helper<T, 0>
+{
+    struct values_type
+    {
+    };
+    static constexpr T *get_values_pointer(values_type &values) noexcept
+    {
+        return nullptr;
+    }
+    static constexpr const T *get_values_pointer(const values_type &values) noexcept
+    {
+        return nullptr;
+    }
+};
+}
+
 template <typename T, std::size_t N>
 struct Constexpr_array
 {
-    T values[N];
+private:
+    typedef detail::Constexpr_array_helper<T, N> Helper;
+    typedef typename Helper::values_type values_type;
+    constexpr T *get_values_pointer() noexcept
+    {
+        return Helper::get_values_pointer(values);
+    }
+    constexpr const T *get_values_pointer() const noexcept
+    {
+        return Helper::get_values_pointer(values);
+    }
+
+public:
+    values_type values;
     typedef T value_type;
     typedef std::size_t size_type;
     typedef std::ptrdiff_t difference_type;
@@ -53,69 +99,69 @@ struct Constexpr_array
     {
         if(index >= N)
             throw std::out_of_range("Constexpr_array::at");
-        return values[index];
+        return get_values_pointer()[index];
     }
     constexpr const T &at(std::size_t index) const
     {
         if(index >= N)
             throw std::out_of_range("Constexpr_array::at");
-        return values[index];
+        return get_values_pointer()[index];
     }
     constexpr T &operator[](std::size_t index) noexcept
     {
-        return values[index];
+        return get_values_pointer()[index];
     }
     constexpr const T &operator[](std::size_t index) const noexcept
     {
-        return values[index];
+        return get_values_pointer()[index];
     }
     constexpr T &front() noexcept
     {
-        return values[0];
+        return get_values_pointer()[0];
     }
     constexpr const T &front() const noexcept
     {
-        return values[0];
+        return get_values_pointer()[0];
     }
     constexpr T &back() noexcept
     {
-        return values[N - 1];
+        return get_values_pointer()[N - 1];
     }
     constexpr const T &back() const noexcept
     {
-        return values[N - 1];
+        return get_values_pointer()[N - 1];
     }
     constexpr T *data() noexcept
     {
-        return values;
+        return get_values_pointer();
     }
     constexpr const T *data() const noexcept
     {
-        return values;
+        return get_values_pointer();
     }
     constexpr iterator begin() noexcept
     {
-        return values;
+        return get_values_pointer();
     }
     constexpr const_iterator begin() const noexcept
     {
-        return values;
+        return get_values_pointer();
     }
     constexpr const_iterator cbegin() const noexcept
     {
-        return values;
+        return get_values_pointer();
     }
     constexpr iterator end() noexcept
     {
-        return values + N;
+        return get_values_pointer() + N;
     }
     constexpr const_iterator end() const noexcept
     {
-        return values + N;
+        return get_values_pointer() + N;
     }
     constexpr const_iterator cend() const noexcept
     {
-        return values + N;
+        return get_values_pointer() + N;
     }
     constexpr reverse_iterator rbegin() noexcept
     {
@@ -155,14 +201,14 @@ struct Constexpr_array
     }
     constexpr void fill(const T &value) noexcept(std::is_nothrow_copy_assignable<T>::value)
     {
-        for(auto &i : values)
+        for(auto &i : *this)
             i = value;
     }
     constexpr void swap(Constexpr_array &other) noexcept(is_nothrow_swappable_v<T>)
     {
         using std::swap;
         for(std::size_t index = 0; index < size(); index++)
-            swap(values[index], other.values[index]);
+            swap(get_values_pointer()[index], other.get_values_pointer()[index]);
     }
 };
 
index e063a9ef81c5c5406fccd325535c1ae9bbda2fb0..51e082600c999e103c9c9abac80178a2d8ed7c36 100644 (file)
@@ -61,26 +61,37 @@ private:
 
 public:
     static constexpr bool is_compact = is_compact_helper();
+    struct Value_and_index
+    {
+        T value;
+        std::size_t index;
+        constexpr Value_and_index() noexcept : value(), index()
+        {
+        }
+        constexpr Value_and_index(T value, std::size_t index) noexcept : value(value), index(index)
+        {
+        }
+    };
 
 private:
     template <std::size_t N>
-    static constexpr Constexpr_array<std::pair<T, std::size_t>, N> sort_value_index_map(
-        const std::pair<T, std::size_t> *value_index_map) noexcept
+    static constexpr Constexpr_array<Value_and_index, N> sort_value_index_map(
+        const Value_and_index *value_index_map) noexcept
     {
         // uses merge sort algorithm
         if(N == 0)
             return {};
-        Constexpr_array<std::pair<T, std::size_t>, N> retval{};
+        Constexpr_array<Value_and_index, N> retval{};
         if(N == 1)
         {
             retval[0] = value_index_map[0];
-            return;
+            return retval;
         }
 
         // split
-        constexpr std::size_t split_index = N2 / 2;
+        constexpr std::size_t split_index = N / 2;
         constexpr std::size_t part1_size = split_index;
-        constexpr std::size_t part2_size = N2 - part1_size;
+        constexpr std::size_t part2_size = N - part1_size;
         auto part1 = sort_value_index_map<part1_size>(value_index_map);
         auto part2 = sort_value_index_map<part2_size>(value_index_map + split_index);
 
@@ -91,8 +102,8 @@ private:
         while(part1_index < part1_size && part2_index < part2_size)
         {
             // we want to copy from part1 if values are equal
-            if(static_cast<underlying_type>(std::get<0>(part2[part2_index]))
-               < static_cast<underlying_type>(std::get<0>(part1[part1_index])))
+            if(static_cast<underlying_type>(part2[part2_index].value)
+               < static_cast<underlying_type>(part1[part1_index].value))
                 retval[retval_index++] = part2[part2_index++];
             else
                 retval[retval_index++] = part1[part1_index++];
@@ -103,19 +114,19 @@ private:
             retval[retval_index++] = part2[part2_index++];
         return retval;
     }
-    static constexpr Constexpr_array<std::pair<T, std::size_t>, value_count>
+    static constexpr Constexpr_array<Value_and_index, value_count>
         make_sorted_value_index_map() noexcept
     {
-        Constexpr_array<std::pair<T, std::size_t>, N> retval{};
+        Constexpr_array<Value_and_index, value_count> retval{};
         for(std::size_t i = 0; i < value_count; i++)
             retval[i] = {values[i], i};
-        retval = sort_value_index_map<N>(retval.data());
+        retval = sort_value_index_map<value_count>(retval.data());
         return retval;
     }
 
 public:
-    static constexpr Constexpr_array<std::pair<T, std::size_t>, value_count>
-        sorted_value_index_map = make_sorted_value_index_map();
+    static constexpr Constexpr_array<Value_and_index, value_count> sorted_value_index_map =
+        make_sorted_value_index_map();
     static constexpr std::size_t npos = -1;
     /** find first occurrence of value in values and return index if found, otherwise return npos */
     static constexpr std::size_t find_value(T value) noexcept
@@ -127,7 +138,7 @@ public:
             retval = static_cast<std::size_t>(static_cast<underlying_type>(value))
                      - static_cast<std::size_t>(static_cast<underlying_type>(values.front()));
         }
-        else if(value_count < 8)
+        else if(value_count < binary_search_transition)
         {
             retval = -1;
             for(std::size_t i = 0; i < value_count; i++)
@@ -174,7 +185,7 @@ template <typename T>
 constexpr bool Enum_traits<T>::is_compact;
 
 template <typename T>
-constexpr Constexpr_array<std::pair<T, std::size_t>, Enum_traits<T>::value_count>
+constexpr Constexpr_array<typename Enum_traits<T>::Value_and_index, Enum_traits<T>::value_count>
     Enum_traits<T>::sorted_value_index_map;
 
 template <typename T>
@@ -189,12 +200,13 @@ struct Default_enum_traits
 };
 
 template <typename Enum, Enum... Values>
-static constexpr Enum_values<Enum, sizeof...(Values)> Default_enum_traits<Enum, Values...>::values;
+constexpr Constexpr_array<Enum, sizeof...(Values)> Default_enum_traits<Enum, Values...>::values;
 /** generate code for Enum_traits instantiation; use like
  * <code>vulkan_cpu_util_generate_enum_traits(Enum, Enum::Value1, Enum::Value2, Enum::Value3,
  * <...>);</code> */
-#define vulkan_cpu_util_generate_enum_traits(...) \
-    ::vulkan_cpu::util::detail::Default_enum_traits<__VA_ARGS__> enum_traits_resolve_function(Enum)
+#define vulkan_cpu_util_generate_enum_traits(Enum, ...)                \
+    ::vulkan_cpu::util::detail::Default_enum_traits<Enum, __VA_ARGS__> \
+        enum_traits_resolve_function(Enum)
 }
 
 /** behaves like a std::set<T> */