*/
#include "generate.h"
#include "json/json.h"
-#include "util/string_view.h"
#include "util/optional.h"
#include <limits>
#include <algorithm>
#include <iostream>
#include <unordered_set>
+#error finish converting to use get_enum_with_parameters_struct_name
+
namespace vulkan_cpu
{
namespace generate_spirv_parser
namespace generate
{
Generator::Generator_state::Generator_state(const Generator *generator,
- Generator_args &generator_args)
+ Generator_args &generator_args,
+ const ast::Top_level &top_level)
: generator_args(generator_args),
indent_level(0),
full_output_file_name(generator_args.output_directory + "/"
+ generator->output_base_file_name),
guard_macro_name(get_guard_macro_name_from_file_name(full_output_file_name)),
- os()
+ os(),
+ top_level(top_level),
+ operand_kind_map(),
+ operand_has_any_parameters_map()
{
os.exceptions(std::ios::badbit | std::ios::failbit);
+ for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+ {
+ operand_kind_map.emplace(operand_kind.kind, &operand_kind);
+ bool &has_any_parameters = operand_has_any_parameters_map[&operand_kind];
+ has_any_parameters = false;
+ if(util::holds_alternative<ast::Operand_kinds::Operand_kind::Enumerants>(
+ operand_kind.value))
+ {
+ auto &enumerants =
+ util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
+ for(auto &enumerant : enumerants.enumerants)
+ {
+ if(!enumerant.parameters.empty())
+ {
+ has_any_parameters = true;
+ break;
+ }
+ }
+ }
+ }
}
void Generator::Generator_state::open_output_file()
void Generator::write_automatically_generated_file_warning(Generator_state &state)
{
- state << R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */
-)";
+ state
+ << "/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */\n";
}
void Generator::write_copyright_comment(Generator_state &state, const ast::Copyright ©right)
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",
- })
+ static constexpr const char *const reserved_words[] = {
+ "alignas",
+ "alignof",
+ "and",
+ "and_eq",
+ "asm",
+ "atomic_cancel",
+ "atomic_commit",
+ "atomic_noexcept",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "char16_t",
+ "char32_t",
+ "class",
+ "compl",
+ "concept",
+ "concepts",
+ "const",
+ "const_cast",
+ "constexpr",
+ "continue",
+ "decltype",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "import",
+ "inline",
+ "int",
+ "long",
+ "module",
+ "modules",
+ "mutable",
+ "namespace",
+ "new",
+ "noexcept",
+ "not",
+ "not_eq",
+ "nullptr",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "requires",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_assert",
+ "static_cast",
+ "struct",
+ "switch",
+ "synchronized",
+ "template",
+ "this",
+ "thread_local",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq",
+ };
+ for(const char *reserved_word : reserved_words)
{
if(retval == reserved_word)
{
static void test()
{
for(auto &input : {
- "abc def", "AbcDef", "ABCDef", "'abc, def'",
- })
+ "abc def", "AbcDef", "ABCDef", "'abc, def'",
+ })
{
std::cout << "\"" << input << "\" -> " << get_member_name_from_words(input)
<< std::endl;
return get_member_name_from_words(operand.kind);
}
+std::string Generator::get_enum_with_parameters_struct_name(
+ Generator_state &state, const ast::Operand_kinds::Operand_kind &operand_kind)
+{
+ if(get_operand_has_any_parameters(state, operand_kind))
+ return operand_kind.kind + "_with_parameters";
+ return operand_kind.kind;
+}
+
void Generator::write_struct_nonstatic_members_and_constructors(Generator_state &state,
const std::string &struct_name,
const std::string *member_types,
}
virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
{
- Generator_state state(this, generator_args);
+ Generator_state state(this, generator_args, top_level);
state.open_output_file();
write_file_comments(state, top_level.copyright);
write_file_guard_start(state);
state << ",\n";
}
}
- state << "};\n";
- if(!is_bit_enum)
+ state << "};\n"
+ "\n"
+ "vulkan_cpu_util_generate_enum_traits("
+ << operand_kind->kind;
{
- state << "\n"
- "vulkan_cpu_util_generate_enum_traits("
- << operand_kind->kind;
- {
- auto push_indent = state.pushed_indent();
- for(auto &enumerant : unique_enumerants)
- state << ",\n" << indent << operand_kind->kind
- << "::" << get_enumerant_name(
- operand_kind->kind, enumerant.enumerant, false);
- state << ");\n";
- }
+ auto push_indent = state.pushed_indent();
+ for(auto &enumerant : unique_enumerants)
+ state << ",\n" << indent << operand_kind->kind << "::"
+ << get_enumerant_name(operand_kind->kind, enumerant.enumerant, false);
+ state << ");\n";
}
state << "\n"
"constexpr const char *get_enumerant_name("
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";
+ base_type = "std::uint32_t"; // TODO: fix after determining if LiteralInteger
+ // can be multiple words
else if(operand_kind->kind == "LiteralString")
base_type = "std::string";
else if(operand_kind->kind == "LiteralExtInstInteger")
}
virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
{
- Generator_state state(this, generator_args);
+ Generator_state state(this, generator_args, top_level);
state.open_output_file();
write_file_comments(state, top_level.copyright);
state << "#include \"spirv.h\"\n";
Parser_header_generator() : Generator("parser.h")
{
}
- static std::string get_dump_function_name(std::string kind)
+ static std::string get_dump_operand_function_name(std::string kind)
{
return "dump_operand_" + std::move(kind);
}
+ static std::string get_parse_operand_function_name(std::string kind)
+ {
+ return "parse_operand_" + std::move(kind);
+ }
+ static std::string get_parse_instruction_function_name(std::string opname)
+ {
+ return "parse_instruction_" + get_enumerant_name(op_enum_name, opname, true);
+ }
virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
{
- Generator_state state(this, generator_args);
+ Generator_state state(this, generator_args, top_level);
state.open_output_file();
write_file_comments(state, top_level.copyright);
write_file_guard_start(state);
#include <memory>
#include <ostream>
#include "util/optional.h"
+#include "json/json.h"
#include <vector>
)";
state << indent(R"(struct Parse_error
{
`std::size_t word_index;
+`std::size_t instruction_word_index;
`std::string message;
-`Parse_error(std::size_t word_index, std::string message) noexcept
+`Parse_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) noexcept
``: word_index(word_index),
+`` instruction_word_index(instruction_word_index),
`` message(std::move(message))
`{
`}
{
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;
+virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) = 0;
+virtual void handle_spirv_version(unsigned major, unsigned minor) = 0;
+virtual void handle_generator_magic_number(Word value) = 0;
+virtual void handle_id_bound(Word id_bound) = 0;
)");
for(auto &instruction : top_level.instructions.instructions)
{
{
auto 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;
+ R"(virtual std::unique_ptr<Parse_error> handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message) override;
+virtual void handle_spirv_version(unsigned major, unsigned minor) override;
+virtual void handle_generator_magic_number(Word value) override;
+virtual void handle_id_bound(Word id_bound) override;
)");
for(auto &instruction : top_level.instructions.instructions)
{
}
for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
{
- auto dump_function_name = get_dump_function_name(operand_kind.kind);
+ auto dump_function_name = get_dump_operand_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<"
"{\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)
+ for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+ {
+ auto parse_function_name = get_parse_operand_function_name(operand_kind.kind);
+ state
+ << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
+ << indent(
+ true,
+ R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index, std::size_t &word_index, )")
+ << operand_kind.kind << indent(true,
+ R"( &value)
+{
+`if(word_index >= word_count)
+``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "instruction missing operand");
+)");
+ auto push_indent = state.pushed_indent();
+ switch(operand_kind.category)
+ {
+ case ast::Operand_kinds::Operand_kind::Category::bit_enum:
+ {
+ state << indent(R"(value = static_cast<)") << operand_kind.kind
+ << indent(true, R"(>(words[word_index++]);
+)");
+ break;
+ }
+ case ast::Operand_kinds::Operand_kind::Category::value_enum:
+ {
+ state << indent(R"(value = static_cast<)") << operand_kind.kind
+ << indent(true, R"(>(words[word_index]);
+if(util::Enum_traits<)") << operand_kind.kind
+ << indent(true, R"(>::find_value(value) == util::Enum_traits<)")
+ << operand_kind.kind << indent(true, R"(>::npos)
+`return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "invalid enum value");
+word_index++;
+)");
+ break;
+ }
+ case ast::Operand_kinds::Operand_kind::Category::composite:
+ {
+ auto &bases =
+ util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
+ for(std::size_t i = 0; i < bases.values.size(); i++)
+ {
+ state << indent;
+ if(i == 0)
+ state << indent(true, "auto ");
+ state << indent(true, "parse_error = ")
+ << get_parse_operand_function_name(bases.values[i])
+ << "(words, word_count, semantics, error_instruction_index, "
+ "word_index, value."
+ << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
+ "part_")
+ << indent(true, R"();
+if(parse_error)
+`return parse_error;
+)");
+ }
+ break;
+ }
+ case ast::Operand_kinds::Operand_kind::Category::id:
+ {
+ state << indent(R"(value = static_cast<Id>(words[word_index++]);
+)");
+ break;
+ }
+ case ast::Operand_kinds::Operand_kind::Category::literal:
+ {
+ if(operand_kind.kind == "LiteralInteger")
+ {
+ // TODO: fix after determining if LiteralInteger can be multiple words
+ state << indent(R"(value = words[word_index++];
+)");
+ }
+ else if(operand_kind.kind == "LiteralExtInstInteger")
+ {
+ state << indent(R"(value = words[word_index++];
+)");
+ }
+ else if(operand_kind.kind == "LiteralString")
+ {
+ state << indent(
+ R"(value.clear();
+bool done = false;
+while(!done)
{
+`if(word_index >= word_count)
+``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string missing terminating null");
+`Word word = words[word_index++];
+`for(std::size_t i = 0; i < 4; i++)
+`{
+``unsigned char ch = word & 0xFFU;
+``word >>= 8;
+``if(ch == '\0')
+``{
+```done = true;
+```if(word != 0)
+````return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "string has non-zero padding");
+``}
+``else
+``{
+```value += ch;
+``}
+`}
+}
)");
+ }
+ else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
+ {
+#warning finish
+ state << indent(R"(value = static_cast<)") << op_enum_name
+ << indent(true, R"(>(words[word_index++]);
+)");
+ }
+ else
+ {
+ state << indent(
+ R"(static_assert(std::is_same<decltype(value), std::vector<Word> &>::value, "missing parse code for operand kind");
+value.clear();
+value.reserve(word_count - word_index);
+while(word_index < word_count)
+`value.push_back(words[word_index++]);
+)");
+ }
+ break;
+ }
+ }
+ push_indent.finish();
+ state << indent(R"(`return nullptr;
+}
+)");
+ }
+ for(auto &instruction : top_level.instructions.instructions)
{
+ auto struct_name = get_enumerant_name(op_enum_name, instruction.opname, true);
+ auto parse_function_name = get_parse_instruction_function_name(instruction.opname);
+ state
+ << indent(R"(static std::unique_ptr<Parse_error> )") << parse_function_name
+ << indent(
+ true,
+ R"((const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
+{
+`std::size_t word_index = 1; // skip opcode
+)");
auto push_indent2 = state.pushed_indent();
- state << indent(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 << struct_name << " instruction;\n";
+ if(!instruction.operands.empty())
+ state << indent("std::unique_ptr<Parse_error> parse_error;\n");
+ for(auto &operand : instruction.operands.operands)
+ {
+ auto parse_operand_function_name =
+ get_parse_operand_function_name(operand.kind);
+ auto member_name = get_member_name_from_operand(operand);
+ switch(operand.quantifier)
+ {
+ case ast::Instructions::Instruction::Operands::Operand::Quantifier::none:
+ {
+ state
+ << indent(R"(parse_error = )") << parse_operand_function_name
+ << indent(
+ true,
+ R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
+ << member_name << indent(true, R"();
+if(parse_error)
+`return parse_error;
+)");
+ break;
+ }
+ case ast::Instructions::Instruction::Operands::Operand::Quantifier::optional:
+ {
+ state
+ << indent(R"(if(word_index < word_count)
+{
+`instruction.)") << member_name
+ << indent(true, R"(.emplace();
+`parse_error = )") << parse_operand_function_name
+ << indent(
+ true,
+ R"((words, word_count, semantics, error_instruction_index, word_index, *instruction.)")
+ << member_name << indent(true, R"();
+`if(parse_error)
+``return parse_error;
+}
+)");
+ break;
+ }
+ case ast::Instructions::Instruction::Operands::Operand::Quantifier::variable:
+ {
+ state
+ << indent(R"(while(word_index < word_count)
+{
+`instruction.)") << member_name
+ << indent(true, R"(.emplace_back();
+`parse_error = )") << parse_operand_function_name
+ << indent(
+ true,
+ R"((words, word_count, semantics, error_instruction_index, word_index, instruction.)")
+ << member_name << indent(true, R"(.back());
+`if(parse_error)
+``return parse_error;
+}
+)");
+ }
+ }
+ }
+ push_indent2.finish();
+ state << indent(R"(`if(word_index < word_count)
+``return semantics.handle_error(error_instruction_index + word_index, error_instruction_index, "extra words at end of instruction");
+`semantics.handle_instruction(std::move(instruction));
+`return nullptr;
+}
)");
}
- state << indent("}\n");
+ state << indent(
+ R"(static std::unique_ptr<Parse_error> parse_instruction(const Word *words, std::size_t word_count, Semantics &semantics, std::size_t error_instruction_index)
+{
+`Op op = static_cast<Op>(words[0] & 0xFFFFU);
+`switch(op)
+`{
+)");
+ for(auto &instruction : top_level.instructions.instructions)
+ {
+ auto push_indent2 = state.pushed_indent(2);
+ auto enumerant_name = get_enumerant_name(op_enum_name, instruction.opname, true);
+ auto parse_function_name = get_parse_instruction_function_name(instruction.opname);
+ state << indent("case ") << op_enum_name << "::" << enumerant_name
+ << indent(true, R"(:
+`return )") << parse_function_name
+ << indent(true, R"((words, word_count, semantics, error_instruction_index);
+)");
+ }
+ state << indent(R"(`}
+`return semantics.handle_error(error_instruction_index, error_instruction_index, json::ast::Number_value::append_unsigned_integer_to_string(static_cast<Word>(op), "unknown instruction: 0x", 0x10));
+}
+
+static std::unique_ptr<Parse_error> parse(const Word *words, std::size_t word_count, Semantics &semantics)
+{
+`std::size_t word_index = 0;
+`if(word_index >= word_count)
+``return semantics.handle_error(word_index, 0, "hit EOF when parsing magic number");
+`if(words[word_index] != magic_number)
+``return semantics.handle_error(word_index, 0, "invalid magic number");
+`word_index++;
+`if(word_index >= word_count)
+``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V version");
+`if(words[word_index] & ~0xFFFF00UL)
+``return semantics.handle_error(word_index, 0, "invalid SPIR-V version");
+`auto input_major_version = words[word_index] >> 16;
+`auto input_minor_version = (words[word_index] >> 8) & 0xFFU;
+`semantics.handle_spirv_version(input_major_version, input_minor_version);
+`if(input_major_version != major_version || input_minor_version > minor_version)
+``return semantics.handle_error(word_index, 0, "SPIR-V version not supported");
+`word_index++;
+`if(word_index >= word_count)
+``return semantics.handle_error(word_index, 0, "hit EOF when parsing generator's magic number");
+`semantics.handle_generator_magic_number(words[word_index++]);
+`if(word_index >= word_count)
+``return semantics.handle_error(word_index, 0, "hit EOF when parsing id bound");
+`semantics.handle_id_bound(words[word_index++]);
+`if(word_index >= word_count)
+``return semantics.handle_error(word_index, 0, "hit EOF when parsing SPIR-V shader header");
+`if(words[word_index] != 0)
+``return semantics.handle_error(word_index, 0, "nonzero reserved word in SPIR-V shader header");
+`word_index++;
+`// now we've finished reading the shader header, the rest of the shader is just instructions
+`while(word_index < word_count)
+`{
+``auto instruction_word_count = words[word_index] >> 16;
+``if(instruction_word_count == 0)
+```return semantics.handle_error(word_index, word_index, "invalid instruction");
+``if(word_index + instruction_word_count > word_count)
+```return semantics.handle_error(word_index, word_index, "instruction longer than rest of shader");
+``auto parse_error = parse_instruction(words + word_index, instruction_word_count, semantics, word_index);
+``if(parse_error)
+```return parse_error;
+``word_index += instruction_word_count;
+`}
+`return nullptr;
+}
+)");
#warning finish
}
state << "};\n";
}
virtual void run(Generator_args &generator_args, const ast::Top_level &top_level) const override
{
- Generator_state state(this, generator_args);
+ Generator_state state(this, generator_args, top_level);
state.open_output_file();
write_file_comments(state, top_level.copyright);
state << "#include \"parser.h\"\n"
+ "#include <type_traits>\n"
"\n";
write_namespaces_start(state, spirv_namespace_names);
state << indent(R"(namespace
}
}
-std::unique_ptr<Parse_error> Parse_dump::handle_error(std::size_t word_index, std::string message)
+std::unique_ptr<Parse_error> Parse_dump::handle_error(std::size_t word_index, std::size_t instruction_word_index, std::string message)
{
-`return std::unique_ptr<Parse_error>(new Parse_error(word_index, std::move(message)));
+`return std::unique_ptr<Parse_error>(new Parse_error(word_index, instruction_word_index, std::move(message)));
+}
+
+void Parse_dump::handle_spirv_version(unsigned major, unsigned minor)
+{
+`os << "SPIR-V version " << major << "." << minor << "\n";
+}
+
+void Parse_dump::handle_generator_magic_number(Word value)
+{
+`os << "generator magic number: " << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10) << "\n";
+}
+
+void Parse_dump::handle_id_bound(Word id_bound)
+{
+`os << "id bound: " << json::ast::Number_value::unsigned_integer_to_string(id_bound) << "\n";
}
)");
for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
{
auto dump_function_name =
- Parser_header_generator::get_dump_function_name(operand_kind.kind);
+ Parser_header_generator::get_dump_operand_function_name(operand_kind.kind);
{
state << indent(R"(
void Parse_dump::)") << dump_function_name
{
case ast::Operand_kinds::Operand_kind::Category::bit_enum:
{
- auto &enumerants =
- util::get<ast::Operand_kinds::Operand_kind::Enumerants>(operand_kind.value);
-#warning finish
+ state << indent(R"(Word bits = static_cast<Word>(v);
+util::Enum_set<)") << operand_kind.kind
+ << indent(true, R"(> enum_set{};
+for(auto value : util::Enum_traits<)")
+ << operand_kind.kind << indent(true, R"(>::values)
+{
+`if(static_cast<Word>(value) == 0)
+`{
+``if(v == value)
+```enum_set.insert(value);
+``continue;
+`}
+`if((bits & static_cast<Word>(value)) == static_cast<Word>(value))
+`{
+``bits &= ~static_cast<Word>(value);
+``enum_set.insert(value);
+`}
+}
+bool first = true;
+for(auto value : enum_set)
+{
+`if(first)
+``first = false;
+`else
+``os << " | ";
+`os << get_enumerant_name(value);
+}
+if(bits)
+{
+`if(!first)
+``os << " | ";
+`os << json::ast::Number_value::append_unsigned_integer_to_string(bits, "0x", 0x10);
+}
+else if(first)
+{
+`os << "0";
+}
+)");
break;
}
case ast::Operand_kinds::Operand_kind::Category::value_enum:
{
-#warning finish
+ state << indent(R"(if(util::Enum_traits<)") << operand_kind.kind
+ << indent(true, R"(>::find_value(v) == util::Enum_traits<)")
+ << operand_kind.kind << indent(true, R"(>::npos)
+`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(v));
+else
+`os << get_enumerant_name(v);
+)");
break;
}
case ast::Operand_kinds::Operand_kind::Category::composite:
{
-#warning finish
+ auto &bases =
+ util::get<ast::Operand_kinds::Operand_kind::Bases>(operand_kind.value);
+ state << indent("os << \"{\";\n");
+ for(std::size_t i = 0; i < bases.values.size(); i++)
+ {
+ if(i != 0)
+ {
+ state << indent("os << \", \";\n");
+ }
+ state << indent << Parser_header_generator::get_dump_operand_function_name(
+ bases.values[i])
+ << "(v."
+ << json::ast::Number_value::append_unsigned_integer_to_string(i + 1,
+ "part_")
+ << ");\n";
+ }
+ state << indent("os << \"}\";\n");
break;
}
case ast::Operand_kinds::Operand_kind::Category::id:
{
-#warning finish
+ state << indent(
+ R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "#");
+)");
break;
}
case ast::Operand_kinds::Operand_kind::Category::literal:
{
-#warning finish
+ if(operand_kind.kind == "LiteralInteger")
+ {
+ state << indent(
+ R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x");
+)");
+ }
+ else if(operand_kind.kind == "LiteralExtInstInteger")
+ {
+ state << indent(
+ R"(os << json::ast::Number_value::append_unsigned_integer_to_string(v, "0x");
+)");
+ }
+ else if(operand_kind.kind == "LiteralString")
+ {
+ state << indent(
+ R"(json::ast::String_value::write(os, v);
+)");
+ }
+ else if(operand_kind.kind == "LiteralSpecConstantOpInteger")
+ {
+ state << indent(R"(if(util::Enum_traits<)") << op_enum_name
+ << indent(true, R"(>::find_value(v) == util::Enum_traits<)")
+ << op_enum_name << indent(true, R"(>::npos)
+`os << json::ast::Number_value::unsigned_integer_to_string(static_cast<Word>(v));
+else
+`os << get_enumerant_name(v);
+)");
+ }
+ else
+ {
+ state << indent(
+ R"(static_assert(std::is_same<decltype(v), const std::vector<Word> &>::value, "missing dump code for operand kind");
+auto separator = "";
+os << "{";
+for(Word value : v)
+{
+`os << separator;
+`separator = ", ";
+`os << json::ast::Number_value::append_unsigned_integer_to_string(value, "0x", 0x10, 8);
+}
+os << "}";
+)");
+ }
break;
}
}
`os << "}";
}
)");
-#warning finish
}
for(auto &instruction : top_level.instructions.instructions)
{
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 << Parser_header_generator::get_dump_operand_function_name(operand.kind)
<< indent(true, R"((instruction.)") << member_name << indent(true, R"();
os << "\n";
)");