|
|
@@ -10,135 +10,134 @@
|
|
|
#include <cstring>
|
|
|
#include <map>
|
|
|
|
|
|
-namespace json {
|
|
|
- namespace helper {
|
|
|
- namespace {
|
|
|
- std::string get_no_end_error(char expected, char found) {
|
|
|
- char str[64] = { '\0' };
|
|
|
- snprintf(str, sizeof(str),
|
|
|
- "Expected delimeter: ',' or '%c', got '%c' instead",
|
|
|
- expected, found);
|
|
|
- return str;
|
|
|
- }
|
|
|
+namespace json { namespace helper {
|
|
|
+ namespace {
|
|
|
+ std::string get_no_end_error(char expected, char found) {
|
|
|
+ char str[64] = { '\0' };
|
|
|
+ snprintf(str, sizeof(str),
|
|
|
+ "Expected delimeter: ',' or '%c', got '%c' instead",
|
|
|
+ expected, found);
|
|
|
+ return str;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ namespace {
|
|
|
+ std::map<numeric_token_info::parse_state, uint_jt> bases{
|
|
|
+ { numeric_token_info::decimal, 10 },
|
|
|
+ { numeric_token_info::octal, 8 },
|
|
|
+ { numeric_token_info::hexadecimal, 16 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, std::string> allowed{
|
|
|
+ { numeric_token_info::decimal, "0123456789" },
|
|
|
+ { numeric_token_info::octal, "01234567" },
|
|
|
+ { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" }
|
|
|
+ };
|
|
|
+ std::map<char, uint_jt> values{
|
|
|
+ { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 },
|
|
|
+ { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 },
|
|
|
+ { '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'A', 10 },
|
|
|
+ { 'b', 11 }, { 'B', 11 }, { 'c', 12 }, { 'C', 12 },
|
|
|
+ { 'd', 13 }, { 'D', 13 }, { 'e', 14 }, { 'E', 14 },
|
|
|
+ { 'f', 15 }, { 'F', 15 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, uint_jt> thresholds{
|
|
|
+ { numeric_token_info::decimal, UINT_JT_MAX / 10 },
|
|
|
+ { numeric_token_info::octal, UINT_JT_MAX / 8 },
|
|
|
+ { numeric_token_info::hexadecimal, UINT_JT_MAX / 16 }
|
|
|
+ };
|
|
|
+ std::map<numeric_token_info::parse_state, uint_jt> last_digits{
|
|
|
+ { numeric_token_info::decimal, INT_JT_MAX % 10 },
|
|
|
+ { numeric_token_info::octal, INT_JT_MAX % 8 },
|
|
|
+ { numeric_token_info::hexadecimal, INT_JT_MAX % 16 }
|
|
|
+ };
|
|
|
|
|
|
- namespace {
|
|
|
- std::map<numeric_token_info::parse_state, uint_jt> bases{
|
|
|
- { numeric_token_info::decimal, 10 },
|
|
|
- { numeric_token_info::octal, 8 },
|
|
|
- { numeric_token_info::hexadecimal, 16 }
|
|
|
- };
|
|
|
- std::map<numeric_token_info::parse_state, std::string> allowed{
|
|
|
- { numeric_token_info::decimal, "0123456789" },
|
|
|
- { numeric_token_info::octal, "01234567" },
|
|
|
- { numeric_token_info::hexadecimal, "0123456789aAbBcCdDeEfF" }
|
|
|
- };
|
|
|
- std::map<char, uint_jt> values{
|
|
|
- { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 },
|
|
|
- { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 },
|
|
|
- { '8', 8 }, { '9', 9 }, { 'a', 10 }, { 'A', 10 },
|
|
|
- { 'b', 11 }, { 'B', 11 }, { 'c', 12 }, { 'C', 12 },
|
|
|
- { 'd', 13 }, { 'D', 13 }, { 'e', 14 }, { 'E', 14 },
|
|
|
- { 'f', 15 }, { 'F', 15 }
|
|
|
- };
|
|
|
- std::map<numeric_token_info::parse_state, uint_jt> thresholds{
|
|
|
- { numeric_token_info::decimal, UINT_JT_MAX / 10 },
|
|
|
- { numeric_token_info::octal, UINT_JT_MAX / 8 },
|
|
|
- { numeric_token_info::hexadecimal, UINT_JT_MAX / 16 }
|
|
|
- };
|
|
|
- std::map<numeric_token_info::parse_state, uint_jt> last_digits{
|
|
|
- { numeric_token_info::decimal, INT_JT_MAX % 10 },
|
|
|
- { numeric_token_info::octal, INT_JT_MAX % 8 },
|
|
|
- { numeric_token_info::hexadecimal, INT_JT_MAX % 16 }
|
|
|
- };
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // TODO - parse hex and octal
|
|
|
- numeric_token_info::numeric_token_info(char const * start)
|
|
|
- : val(0)
|
|
|
- , base(decimal)
|
|
|
- , it(start)
|
|
|
- , end(start)
|
|
|
- , is_double(false)
|
|
|
- , is_negative(*start == '-') {
|
|
|
- if ( is_negative ) { ++it; ++end; }
|
|
|
- if ( *end == '0' ) {
|
|
|
- base = octal;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO - parse hex and octal
|
|
|
+ numeric_token_info::numeric_token_info(char const * start)
|
|
|
+ : val(0)
|
|
|
+ , base(decimal)
|
|
|
+ , it(start)
|
|
|
+ , end(start)
|
|
|
+ , is_double(false)
|
|
|
+ , is_negative(*start == '-') {
|
|
|
+ if ( is_negative ) { ++it; ++end; }
|
|
|
+ if ( *end == '0' ) {
|
|
|
+ base = octal;
|
|
|
+ ++end;
|
|
|
+ if (strchr("xX", *end)) {
|
|
|
+ base = hexadecimal;
|
|
|
++end;
|
|
|
- if (strchr("xX", *end)) {
|
|
|
- base = hexadecimal;
|
|
|
- ++end;
|
|
|
- }
|
|
|
- }
|
|
|
- for (char c = *end;
|
|
|
- !strchr(",]}", c) && !isspace(c);
|
|
|
- c = *++end) {
|
|
|
- is_double |= !strchr(allowed[base].c_str(), c);
|
|
|
- }
|
|
|
-
|
|
|
- if ( is_negative && base != decimal ) {
|
|
|
- throw json_numeric_exception("Only decimal numbers can be recorded as negative");
|
|
|
- }
|
|
|
- if (end == it) {
|
|
|
- throw unterminated_json_exception("Expected any token, got nothing");
|
|
|
}
|
|
|
}
|
|
|
+ for (char c = *end;
|
|
|
+ !strchr(",]}", c) && !isspace(c);
|
|
|
+ c = *++end) {
|
|
|
+ is_double |= !strchr(allowed[base].c_str(), c);
|
|
|
+ }
|
|
|
|
|
|
- numeric_state numeric_token_info::parse_numeric() {
|
|
|
- uint_jt const threshold = thresholds[base];
|
|
|
- uint_jt const last_digit = last_digits[base];
|
|
|
- val = 0;
|
|
|
- for (char c = *it; it != end; c = *++it) {
|
|
|
- uint_jt digit = values[c];
|
|
|
- if (val > threshold ||
|
|
|
- ( val == threshold && ((it + 1) < end ||
|
|
|
- digit > last_digit))) {
|
|
|
- return DOUBLE;
|
|
|
- }
|
|
|
- val = (bases[base] * val) + digit;
|
|
|
- }
|
|
|
- return INTEGER;
|
|
|
+ if ( is_negative && base != decimal ) {
|
|
|
+ throw json_numeric_exception("Only decimal numbers can be recorded as negative");
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- const char get_next_element(char const*& data) {
|
|
|
- while (isspace(*data)) ++data;
|
|
|
- return *data;
|
|
|
+ if (end == it) {
|
|
|
+ throw unterminated_json_exception("Expected any token, got nothing");
|
|
|
}
|
|
|
-
|
|
|
- void advance_to_boundary(char const endtok, char const*& data) {
|
|
|
- char const next = get_next_element(data);
|
|
|
- if (next == ',') {
|
|
|
- ++data;
|
|
|
- } else if (next != endtok) {
|
|
|
- throw json::unterminated_json_exception(get_no_end_error(endtok, *data));
|
|
|
+ }
|
|
|
+
|
|
|
+ numeric_state numeric_token_info::parse_numeric() {
|
|
|
+ uint_jt const threshold = thresholds[base];
|
|
|
+ uint_jt const last_digit = last_digits[base];
|
|
|
+ val = 0;
|
|
|
+ for (char c = *it; it != end; c = *++it) {
|
|
|
+ uint_jt digit = values[c];
|
|
|
+ if (val > threshold ||
|
|
|
+ ( val == threshold && ((it + 1) < end ||
|
|
|
+ digit > last_digit))) {
|
|
|
+ return DOUBLE;
|
|
|
}
|
|
|
+ val = (bases[base] * val) + digit;
|
|
|
}
|
|
|
-
|
|
|
- int reverse_count(char const * data, char val) {
|
|
|
- int i = 0;
|
|
|
- while (*data-- == val) { ++i; }
|
|
|
- return i;
|
|
|
+ return INTEGER;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ const char get_next_element(char const*& data) {
|
|
|
+ while (isspace(*data)) ++data;
|
|
|
+ return *data;
|
|
|
+ }
|
|
|
+
|
|
|
+ void advance_to_boundary(char const endtok, char const*& data) {
|
|
|
+ char const next = get_next_element(data);
|
|
|
+ if (next == ',') {
|
|
|
+ ++data;
|
|
|
+ } else if (next != endtok) {
|
|
|
+ throw unterminated_json_exception(get_no_end_error(endtok, *data));
|
|
|
}
|
|
|
-
|
|
|
- std::string replace_all(std::string str, std::string const & from, std::string const & to) {
|
|
|
- std::string::size_type start_pos = 0;
|
|
|
- while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
|
|
- str.replace(start_pos, from.length(), to);
|
|
|
- start_pos += to.length(); // ...
|
|
|
- }
|
|
|
- return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ int reverse_count(char const * data, char val) {
|
|
|
+ int i = 0;
|
|
|
+ while (*data-- == val) { ++i; }
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string replace_all(std::string str, std::string const & from,
|
|
|
+ std::string const & to) {
|
|
|
+ std::string::size_type start_pos = 0;
|
|
|
+ while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
|
|
+ str.replace(start_pos, from.length(), to);
|
|
|
+ start_pos += to.length(); // ...
|
|
|
}
|
|
|
-
|
|
|
- std::string parse_string(char const * & data) {
|
|
|
- char const* start = data;
|
|
|
- while (*++data) {
|
|
|
- if (*data == '"' && (reverse_count(data-1, '\\') % 2) == 0) {
|
|
|
- return replace_all(std::string(start+1, data++), "\\\"", "\"");
|
|
|
- }
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string parse_string(char const * & data) {
|
|
|
+ char const* start = data;
|
|
|
+ while (*++data) {
|
|
|
+ if (*data == '"' && (reverse_count(data-1, '\\') % 2) == 0) {
|
|
|
+ return replace_all(std::string(start+1, data++), "\\\"", "\"");
|
|
|
}
|
|
|
- throw json::unterminated_json_exception("Could not locate end of string");
|
|
|
}
|
|
|
+ throw unterminated_json_exception("Could not locate end of string");
|
|
|
}
|
|
|
-}
|
|
|
+} }
|