diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index d478f407..2bcff1ca 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -2,13 +2,17 @@ #define CHAISCRIPT_SIMPLEJSON_WRAP_HPP #include "json.hpp" +#include "../dispatchkit/dynamic_object.hpp" namespace chaiscript { class json_wrap { public: static Module &library(Module &m) { m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json"); + m.add(chaiscript::fun([](const std::string &t_str) { return object_from_json(t_str); }), "object_from_json"); m.add(chaiscript::fun(&json_wrap::to_json), "to_json"); + m.add(chaiscript::fun(&json_wrap::map_to_object), "map_to_object"); + m.add(chaiscript::fun(&json_wrap::object_to_map), "object_to_map"); return m; } @@ -57,6 +61,63 @@ namespace chaiscript { } } + static Boxed_Value object_from_json(const json::JSON &t_json) { + switch (t_json.JSONType()) { + case json::JSON::Class::Null: + return Boxed_Value(); + case json::JSON::Class::Object: { + auto obj = dispatch::Dynamic_Object("JSON_Object"); + + for (const auto &p : t_json.object_range()) { + obj.get_attr(p.first) = object_from_json(p.second); + } + + return Boxed_Value(std::move(obj)); + } + case json::JSON::Class::Array: { + std::vector vec; + + for (const auto &p : t_json.array_range()) { + vec.emplace_back(object_from_json(p)); + } + + return Boxed_Value(vec); + } + case json::JSON::Class::String: + return Boxed_Value(t_json.to_string()); + case json::JSON::Class::Floating: + return Boxed_Value(t_json.to_float()); + case json::JSON::Class::Integral: + return Boxed_Value(t_json.to_int()); + case json::JSON::Class::Boolean: + return Boxed_Value(t_json.to_bool()); + } + + throw std::runtime_error("Unknown JSON type"); + } + + static Boxed_Value object_from_json(const std::string &t_json) { + try { + return object_from_json(json::JSON::Load(t_json)); + } catch (const std::out_of_range &) { + throw std::runtime_error("Unparsed JSON input"); + } + } + + static Boxed_Value map_to_object(const std::map &t_map) { + auto obj = dispatch::Dynamic_Object("JSON_Object"); + + for (const auto &p : t_map) { + obj.get_attr(p.first) = p.second; + } + + return Boxed_Value(std::move(obj)); + } + + static std::map object_to_map(const dispatch::Dynamic_Object &t_obj) { + return t_obj.get_attrs(); + } + static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); } static json::JSON to_json_object(const Boxed_Value &t_bv) { diff --git a/unittests/object_from_json_1.chai b/unittests/object_from_json_1.chai new file mode 100644 index 00000000..541d1ac9 --- /dev/null +++ b/unittests/object_from_json_1.chai @@ -0,0 +1,6 @@ +// object_from_json: returns Dynamic_Object with dot-access on JSON fields +var obj = object_from_json("{\"name\":\"ChaiScript\",\"version\":6,\"active\":true}") +assert_equal(obj.name, "ChaiScript") +assert_equal(obj.version, 6) +assert_equal(obj.active, true) +assert_equal(obj.get_type_name(), "JSON_Object") diff --git a/unittests/object_from_json_2.chai b/unittests/object_from_json_2.chai new file mode 100644 index 00000000..05467164 --- /dev/null +++ b/unittests/object_from_json_2.chai @@ -0,0 +1,3 @@ +// object_from_json: nested objects become nested Dynamic_Objects +var obj = object_from_json("{\"outer\":{\"inner\":42}}") +assert_equal(obj.outer.inner, 42) diff --git a/unittests/object_from_json_3.chai b/unittests/object_from_json_3.chai new file mode 100644 index 00000000..11a428da --- /dev/null +++ b/unittests/object_from_json_3.chai @@ -0,0 +1,3 @@ +// object_from_json: arrays remain as vectors +var obj = object_from_json("{\"items\":[1,2,3]}") +assert_equal(obj.items, [1,2,3]) diff --git a/unittests/object_from_json_4.chai b/unittests/object_from_json_4.chai new file mode 100644 index 00000000..626e1d63 --- /dev/null +++ b/unittests/object_from_json_4.chai @@ -0,0 +1,9 @@ +// object_to_map and map_to_object conversions +var m = ["a": 1, "b": "hello"] +var obj = map_to_object(m) +assert_equal(obj.a, 1) +assert_equal(obj.b, "hello") + +var m2 = object_to_map(obj) +assert_equal(m2["a"], 1) +assert_equal(m2["b"], "hello") diff --git a/unittests/object_from_json_5.chai b/unittests/object_from_json_5.chai new file mode 100644 index 00000000..678f9a9c --- /dev/null +++ b/unittests/object_from_json_5.chai @@ -0,0 +1,6 @@ +// object_from_json roundtrip through to_json +var json_str = "{\"key\":\"value\"}" +var obj = object_from_json(json_str) +var result = to_json(obj) +var obj2 = object_from_json(result) +assert_equal(obj2.key, "value")