From 1158fde8e9b75b730b8b27f42e8b3386293ea617 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 5 Jun 2017 03:24:05 -0700 Subject: [PATCH] creating ast from json ast works --- .gitignore | 5 +- src/generate_spirv_parser/ast.cpp | 113 +++++- src/generate_spirv_parser/ast.h | 174 ++++++++- .../generate_spirv_parser.cpp | 16 +- src/generate_spirv_parser/parser.cpp | 349 +++++++++++++++++- src/json/json.cpp | 116 +++++- src/json/json.h | 146 +++++++- src/spirv/CMakeLists.txt | 35 +- 8 files changed, 886 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index 35e14f9..11f41ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ /.metadata/ -/build/src/ -/build/CMakeFiles/ +/build/ cmake_install.cmake CMakeCache.txt Makefile /.settings/ /test-files/test.spv -/build/compile_commands.json +out.json diff --git a/src/generate_spirv_parser/ast.cpp b/src/generate_spirv_parser/ast.cpp index e80b9ca..eb17bb3 100644 --- a/src/generate_spirv_parser/ast.cpp +++ b/src/generate_spirv_parser/ast.cpp @@ -30,9 +30,10 @@ namespace ast { namespace { -std::string to_hex_string(std::uint32_t v) +std::string to_hex_string(std::uint32_t v, std::size_t min_digit_count) { - return json::ast::Number_value::append_unsigned_integer_to_string(v, "0x", 0x10, 8); + return json::ast::Number_value::append_unsigned_integer_to_string( + v, "0x", 0x10, min_digit_count); } constexpr json::Location make_empty_location() noexcept @@ -52,26 +53,111 @@ json::ast::Value Copyright::to_json() const return json::ast::Value(make_empty_location(), std::move(retval)); } +json::ast::Value Instructions::Instruction::Operands::Operand::to_json() const +{ + json::ast::Object retval; + retval.values["kind"] = json::ast::Value(make_empty_location(), kind); + if(!name.empty()) + retval.values["name"] = json::ast::Value(make_empty_location(), name); + if(quantifier != Quantifier::none) + retval.values["quantifier"] = + json::ast::Value(make_empty_location(), get_quantifier_string(quantifier)); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value Instructions::Instruction::Operands::to_json() const +{ + json::ast::Array retval; + retval.values.reserve(operands.size()); + for(auto &operand : operands) + retval.values.push_back(operand.to_json()); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value Instructions::Instruction::to_json() const +{ + json::ast::Object retval; + retval.values["opname"] = json::ast::Value(make_empty_location(), opname); + retval.values["opcode"] = json::ast::Value(make_empty_location(), opcode); + if(!operands.empty()) + retval.values["operands"] = operands.to_json(); + if(!capabilities.empty()) + retval.values["capabilities"] = capabilities.to_json(); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + json::ast::Value Instructions::to_json() const { json::ast::Array retval; -#warning finish + retval.values.reserve(instructions.size()); + for(auto &instruction : instructions) + retval.values.push_back(instruction.to_json()); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value Capabilities::to_json() const +{ + json::ast::Array retval; + retval.values.reserve(capabilities.size()); + for(auto &capability : capabilities) + retval.values.push_back(json::ast::Value(make_empty_location(), capability)); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value Extensions::to_json() const +{ + json::ast::Array retval; + retval.values.reserve(extensions.size()); + for(auto &extension : extensions) + retval.values.push_back(json::ast::Value(make_empty_location(), extension)); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value + Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter::to_json() const +{ + json::ast::Object retval; + retval.values["kind"] = json::ast::Value(make_empty_location(), kind); + if(!name.empty()) + retval.values["name"] = json::ast::Value(make_empty_location(), name); + return json::ast::Value(make_empty_location(), std::move(retval)); +} + +json::ast::Value Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::to_json() const +{ + json::ast::Array retval; + retval.values.reserve(parameters.size()); + for(auto ¶meter : parameters) + retval.values.push_back(parameter.to_json()); return json::ast::Value(make_empty_location(), std::move(retval)); } -json::ast::Value Operand_kinds::Operand_kind::Enumerants::Enumerant::to_json() const +json::ast::Value Operand_kinds::Operand_kind::Enumerants::Enumerant::to_json( + bool is_bit_enumerant) const { json::ast::Object retval; -#warning finish + retval.values["enumerant"] = json::ast::Value(make_empty_location(), enumerant); + json::ast::Value value_out; + if(is_bit_enumerant) + value_out = json::ast::Value(make_empty_location(), to_hex_string(value, 4)); + else + value_out = json::ast::Value(make_empty_location(), value); + retval.values["value"] = value_out; + if(!capabilities.empty()) + retval.values["capabilities"] = capabilities.to_json(); + if(!parameters.empty()) + retval.values["parameters"] = parameters.to_json(); + if(!extensions.empty()) + retval.values["extensions"] = extensions.to_json(); return json::ast::Value(make_empty_location(), std::move(retval)); } -json::ast::Value Operand_kinds::Operand_kind::Enumerants::to_json() const +json::ast::Value Operand_kinds::Operand_kind::Enumerants::to_json(bool is_bit_enumerant) const { json::ast::Array retval; retval.values.reserve(enumerants.size()); for(auto &enumerant : enumerants) - retval.values.push_back(enumerant.to_json()); + retval.values.push_back(enumerant.to_json(is_bit_enumerant)); return json::ast::Value(make_empty_location(), std::move(retval)); } @@ -98,7 +184,7 @@ json::ast::Value Operand_kinds::Operand_kind::to_json() const retval.values[get_value_json_key_name_from_category(category)] = util::visit( [&](auto &v) -> json::ast::Value { - return v.to_json(); + return v.to_json(category); }, value); return json::ast::Value(make_empty_location(), std::move(retval)); @@ -118,13 +204,10 @@ json::ast::Value Top_level::to_json() const json::ast::Object retval; retval.values["copyright"] = copyright.to_json(); retval.values["magic_number"] = - json::ast::Value(make_empty_location(), to_hex_string(magic_number)); - retval.values["major_version"] = json::ast::Value( - make_empty_location(), json::ast::Number_value::unsigned_integer_to_string(major_version)); - retval.values["minor_version"] = json::ast::Value( - make_empty_location(), json::ast::Number_value::unsigned_integer_to_string(minor_version)); - retval.values["revision"] = json::ast::Value( - make_empty_location(), json::ast::Number_value::unsigned_integer_to_string(revision)); + json::ast::Value(make_empty_location(), to_hex_string(magic_number, 8)); + retval.values["major_version"] = json::ast::Value(make_empty_location(), major_version); + retval.values["minor_version"] = json::ast::Value(make_empty_location(), minor_version); + retval.values["revision"] = json::ast::Value(make_empty_location(), revision); retval.values["instructions"] = instructions.to_json(); retval.values["operand_kinds"] = operand_kinds.to_json(); return json::ast::Value(make_empty_location(), std::move(retval)); diff --git a/src/generate_spirv_parser/ast.h b/src/generate_spirv_parser/ast.h index 6c9d044..f9d988e 100644 --- a/src/generate_spirv_parser/ast.h +++ b/src/generate_spirv_parser/ast.h @@ -47,9 +47,112 @@ struct Copyright json::ast::Value to_json() const; }; +struct Capabilities +{ + std::vector capabilities; + Capabilities() : capabilities() + { + } + explicit Capabilities(std::vector capabilities) noexcept + : capabilities(std::move(capabilities)) + { + } + bool empty() const noexcept + { + return capabilities.empty(); + } + json::ast::Value to_json() const; +}; + +struct Extensions +{ + std::vector extensions; + Extensions() : extensions() + { + } + explicit Extensions(std::vector extensions) noexcept + : extensions(std::move(extensions)) + { + } + bool empty() const noexcept + { + return extensions.empty(); + } + json::ast::Value to_json() const; +}; + struct Instructions { -#warning finish + struct Instruction + { + struct Operands + { + struct Operand + { + enum class Quantifier + { + none, + optional, + variable, + }; + static constexpr const char *get_quantifier_string(Quantifier quantifier) noexcept + { + switch(quantifier) + { + case Quantifier::none: + return ""; + case Quantifier::optional: + return "?"; + case Quantifier::variable: + return "*"; + } + return ""; + } + std::string kind; + std::string name; + Quantifier quantifier; + Operand(std::string kind, std::string name, Quantifier quantifier) noexcept + : kind(std::move(kind)), + name(std::move(name)), + quantifier(quantifier) + { + } + json::ast::Value to_json() const; + }; + std::vector operands; + Operands() : operands() + { + } + explicit Operands(std::vector operands) noexcept + : operands(std::move(operands)) + { + } + bool empty() const noexcept + { + return operands.empty(); + } + json::ast::Value to_json() const; + }; + std::string opname; + std::uint32_t opcode; + Operands operands; + Capabilities capabilities; + Instruction(std::string opname, + std::uint32_t opcode, + Operands operands, + Capabilities capabilities) noexcept : opname(std::move(opname)), + opcode(opcode), + operands(std::move(operands)), + capabilities(std::move(capabilities)) + { + } + json::ast::Value to_json() const; + }; + std::vector instructions; + explicit Instructions(std::vector instructions) noexcept + : instructions(std::move(instructions)) + { + } json::ast::Value to_json() const; }; @@ -92,14 +195,60 @@ struct Operand_kinds } struct Enumerant { -#warning finish - json::ast::Value to_json() const; + std::string enumerant; + std::uint32_t value; + Capabilities capabilities; + struct Parameters + { + struct Parameter + { + std::string kind; + std::string name; + explicit Parameter(std::string kind, std::string name) noexcept + : kind(std::move(kind)), + name(std::move(name)) + { + } + json::ast::Value to_json() const; + }; + std::vector parameters; + Parameters() : parameters() + { + } + explicit Parameters(std::vector parameters) noexcept + : parameters(std::move(parameters)) + { + } + json::ast::Value to_json() const; + bool empty() const noexcept + { + return parameters.empty(); + } + }; + Parameters parameters; + Extensions extensions; + Enumerant(std::string enumerant, + std::uint32_t value, + Capabilities capabilities, + Parameters parameters, + Extensions extensions) noexcept : enumerant(std::move(enumerant)), + value(value), + capabilities(std::move(capabilities)), + parameters(std::move(parameters)), + extensions(std::move(extensions)) + { + } + json::ast::Value to_json(bool is_bit_enumerant) const; }; std::vector enumerants; explicit Enumerants(std::vector enumerants) noexcept : enumerants(enumerants) { } - json::ast::Value to_json() const; + json::ast::Value to_json(bool is_bit_enumerant) const; + json::ast::Value to_json(Category category) const + { + return to_json(category == Category::bit_enum); + } }; struct Doc { @@ -108,7 +257,15 @@ struct Operand_kinds return "doc"; } std::string value; + Doc() = default; + explicit Doc(std::string value) noexcept : value(std::move(value)) + { + } json::ast::Value to_json() const; + json::ast::Value to_json(Category category) const + { + return to_json(); + } }; struct Bases { @@ -117,7 +274,15 @@ struct Operand_kinds return "bases"; } std::vector values; + Bases() = default; + explicit Bases(std::vector values) noexcept : values(std::move(values)) + { + } json::ast::Value to_json() const; + json::ast::Value to_json(Category category) const + { + return to_json(); + } }; typedef util::variant Value; Value value; @@ -152,7 +317,6 @@ struct Operand_kinds } return ""; } -#warning finish Operand_kind(Category category, std::string kind, Value value) noexcept : category(category), kind(kind), diff --git a/src/generate_spirv_parser/generate_spirv_parser.cpp b/src/generate_spirv_parser/generate_spirv_parser.cpp index 3bfb0eb..01d014a 100644 --- a/src/generate_spirv_parser/generate_spirv_parser.cpp +++ b/src/generate_spirv_parser/generate_spirv_parser.cpp @@ -47,9 +47,21 @@ int generate_spirv_parser_main(int argc, char **argv) json::Source::load_file(std::move(file_name)); try { - auto ast = parser::parse(json::parse(&source)); + auto json_in = json::parse(&source); + auto ast = parser::parse(json_in.duplicate()); std::ofstream os("out.json"); - json::write(os, ast.to_json(), json::Write_options::pretty()); + auto json_out = ast.to_json(); + json::write(os, json_out, json::Write_options::pretty()); + os.close(); + auto difference = json::Difference::find_difference(json_in, json_out); + if(difference) + { + std::cerr << "differs at " << difference->append_to_string("root") << std::endl; + } + else + { + std::cerr << "no difference" << std::endl; + } #warning finish std::cerr << "generate_spirv_parser is not finished being implemented" << std::endl; return 1; diff --git a/src/generate_spirv_parser/parser.cpp b/src/generate_spirv_parser/parser.cpp index 2672816..5b7871c 100644 --- a/src/generate_spirv_parser/parser.cpp +++ b/src/generate_spirv_parser/parser.cpp @@ -24,6 +24,8 @@ #include "../util/optional.h" #include #include +#include +#include namespace vulkan_cpu { @@ -226,7 +228,8 @@ Enum parse_enum_string(const json::ast::Value &value, std::string parse_identifier_string(json::ast::Value value, const Path_builder_base *parent_path_builder, - const char *name) + const char *name, + bool can_start_with_digit = false) { if(value.get_value_kind() != json::ast::Value_kind::string) throw Parse_error( @@ -236,7 +239,7 @@ std::string parse_identifier_string(json::ast::Value value, throw Parse_error(value.location, parent_path_builder->path(), std::string(name) + " must not be an empty string"); - if(!is_identifier_start(string_value.value[0])) + if(!can_start_with_digit && !is_identifier_start(string_value.value[0])) throw Parse_error( value.location, parent_path_builder->path(), @@ -272,21 +275,174 @@ ast::Copyright parse_copyright(json::ast::Value value, const Path_builder_base * return ast::Copyright(std::move(lines)); } +ast::Capabilities parse_capabilities(json::ast::Value value, + const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::array) + throw Parse_error( + value.location, parent_path_builder->path(), "capabilities is not an array"); + auto &capabilities_array = value.get_array(); + std::vector capabilities; + capabilities.reserve(capabilities_array.values.size()); + for(std::size_t index = 0; index < capabilities_array.values.size(); index++) + { + Path_builder path_builder(&index, parent_path_builder); + auto &element = capabilities_array.values[index]; + capabilities.push_back( + parse_identifier_string(std::move(element), &path_builder, "capabilities")); + } + return ast::Capabilities(std::move(capabilities)); +} + +ast::Extensions parse_extensions(json::ast::Value value, + const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::array) + throw Parse_error( + value.location, parent_path_builder->path(), "extensions is not an array"); + auto &extensions_array = value.get_array(); + std::vector extensions; + extensions.reserve(extensions_array.values.size()); + for(std::size_t index = 0; index < extensions_array.values.size(); index++) + { + Path_builder path_builder(&index, parent_path_builder); + auto &element = extensions_array.values[index]; + extensions.push_back( + parse_identifier_string(std::move(element), &path_builder, "extensions")); + } + return ast::Extensions(std::move(extensions)); +} + +ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter + parse_operand_kinds_operand_kind_enumerants_enumerant_parameters_parameter( + json::ast::Value value, const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::object) + throw Parse_error( + value.location, parent_path_builder->path(), "parameter is not an object"); + auto ¶meter_object = value.get_object(); + constexpr auto kind_name = "kind"; + std::string kind = get_object_member_or_throw_parse_error( + value.location, + parameter_object, + parent_path_builder, + kind_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) + { + return parse_identifier_string(std::move(entry_value), path_builder, kind_name); + }); + std::string name = ""; + for(auto &entry : parameter_object.values) + { + const auto &key = std::get<0>(entry); + auto &entry_value = std::get<1>(entry); + Path_builder path_builder(&key, parent_path_builder); + if(key == "name") + { + if(entry_value.get_value_kind() != json::ast::Value_kind::string) + throw Parse_error( + entry_value.location, path_builder.path(), "name is not a string"); + name = std::move(entry_value.get_string().value); + } + else if(key != kind_name) + { + throw Parse_error(entry_value.location, path_builder.path(), "unknown key"); + } + } + return ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter( + std::move(kind), std::move(name)); +} + +ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters + parse_operand_kinds_operand_kind_enumerants_enumerant_parameters( + json::ast::Value value, const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::array) + throw Parse_error( + value.location, parent_path_builder->path(), "parameters is not an array"); + auto ¶meters_array = value.get_array(); + std::vector + parameters; + parameters.reserve(parameters_array.values.size()); + for(std::size_t index = 0; index < parameters_array.values.size(); index++) + { + Path_builder path_builder(&index, parent_path_builder); + auto &element = parameters_array.values[index]; + parameters.push_back( + parse_operand_kinds_operand_kind_enumerants_enumerant_parameters_parameter( + std::move(element), &path_builder)); + } + return ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters( + std::move(parameters)); +} + ast::Operand_kinds::Operand_kind::Enumerants::Enumerant parse_operand_kinds_operand_kind_enumerants_enumerant( - json::ast::Value value, const Path_builder_base *parent_path_builder) + json::ast::Value value, const Path_builder_base *parent_path_builder, bool is_bit_enumerant) { if(value.get_value_kind() != json::ast::Value_kind::object) throw Parse_error( value.location, parent_path_builder->path(), "enumerant is not an object"); auto &enumerant_object = value.get_object(); - static_cast(enumerant_object); -#warning finish - return ast::Operand_kinds::Operand_kind::Enumerants::Enumerant(); + constexpr auto enumerant_name = "enumerant"; + std::string enumerant = get_object_member_or_throw_parse_error( + value.location, + enumerant_object, + parent_path_builder, + enumerant_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) + { + return parse_identifier_string( + std::move(entry_value), path_builder, enumerant_name, true); + }); + constexpr auto value_name = "value"; + std::uint32_t enumerant_value = get_object_member_or_throw_parse_error( + value.location, + enumerant_object, + parent_path_builder, + value_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) -> std::uint32_t + { + if(is_bit_enumerant) + return parse_hex_integer_string( + entry_value, path_builder, value_name, 1, 8); + return parse_integer(entry_value, path_builder, value_name); + }); + ast::Capabilities capabilities; + ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters parameters; + ast::Extensions extensions; + for(auto &entry : enumerant_object.values) + { + const auto &key = std::get<0>(entry); + auto &entry_value = std::get<1>(entry); + Path_builder path_builder(&key, parent_path_builder); + if(key == "capabilities") + { + capabilities = parse_capabilities(std::move(entry_value), &path_builder); + } + else if(key == "parameters") + { + parameters = parse_operand_kinds_operand_kind_enumerants_enumerant_parameters( + std::move(entry_value), &path_builder); + } + else if(key == "extensions") + { + extensions = parse_extensions(std::move(entry_value), &path_builder); + } + else if(key != enumerant_name && key != value_name) + { + throw Parse_error(entry_value.location, path_builder.path(), "unknown key"); + } + } + return ast::Operand_kinds::Operand_kind::Enumerants::Enumerant(std::move(enumerant), + enumerant_value, + std::move(capabilities), + std::move(parameters), + std::move(extensions)); } ast::Operand_kinds::Operand_kind::Enumerants parse_operand_kinds_operand_kind_enumerants( - json::ast::Value value, const Path_builder_base *parent_path_builder) + json::ast::Value value, const Path_builder_base *parent_path_builder, bool is_bit_enumerant) { if(value.get_value_kind() != json::ast::Value_kind::array) throw Parse_error( @@ -298,7 +454,7 @@ ast::Operand_kinds::Operand_kind::Enumerants parse_operand_kinds_operand_kind_en { Path_builder path_builder(&index, parent_path_builder); enumerants.push_back(parse_operand_kinds_operand_kind_enumerants_enumerant( - std::move(enumerants_array.values[index]), &path_builder)); + std::move(enumerants_array.values[index]), &path_builder, is_bit_enumerant)); } return ast::Operand_kinds::Operand_kind::Enumerants(std::move(enumerants)); } @@ -354,15 +510,17 @@ ast::Operand_kinds::Operand_kind parse_operand_kinds_operand_kind( case ast::Operand_kinds::Operand_kind::Category::bit_enum: case ast::Operand_kinds::Operand_kind::Category::value_enum: operand_kind_value = parse_operand_kinds_operand_kind_enumerants( - std::move(entry_value), &path_builder); + std::move(entry_value), + &path_builder, + category == ast::Operand_kinds::Operand_kind::Category::bit_enum); break; case ast::Operand_kinds::Operand_kind::Category::id: case ast::Operand_kinds::Operand_kind::Category::literal: if(entry_value.get_value_kind() != json::ast::Value_kind::string) throw Parse_error( entry_value.location, path_builder.path(), "doc is not a string"); - operand_kind_value = ast::Operand_kinds::Operand_kind::Doc{ - std::move(entry_value.get_string().value)}; + operand_kind_value = ast::Operand_kinds::Operand_kind::Doc( + std::move(entry_value.get_string().value)); break; case ast::Operand_kinds::Operand_kind::Category::composite: { @@ -382,7 +540,7 @@ ast::Operand_kinds::Operand_kind parse_operand_kinds_operand_kind( "bases element is not a string"); bases.push_back(std::move(entry.get_string().value)); } - operand_kind_value = ast::Operand_kinds::Operand_kind::Bases{std::move(bases)}; + operand_kind_value = ast::Operand_kinds::Operand_kind::Bases(std::move(bases)); break; } } @@ -422,6 +580,131 @@ ast::Operand_kinds parse_operand_kinds(json::ast::Value value, return ast::Operand_kinds(std::move(operand_kinds)); } +ast::Instructions::Instruction::Operands::Operand parse_instructions_instruction_operands_operand( + json::ast::Value value, const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::object) + throw Parse_error(value.location, parent_path_builder->path(), "operand is not an object"); + auto &operand_object = value.get_object(); + constexpr auto kind_name = "kind"; + std::string kind = get_object_member_or_throw_parse_error( + value.location, + operand_object, + parent_path_builder, + kind_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) + { + return parse_identifier_string(std::move(entry_value), path_builder, kind_name); + }); + std::string name; + auto quantifier = ast::Instructions::Instruction::Operands::Operand::Quantifier::none; + for(auto &entry : operand_object.values) + { + const auto &key = std::get<0>(entry); + auto &entry_value = std::get<1>(entry); + Path_builder path_builder(&key, parent_path_builder); + if(key == "name") + { + if(entry_value.get_value_kind() != json::ast::Value_kind::string) + throw Parse_error( + entry_value.location, path_builder.path(), "name is not a string"); + name = std::move(entry_value.get_string().value); + } + else if(key == "quantifier") + { + quantifier = parse_enum_string( + std::move(entry_value), + &path_builder, + "quantifier", + make_enum_value_descriptors); + } + else if(key != kind_name) + { + throw Parse_error(entry_value.location, path_builder.path(), "unknown key"); + } + } + return ast::Instructions::Instruction::Operands::Operand( + std::move(kind), std::move(name), quantifier); +} + +ast::Instructions::Instruction::Operands parse_instructions_instruction_operands( + json::ast::Value value, const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::array) + throw Parse_error(value.location, parent_path_builder->path(), "operands is not an array"); + auto &operands_array = value.get_array(); + std::vector operands; + operands.reserve(operands_array.values.size()); + for(std::size_t index = 0; index < operands_array.values.size(); index++) + { + Path_builder path_builder(&index, parent_path_builder); + operands.push_back(parse_instructions_instruction_operands_operand( + std::move(operands_array.values[index]), &path_builder)); + } + return ast::Instructions::Instruction::Operands(std::move(operands)); +} + +ast::Instructions::Instruction parse_instructions_instruction( + json::ast::Value value, const Path_builder_base *parent_path_builder) +{ + if(value.get_value_kind() != json::ast::Value_kind::object) + throw Parse_error( + value.location, parent_path_builder->path(), "instruction is not an object"); + auto &instruction_object = value.get_object(); + constexpr auto opname_name = "opname"; + std::string opname = get_object_member_or_throw_parse_error( + value.location, + instruction_object, + parent_path_builder, + opname_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) + { + return parse_identifier_string(std::move(entry_value), path_builder, opname_name); + }); + constexpr auto opcode_name = "opcode"; + auto opcode = get_object_member_or_throw_parse_error( + value.location, + instruction_object, + parent_path_builder, + opcode_name, + [&](json::ast::Value &entry_value, const Path_builder_base *path_builder) + { + return parse_integer(std::move(entry_value), path_builder, opcode_name); + }); + ast::Instructions::Instruction::Operands operands; + ast::Capabilities capabilities; + for(auto &entry : instruction_object.values) + { + const auto &key = std::get<0>(entry); + auto &entry_value = std::get<1>(entry); + Path_builder path_builder(&key, parent_path_builder); + if(key == "operands") + { + operands = + parse_instructions_instruction_operands(std::move(entry_value), &path_builder); + } + else if(key == "capabilities") + { + capabilities = parse_capabilities(std::move(entry_value), &path_builder); + } + else if(key != opname_name && key != opcode_name) + { + throw Parse_error(entry_value.location, path_builder.path(), "unknown key"); + } + } + return ast::Instructions::Instruction( + std::move(opname), opcode, std::move(operands), std::move(capabilities)); +} + ast::Instructions parse_instructions(json::ast::Value value, const Path_builder_base *parent_path_builder) { @@ -429,9 +712,15 @@ ast::Instructions parse_instructions(json::ast::Value value, throw Parse_error( value.location, parent_path_builder->path(), "instructions is not an array"); auto &instructions_array = value.get_array(); - static_cast(instructions_array); -#warning finish - return ast::Instructions(); + std::vector instructions; + instructions.reserve(instructions_array.values.size()); + for(std::size_t index = 0; index < instructions_array.values.size(); index++) + { + Path_builder path_builder(&index, parent_path_builder); + instructions.push_back(parse_instructions_instruction( + std::move(instructions_array.values[index]), &path_builder)); + } + return ast::Instructions(std::move(instructions)); } } @@ -502,6 +791,36 @@ ast::Top_level parse(json::ast::Value &&top_level_value) get_value_or_throw_parse_error( std::move(operand_kinds), top_level_value.location, nullptr, "missing operand_kinds")); } + +#if 0 +namespace +{ +void test_fn() +{ + try + { + std::size_t path_index = 0; + Path_builder path_builder(&path_index, nullptr); + std::cout << parse_hex_integer_string( + json::ast::Value({}, "0x1234"), &path_builder, "test", 1, 8) + << std::endl; + } + catch(std::exception &e) + { + std::cout << e.what() << std::endl; + } +} + +struct Test +{ + Test() + { + test_fn(); + std::exit(0); + } +} test; +} +#endif } } } \ No newline at end of file diff --git a/src/json/json.cpp b/src/json/json.cpp index 2654676..1c41d79 100644 --- a/src/json/json.cpp +++ b/src/json/json.cpp @@ -21,8 +21,8 @@ * */ #include "json.h" -#include -#include +#include +#include #include #include #include @@ -560,5 +560,117 @@ void Array::write(std::ostream &os, Write_state &state) const os << ']'; } } + +util::optional Difference::find_difference(const ast::Value &a, const ast::Value &b) +{ + util::optional retval; + auto value_kind = a.get_value_kind(); + if(value_kind != b.get_value_kind()) + { + retval.emplace(); + } + else + { + switch(value_kind) + { + case ast::Value_kind::null: + // always equals + break; + case ast::Value_kind::boolean: + if(a.get_boolean() != b.get_boolean()) + retval.emplace(); + break; + case ast::Value_kind::string: + if(a.get_string() != b.get_string()) + retval.emplace(); + break; + case ast::Value_kind::number: + if(a.get_number() != b.get_number()) + retval.emplace(); + break; + case ast::Value_kind::object: + { + auto &object_a = a.get_object(); + auto &object_b = b.get_object(); + for(auto &object_a_entry : object_a.values) + { + auto &key = std::get<0>(object_a_entry); + auto object_b_iter = object_b.values.find(key); + if(object_b_iter == object_b.values.end()) + { + retval.emplace(std::list>{key}); + break; + } + auto &object_b_entry = *object_b_iter; + auto &object_a_value = std::get<1>(object_a_entry); + auto &object_b_value = std::get<1>(object_b_entry); + retval = find_difference(object_a_value, object_b_value); + if(retval) + { + retval->element_selectors.emplace_front(key); + break; + } + } + if(retval) + break; + for(auto &object_b_entry : object_b.values) + { + auto &key = std::get<0>(object_b_entry); + auto object_a_iter = object_a.values.find(key); + if(object_a_iter == object_a.values.end()) + { + retval.emplace(std::list>{key}); + break; + } + // already checked object_a_value vs. object_b_value + } + break; + } + case ast::Value_kind::array: + { + auto &array_a = a.get_array(); + auto &array_b = b.get_array(); + for(std::size_t i = 0; i < array_a.values.size() && i < array_b.values.size(); i++) + { + auto &array_a_entry = array_a.values[i]; + auto &array_b_entry = array_b.values[i]; + retval = find_difference(array_a_entry, array_b_entry); + if(retval) + { + retval->element_selectors.emplace_front(i); + break; + } + } + if(retval) + break; + if(array_a.values.size() < array_b.values.size()) + retval->element_selectors.emplace_front(array_a.values.size()); + else if(array_a.values.size() > array_b.values.size()) + retval->element_selectors.emplace_front(array_b.values.size()); + break; + } + } + } + return retval; +} + +#if 0 +namespace +{ +void test_fn() +{ + std::cout << ast::Number_value::unsigned_integer_to_string(0x1234U, {}, 0x10, 4) << std::endl; +} + +struct Test +{ + Test() + { + test_fn(); + std::exit(0); + } +} test; +} +#endif } } diff --git a/src/json/json.h b/src/json/json.h index 9350e18..7d9f4c0 100644 --- a/src/json/json.h +++ b/src/json/json.h @@ -33,7 +33,10 @@ #include #include #include +#include +#include #include "../util/variant.h" +#include "../util/optional.h" #include "location.h" namespace vulkan_cpu @@ -137,6 +140,14 @@ struct Null_value final { return Value_kind::null; } + friend constexpr bool operator==(const Null_value &, const Null_value &) noexcept + { + return true; + } + friend constexpr bool operator!=(const Null_value &, const Null_value &) noexcept + { + return false; + } }; struct Boolean_value final @@ -163,6 +174,14 @@ struct Boolean_value final { return Value_kind::boolean; } + friend constexpr bool operator==(const Boolean_value &a, const Boolean_value &b) noexcept + { + return a.value == b.value; + } + friend constexpr bool operator!=(const Boolean_value &a, const Boolean_value &b) noexcept + { + return !operator==(a, b); + } }; struct String_value final @@ -201,6 +220,14 @@ struct String_value final { return Value_kind::string; } + friend bool operator==(const String_value &a, const String_value &b) noexcept + { + return a.value == b.value; + } + friend bool operator!=(const String_value &a, const String_value &b) noexcept + { + return !operator==(a, b); + } }; struct Number_value final @@ -302,20 +329,28 @@ struct Number_value final { return Value_kind::number; } + friend bool operator==(const Number_value &a, const Number_value &b) noexcept + { + return a.value == b.value || (std::isnan(a.value) && std::isnan(b.value)); + } + friend bool operator!=(const Number_value &a, const Number_value &b) noexcept + { + return !operator==(a, b); + } }; struct Composite_value; -class Composite_value_pointer +class Composite_value_reference { private: std::shared_ptr value; public: - constexpr Composite_value_pointer() noexcept = default; + constexpr Composite_value_reference() noexcept = default; template ::value>::type> - Composite_value_pointer(std::shared_ptr value) noexcept : value(std::move(value)) + Composite_value_reference(std::shared_ptr value) noexcept : value(std::move(value)) { } Composite_value *operator->() const noexcept @@ -336,6 +371,13 @@ public: retval.swap(value); return retval; } + friend bool operator==(const Composite_value_reference &a, + const Composite_value_reference &b) noexcept; + friend bool operator!=(const Composite_value_reference &a, + const Composite_value_reference &b) noexcept + { + return !operator==(a, b); + } }; struct Object; @@ -344,7 +386,7 @@ struct Array; struct Value { Location location; - util::variant + util::variant value; constexpr Value() { @@ -365,7 +407,7 @@ struct Value : location(std::move(location)), value(std::move(value)) { } - explicit Value(Location location, Composite_value_pointer value) + explicit Value(Location location, Composite_value_reference value) : location(std::move(location)), value(std::move(value)) { } @@ -409,6 +451,14 @@ struct Value Array &get_array(); const Array &get_array() const; Value_kind get_value_kind() const noexcept; + friend bool operator==(const Value &a, const Value &b) noexcept + { + return a.value == b.value; + } + friend bool operator!=(const Value &a, const Value &b) noexcept + { + return !operator==(a, b); + } }; struct Composite_value @@ -416,10 +466,27 @@ struct Composite_value Composite_value() = default; virtual ~Composite_value() = default; virtual void write(std::ostream &os, Write_state &state) const = 0; - virtual Composite_value_pointer duplicate() const = 0; + virtual Composite_value_reference duplicate() const = 0; virtual Value_kind get_value_kind() const noexcept = 0; + virtual bool operator==(const Composite_value &rt) const noexcept = 0; + bool operator!=(const Composite_value &rt) const noexcept + { + return !operator==(rt); + } }; +/** returns true if a and b are structurally equal */ +inline bool operator==(const Composite_value_reference &a, + const Composite_value_reference &b) noexcept +{ + if(a.value == b.value) + return true; + if(!a.value || !b.value) + return false; + return *a.value == *b.value; +} + + inline Value Value::duplicate() const { return util::visit( @@ -440,7 +507,7 @@ struct Object final : public Composite_value { } virtual void write(std::ostream &os, Write_state &state) const override; - virtual Composite_value_pointer duplicate() const override + virtual Composite_value_reference duplicate() const override { std::unordered_map new_values; for(auto &entry : values) @@ -453,16 +520,26 @@ struct Object final : public Composite_value { return Value_kind::object; } + bool operator==(const Object &rt) const noexcept + { + return values == rt.values; + } + virtual bool operator==(const Composite_value &rt) const noexcept override + { + if(dynamic_cast(&rt)) + return operator==(static_cast(rt)); + return false; + } }; inline Object &Value::get_object() { - return dynamic_cast(*util::get(value)); + return dynamic_cast(*util::get(value)); } inline const Object &Value::get_object() const { - return dynamic_cast(*util::get(value)); + return dynamic_cast(*util::get(value)); } struct Array final : public Composite_value @@ -475,7 +552,7 @@ struct Array final : public Composite_value { } virtual void write(std::ostream &os, Write_state &state) const override; - virtual Composite_value_pointer duplicate() const override + virtual Composite_value_reference duplicate() const override { std::vector new_values; new_values.reserve(values.size()); @@ -487,16 +564,26 @@ struct Array final : public Composite_value { return Value_kind::array; } + bool operator==(const Array &rt) const noexcept + { + return values == rt.values; + } + virtual bool operator==(const Composite_value &rt) const noexcept override + { + if(dynamic_cast(&rt)) + return operator==(static_cast(rt)); + return false; + } }; inline Array &Value::get_array() { - return dynamic_cast(*util::get(value)); + return dynamic_cast(*util::get(value)); } inline const Array &Value::get_array() const { - return dynamic_cast(*util::get(value)); + return dynamic_cast(*util::get(value)); } inline Value_kind Value::get_value_kind() const noexcept @@ -535,6 +622,41 @@ inline void write(std::ostream &os, const ast::Value &v, Write_options options = Write_state state(std::move(options)); write(os, v, state); } + +struct Difference +{ + std::list> element_selectors; + Difference() noexcept = default; + explicit Difference( + std::list> element_selectors) noexcept + : element_selectors(std::move(element_selectors)) + { + } + std::string append_to_string(std::string buffer) const + { + for(auto &element_selector : element_selectors) + { + if(util::holds_alternative(element_selector)) + { + buffer = ast::Number_value::append_unsigned_integer_to_string( + util::get(element_selector), std::move(buffer) + '[') + + ']'; + } + else + { + buffer += "[\""; + buffer += util::get(element_selector); + buffer += "\"]"; + } + } + return buffer; + } + std::string to_string() const + { + return append_to_string({}); + } + static util::optional find_difference(const ast::Value &a, const ast::Value &b); +}; } } diff --git a/src/spirv/CMakeLists.txt b/src/spirv/CMakeLists.txt index 7f8ec70..95efade 100644 --- a/src/spirv/CMakeLists.txt +++ b/src/spirv/CMakeLists.txt @@ -20,21 +20,28 @@ # cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/src) -set(spirv_parser_generated_dir ${spirv_parser_generated_include_dir}/spirv) -set(spirv_parser_source ${spirv_parser_generated_dir}/parser.cpp) -set(spirv_parser_header ${spirv_parser_generated_dir}/parser.h) -set(spirv_core_grammar_json ${CMAKE_CURRENT_SOURCE_DIR}/../khronos-spirv/spirv.core.grammar.json) +set(do_generate_spirv_parser YES) -add_custom_command(OUTPUT ${spirv_parser_source} ${spirv_parser_header} - COMMAND ${CMAKE_COMMAND} -E make_directory ${spirv_parser_generated_dir} - COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_dir} $ ${spirv_core_grammar_json} - MAIN_DEPENDENCY ${spirv_core_grammar_json} - DEPENDS $ - VERBATIM - COMMENT "Generating SPIR-V Parser") +set(sources spirv.cpp) -set(sources spirv.cpp ${spirv_parser_source}) +if(${do_generate_spirv_parser}) + set(spirv_parser_generated_include_dir ${CMAKE_CURRENT_BINARY_DIR}/src) + set(spirv_parser_generated_dir ${spirv_parser_generated_include_dir}/spirv) + set(spirv_parser_source ${spirv_parser_generated_dir}/parser.cpp) + set(spirv_parser_header ${spirv_parser_generated_dir}/parser.h) + set(spirv_core_grammar_json ${CMAKE_CURRENT_SOURCE_DIR}/../khronos-spirv/spirv.core.grammar.json) + + add_custom_command(OUTPUT ${spirv_parser_source} ${spirv_parser_header} + COMMAND ${CMAKE_COMMAND} -E make_directory ${spirv_parser_generated_dir} + COMMAND ${CMAKE_COMMAND} -E chdir ${spirv_parser_generated_dir} $ ${spirv_core_grammar_json} + MAIN_DEPENDENCY ${spirv_core_grammar_json} + DEPENDS $ + VERBATIM + COMMENT "Generating SPIR-V Parser") + set(sources ${sources} ${spirv_parser_source}) +endif() add_library(spirv STATIC ${sources}) target_link_libraries(spirv util) -target_include_directories(spirv PUBLIC ${spirv_parser_generated_include_dir}) \ No newline at end of file +if(${do_generate_spirv_parser}) + target_include_directories(spirv PUBLIC ${spirv_parser_generated_include_dir}) +endif() \ No newline at end of file -- 2.30.2