diff --git a/CMakeLists.txt b/CMakeLists.txt index 98191f39..81624024 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,5 +94,6 @@ if(CLICE_ENABLE_TEST) target_clang(clice_test) file(GLOB_RECURSE AST_SRC_FILES "${CMAKE_SOURCE_DIR}/src/AST/*.cpp") - target_sources(clice_test PRIVATE ${AST_SRC_FILES} "${CMAKE_SOURCE_DIR}/tests/Resolver.cpp") + file(GLOB_RECURSE TEST_SRC_FILES "${CMAKE_SOURCE_DIR}/tests/*.cpp") + target_sources(clice_test PRIVATE ${AST_SRC_FILES} ${TEST_SRC_FILES}) endif() diff --git a/include/Support/JSON.h b/include/Support/JSON.h new file mode 100644 index 00000000..1e6a806a --- /dev/null +++ b/include/Support/JSON.h @@ -0,0 +1,73 @@ +#include +#include +#include + +namespace clice::json { + +using namespace llvm::json; + +template +constexpr inline bool is_array_v = false; + +template +constexpr inline bool is_array_v> = true; + +template +constexpr inline bool is_integral_v = + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; + +template +Object serialize(const T& object) { + Object result; + for_each(object, [&](std::string_view name, Value& value) { + if constexpr(is_array_v) { + Array array; + for(const auto& element: value) { + array.push_back(serialize(element)); + } + result.try_emplace(llvm::StringRef(name), std::move(array)); + } else if constexpr(std::is_constructible_v) { + result.try_emplace(llvm::StringRef(name), value); + } else { + result.try_emplace(llvm::StringRef(name), serialize(value)); + } + }); + return result; +} + +template +T deserialize(const Object& object) { + T result; + for_each(result, [&](std::string_view name, Value& value) { + if constexpr(is_array_v) { + if(const auto* array = object.getArray(name)) { + for(std::size_t i = 0; i < array->size(); ++i) { + value[i] = deserialize((*array)[i]); + } + } + } else if constexpr(std::is_same_v) { + if(auto boolean = object.getBoolean(name)) { + value = *boolean; + } + } else if constexpr(is_integral_v) { + if(auto integer = object.getInteger(name)) { + value = *integer; + } + } else if constexpr(is_integral_v) { + if(auto floating = object.getNumber(name)) { + value = *floating; + } + } else if constexpr(std::is_same_v) { + if(auto string = object.getString(name)) { + value = *string; + } + } else { + if(auto subobject = object.getObject(name)) { + value = deserialize(*subobject); + } + } + }); + return result; +} + +} // namespace clice::json diff --git a/tests/JSON.cpp b/tests/JSON.cpp new file mode 100644 index 00000000..be0ed7c2 --- /dev/null +++ b/tests/JSON.cpp @@ -0,0 +1,26 @@ +#include +#include + +namespace { + +using namespace clice; + +TEST(JSON, Point) { + json::Object object; + object["x"] = 1; + object["y"] = 2; + + struct Point { + int x; + int y; + }; + + auto point = clice::json::deserialize(object); + ASSERT_EQ(point.x, 1); + ASSERT_EQ(point.y, 2); + + auto result = clice::json::serialize(point); + ASSERT_EQ(result, object); +} + +} // namespace