#include <algorithm>
#include <cstdlib>
#include <iostream>
+#include <unordered_set>
namespace vulkan_cpu
{
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 ©right)
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)
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)
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;
}
state << "\n";
}
}
- state << indent << "{\n";
- state << indent << "}\n";
+ state << indent(R"({
+}
+)");
if(member_count != 0)
{
state << indent;
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")
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;
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();
<< "::" << 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;
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"
<< 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);
"{\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"
"{\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"
"{\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;
"{\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"
"{\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"
"{\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)
"{\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());
}
};
+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;
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
{
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,
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 ©right);
static void write_file_comments(Generator_state &state, const ast::Copyright ©right)
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";
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();
};
}
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);
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++];
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
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++)
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>
};
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> */