creating ast from json ast works
authorJacob Lifshay <programmerjake@gmail.com>
Mon, 5 Jun 2017 10:24:05 +0000 (03:24 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Mon, 5 Jun 2017 10:24:05 +0000 (03:24 -0700)
.gitignore
src/generate_spirv_parser/ast.cpp
src/generate_spirv_parser/ast.h
src/generate_spirv_parser/generate_spirv_parser.cpp
src/generate_spirv_parser/parser.cpp
src/json/json.cpp
src/json/json.h
src/spirv/CMakeLists.txt

index 35e14f967bd217c93662d3cd329e219fb1a95465..11f41bafdede133e2e3402f51952461f781b7534 100644 (file)
@@ -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
index e80b9cacaa72ab866ef78d2c6a37616487f4611c..eb17bb3987c7e24ba075ab0f23fff238af92e8af 100644 (file)
@@ -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 &parameter : 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));
index 6c9d04483d3c774faebca4e14ed4a670300a714e..f9d988eeb1b83c2fa9426bb0181e72aea4a7decd 100644 (file)
@@ -47,9 +47,112 @@ struct Copyright
     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;
 };
 
@@ -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<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
         {
@@ -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<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;
@@ -152,7 +317,6 @@ struct Operand_kinds
             }
             return "";
         }
-#warning finish
         Operand_kind(Category category, std::string kind, Value value) noexcept
             : category(category),
               kind(kind),
index 3bfb0ebde520914622c4debe5cb2ccbf1351ebed..01d014af9c5227562410c28ecb2ae33305a970a8 100644 (file)
@@ -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;
index 267281699d89dee1c593641d5929aaad1be7849b..5b7871c2b5f97f77a5fbed4bdfdb12f0dacccf36 100644 (file)
@@ -24,6 +24,8 @@
 #include "../util/optional.h"
 #include <sstream>
 #include <limits>
+#include <iostream>
+#include <cstdlib>
 
 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<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 &parameter_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 &parameters_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(
@@ -298,7 +454,7 @@ ast::Operand_kinds::Operand_kind::Enumerants parse_operand_kinds_operand_kind_en
     {
         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));
 }
@@ -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<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)
 {
@@ -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<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));
 }
 }
 
@@ -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<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
index 26546760155606d109a9570698880f8c56377121..1c41d79964f9d2a978409ce2b17983a2d0e962b5 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 #include "json.h"
-#include <istream>
-#include <ostream>
+#include <iostream>
+#include <cstdlib>
 #include <cmath>
 #include <cstdint>
 #include <cassert>
@@ -560,5 +560,117 @@ void Array::write(std::ostream &os, Write_state &state) const
     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
 }
 }
index 9350e1866402dee58807fabf2dc2ccb2593f7de9..7d9f4c0225f84f4da98bf44f3d66895d988209e6 100644 (file)
 #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
@@ -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<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
@@ -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<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()
     {
@@ -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<std::string, Value> 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<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
@@ -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<Value> 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<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
@@ -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<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);
+};
 }
 }
 
index 7f8ec70cdf745fb935789e3364d802b0941cddbe..95efadecad691b89fd10c1bc2f3bddb5a862a699 100644 (file)
 #
 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