// // json_parser.cpp // json // // Created by Sam Jaffe on 4/24/16. // #include "json.hpp" namespace json { namespace { char const * get_numeric_token_end(char const * start); void parse_numeric(value& json, char const*& data); void parse_object(value& json, char const*& data); void parse_array(value& json, char const*& data); void parse_one_token(value& json, char const*& data); void parse_one_token(value& json, char const*& data) { const char ch = helper::get_next_element(data); if (ch == '{') { parse_object(json, ++data); } else if (ch == '[') { parse_array(json, ++data); } else if (ch == '"') { helper::parse_string(json, ++data); } else if (!strncmp(data, "true", 4)) { json = true; } else if (!strncmp(data, "false", 5)) { json = false; } else { parse_numeric(json, data); } } char const * get_numeric_token_end(char const * start) { while (strchr(",]}", *start) == NULL && !isspace(*start)) { ++start; } return start; } void parse_numeric(value & json, char const * & data) { char const * start = data; char const * const end = get_numeric_token_end(start); if (end == start) { throw malformed_json_exception("Expected any token, got nothing"); } bool const negative = *start == '-'; if (negative) ++start; uint_jt const threshold = (UINT_JT_MAX / 10); uint_jt val = 0; for (; start != end; ++start) { if (!isdigit(*start)) { helper::parse_double(json, start); return; } int_jt digit = static_cast(*start - '\0'); if (val >= threshold) { if (val > threshold || (start + 1) < end || digit > INT_JT_MAX_LAST_DIGIT) { helper::parse_double(json, start); return; } } val = (10 * val) + digit; } if (negative && val == INT_JT_OVER) { json = INT_JT_MIN; } else if (negative) { json = -int_jt(val); } else if (val <= uint_jt(INT_JT_MAX)) { json = int_jt(val); } else { json = val; } } void parse_object(value& json, char const*& data) { std::string key; while (*data && *data != '}') { helper::parse_string(key, data); if (helper::get_next_element(data) != ':') { throw malformed_json_exception(std::string("Expected key:value pair delimited by ':', got '") + *data + "' instead"); } parse_one_token(json[key], ++data); helper::advance_to_boundary('}', data); } if (*data) ++data; else throw malformed_json_exception("Reached end of parse string without finding object end"); } void parse_array(value& json, char const*& data) { size_t current_idx = 0; while (*data && *data != ']') { parse_one_token(json[current_idx++], data); helper::advance_to_boundary(']', data); } if (*data) ++data; else throw malformed_json_exception("Reached end of parse string without finding array end"); } } } namespace json { namespace parser { void parse(value& json, char const* data) { parse_one_token(json, data); if (*data) throw 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); }