// // json.cpp // json // // Created by Sam Jaffe on 1/30/16. // Copyright © 2016 Sam Jaffe. All rights reserved. // #include "json.h" #include "json_parser.hpp" #include "json_binder.hpp" struct test_t { int a, b; }; struct test_2_t { test_t t; double d; }; int main(int argc, char const** argv) { auto bind1 = json::binder::object_binder{} ("a", &test_t::a) ("b", &test_t::b); json::binder::tuple_binder{} (&test_t::a) (&test_t::b); auto bind2 = json::binder::object_binder{} ("t", &test_2_t::t, bind1)("d", &test_2_t::d); { test_t out; std::string data = "{\"a\":1,\"b\":2}"; json::parser::parse(json::binder::bind(out, bind1), data); std::cout << out.a << ',' << out.b << std::endl; } { test_2_t out; std::string data = "{\"t\":{\"a\":1,\"b\":2},\"d\":1.5}"; json::parser::parse(json::binder::bind(out, bind2), data); std::cout << '{' << out.t.a << ',' << out.t.b << "}," << out.d << std::endl; } } const json::value json::value::null_value{}; namespace { void parse_object(json::value& json, char const*& data); void parse_array(json::value& json, char const*& data); void parse_one_token(json::value& json, char const*& data); void parse_one_token(json::value& json, char const*& data) { const char ch = json::helper::get_next_element(data); if (ch == '{') { parse_object(json, ++data); } else if (ch == '[') { parse_array(json, ++data); } else if (ch == '"') { json::helper::parse_string(json, ++data); } else if (isnumber(ch)) { json::helper::parse_numeric(json, data); } else if (!strncmp(data, "true", 4)) { json = true; } else if (!strncmp(data, "false", 5)) { json = false; } else { throw json::malformed_json_exception(std::string("Expected the start of a JSON element, found character '") + ch + "' instead"); } } void parse_object(json::value& json, char const*& data) { std::string key; while (*data && *data != '}') { json::helper::parse_string(key, data); if (json::helper::get_next_element(data) != ':') { throw json::malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead"); } parse_one_token(json[key], ++data); json::helper::advance_to_boundary<'}'>(data); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding object end"); } void parse_array(json::value& json, char const*& data) { size_t current_idx = 0; while (*data && *data != ']') { parse_one_token(json[current_idx++], data); json::helper::advance_to_boundary<']'>(data); } if (*data) ++data; else throw json::malformed_json_exception("Reached end of parse string without finding array end"); } } namespace json { namespace parser { void parse(json::value& json, char const* data) { parse_one_token(json, data); if (*data) throw json::malformed_json_exception("Expected a single json token in top-level parse"); } } } void json::value::parse(char const* data) { parser::parse(*this, data); } void json::value::parse(std::string const& str) { parser::parse(*this, str); } void json::value::parse(std::istream & in) { parser::parse(*this, in); } json::value& json::value::operator[](const size_t idx) { if (!is_array()) { data.set(); } array_jt & val = data.get(); if (val.size() <= idx) val.resize(idx+1); return val[idx]; } json::value const& json::value::operator[](const size_t idx) const { if (!is_array()) return null_value; array_jt const& val = data.get(); if (val.size() <= idx) return null_value; else return val[idx]; } json::value& json::value::operator[](std::string const& key) { if (!is_object()) { data.set(); } return data.get()[key]; } json::value const& json::value::operator[](std::string const& key) const { if (!is_object()) return null_value; object_jt const& val = data.get(); auto it = val.find(key); if (it != val.end()) { return it->second; } else { return null_value; } } json::value::string_jt const& json::value::as_string() const { return data.get(); } json::value::double_jt json::value::as_double() const { if (data.is()) { return data.get(); } else if (data.is()) { return static_cast(data.get()); } else if (data.is()) { return data.get() ? 1.0 : 0.0; } else { return 0.0; } } json::value::int_jt json::value::as_int() const { if (data.is()) { return static_cast(data.get()); } else if (data.is()) { return data.get(); } else if (data.is()) { return data.get() ? 1 : 0; } else { return 0; } } json::value::bool_jt json::value::as_bool() const { if (data.is()) { return data.get() != 0; } else if (data.is()) { return data.get() != 0; } else if (data.is()) { return data.get(); } else { return false; } }