/.metadata/
-/build/src/
-/build/CMakeFiles/
+/build/
cmake_install.cmake
CMakeCache.txt
Makefile
/.settings/
/test-files/test.spv
-/build/compile_commands.json
+out.json
{
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
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));
}
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));
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));
json::ast::Value to_json() const;
};
+struct Capabilities
+{
+ std::vector<std::string> capabilities;
+ Capabilities() : capabilities()
+ {
+ }
+ explicit Capabilities(std::vector<std::string> capabilities) noexcept
+ : capabilities(std::move(capabilities))
+ {
+ }
+ bool empty() const noexcept
+ {
+ return capabilities.empty();
+ }
+ json::ast::Value to_json() const;
+};
+
+struct Extensions
+{
+ std::vector<std::string> extensions;
+ Extensions() : extensions()
+ {
+ }
+ explicit Extensions(std::vector<std::string> 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<Operand> operands;
+ Operands() : operands()
+ {
+ }
+ explicit Operands(std::vector<Operand> 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<Instruction> instructions;
+ explicit Instructions(std::vector<Instruction> instructions) noexcept
+ : instructions(std::move(instructions))
+ {
+ }
json::ast::Value to_json() const;
};
}
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<Parameter> parameters;
+ Parameters() : parameters()
+ {
+ }
+ explicit Parameters(std::vector<Parameter> 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<Enumerant> enumerants;
explicit Enumerants(std::vector<Enumerant> 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
{
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
{
return "bases";
}
std::vector<std::string> values;
+ Bases() = default;
+ explicit Bases(std::vector<std::string> 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<Enumerants, Doc, Bases> Value;
Value value;
}
return "";
}
-#warning finish
Operand_kind(Category category, std::string kind, Value value) noexcept
: category(category),
kind(kind),
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;
#include "../util/optional.h"
#include <sstream>
#include <limits>
+#include <iostream>
+#include <cstdlib>
namespace vulkan_cpu
{
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(
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(),
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<std::string> capabilities;
+ capabilities.reserve(capabilities_array.values.size());
+ for(std::size_t index = 0; index < capabilities_array.values.size(); index++)
+ {
+ Path_builder<std::size_t> 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<std::string> extensions;
+ extensions.reserve(extensions_array.values.size());
+ for(std::size_t index = 0; index < extensions_array.values.size(); index++)
+ {
+ Path_builder<std::size_t> 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<std::string> 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<ast::Operand_kinds::Operand_kind::Enumerants::Enumerant::Parameters::Parameter>
+ parameters;
+ parameters.reserve(parameters_array.values.size());
+ for(std::size_t index = 0; index < parameters_array.values.size(); index++)
+ {
+ Path_builder<std::size_t> 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<void>(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<std::uint32_t>(
+ entry_value, path_builder, value_name, 1, 8);
+ return parse_integer<std::uint32_t>(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<std::string> 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(
{
Path_builder<std::size_t> 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));
}
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:
{
"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;
}
}
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<std::string> 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<ast::Instructions::Instruction::Operands::Operand::
+ Quantifier,
+ ast::Instructions::Instruction::Operands::Operand::
+ get_quantifier_string,
+ ast::Instructions::Instruction::Operands::Operand::
+ Quantifier::none,
+ ast::Instructions::Instruction::Operands::Operand::
+ Quantifier::optional,
+ ast::Instructions::Instruction::Operands::Operand::
+ Quantifier::variable>);
+ }
+ 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<ast::Instructions::Instruction::Operands::Operand> operands;
+ operands.reserve(operands_array.values.size());
+ for(std::size_t index = 0; index < operands_array.values.size(); index++)
+ {
+ Path_builder<std::size_t> 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::uint32_t>(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<std::string> 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)
{
throw Parse_error(
value.location, parent_path_builder->path(), "instructions is not an array");
auto &instructions_array = value.get_array();
- static_cast<void>(instructions_array);
-#warning finish
- return ast::Instructions();
+ std::vector<ast::Instructions::Instruction> instructions;
+ instructions.reserve(instructions_array.values.size());
+ for(std::size_t index = 0; index < instructions_array.values.size(); index++)
+ {
+ Path_builder<std::size_t> 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));
}
}
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<std::size_t> path_builder(&path_index, nullptr);
+ std::cout << parse_hex_integer_string<std::uint32_t>(
+ 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
*
*/
#include "json.h"
-#include <istream>
-#include <ostream>
+#include <iostream>
+#include <cstdlib>
#include <cmath>
#include <cstdint>
#include <cassert>
os << ']';
}
}
+
+util::optional<Difference> Difference::find_difference(const ast::Value &a, const ast::Value &b)
+{
+ util::optional<Difference> 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<util::variant<std::size_t, std::string>>{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<util::variant<std::size_t, std::string>>{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
}
}
#include <limits>
#include <type_traits>
#include <cassert>
+#include <cmath>
+#include <list>
#include "../util/variant.h"
+#include "../util/optional.h"
#include "location.h"
namespace vulkan_cpu
{
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
{
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
{
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
{
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<Composite_value> value;
public:
- constexpr Composite_value_pointer() noexcept = default;
+ constexpr Composite_value_reference() noexcept = default;
template <typename T,
typename = typename std::enable_if<std::is_base_of<Composite_value, T>::value>::type>
- Composite_value_pointer(std::shared_ptr<T> value) noexcept : value(std::move(value))
+ Composite_value_reference(std::shared_ptr<T> value) noexcept : value(std::move(value))
{
}
Composite_value *operator->() const noexcept
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;
struct Value
{
Location location;
- util::variant<Null_value, Boolean_value, String_value, Number_value, Composite_value_pointer>
+ util::variant<Null_value, Boolean_value, String_value, Number_value, Composite_value_reference>
value;
constexpr 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))
{
}
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
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(
{
}
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<std::string, Value> new_values;
for(auto &entry : values)
{
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<const Object *>(&rt))
+ return operator==(static_cast<const Object &>(rt));
+ return false;
+ }
};
inline Object &Value::get_object()
{
- return dynamic_cast<Object &>(*util::get<Composite_value_pointer>(value));
+ return dynamic_cast<Object &>(*util::get<Composite_value_reference>(value));
}
inline const Object &Value::get_object() const
{
- return dynamic_cast<const Object &>(*util::get<Composite_value_pointer>(value));
+ return dynamic_cast<const Object &>(*util::get<Composite_value_reference>(value));
}
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<Value> new_values;
new_values.reserve(values.size());
{
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<const Array *>(&rt))
+ return operator==(static_cast<const Array &>(rt));
+ return false;
+ }
};
inline Array &Value::get_array()
{
- return dynamic_cast<Array &>(*util::get<Composite_value_pointer>(value));
+ return dynamic_cast<Array &>(*util::get<Composite_value_reference>(value));
}
inline const Array &Value::get_array() const
{
- return dynamic_cast<const Array &>(*util::get<Composite_value_pointer>(value));
+ return dynamic_cast<const Array &>(*util::get<Composite_value_reference>(value));
}
inline Value_kind Value::get_value_kind() const noexcept
Write_state state(std::move(options));
write(os, v, state);
}
+
+struct Difference
+{
+ std::list<util::variant<std::size_t, std::string>> element_selectors;
+ Difference() noexcept = default;
+ explicit Difference(
+ std::list<util::variant<std::size_t, std::string>> 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<std::size_t>(element_selector))
+ {
+ buffer = ast::Number_value::append_unsigned_integer_to_string(
+ util::get<std::size_t>(element_selector), std::move(buffer) + '[')
+ + ']';
+ }
+ else
+ {
+ buffer += "[\"";
+ buffer += util::get<std::string>(element_selector);
+ buffer += "\"]";
+ }
+ }
+ return buffer;
+ }
+ std::string to_string() const
+ {
+ return append_to_string({});
+ }
+ static util::optional<Difference> find_difference(const ast::Value &a, const ast::Value &b);
+};
}
}
#
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} $<TARGET_FILE:generate_spirv_parser> ${spirv_core_grammar_json}
- MAIN_DEPENDENCY ${spirv_core_grammar_json}
- DEPENDS $<TARGET_FILE:generate_spirv_parser>
- 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} $<TARGET_FILE:generate_spirv_parser> ${spirv_core_grammar_json}
+ MAIN_DEPENDENCY ${spirv_core_grammar_json}
+ DEPENDS $<TARGET_FILE:generate_spirv_parser>
+ 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