diff --git a/src/jv.c b/src/jv.c index e064baf572..018d46afc6 100644 --- a/src/jv.c +++ b/src/jv.c @@ -137,14 +137,27 @@ static void jvp_invalid_free(jv x) { * Numbers */ -jv jv_number(double x) { - jv j = {JV_KIND_NUMBER, 0, 0, 0, {.number = x}}; +jv jv_number_full(double x, int64_t y) { + jv j = {JV_KIND_NUMBER, 0, 0, 0, {.number.dbl = x, .number.int64 = y}}; return j; } +jv jv_number(double x) { + int64_t y = 0; + if(x == x && x < INT_MAX && x > INT_MIN && x == (int)x) { + y = x; + } + return jv_number_full(x, y); +} + double jv_number_value(jv j) { assert(jv_get_kind(j) == JV_KIND_NUMBER); - return j.u.number; + return j.u.number.dbl; +} + +int64_t jv_number_value_int64(jv j) { + assert(jv_get_kind(j) == JV_KIND_NUMBER); + return j.u.number.int64; } int jv_is_integer(jv j){ diff --git a/src/jv.h b/src/jv.h index 9e74c9d8ae..2ed2d2a7de 100644 --- a/src/jv.h +++ b/src/jv.h @@ -27,7 +27,10 @@ typedef struct { int size; union { struct jv_refcnt* ptr; - double number; + struct { + double dbl; + int64_t int64; + } number; } u; } jv; @@ -60,8 +63,10 @@ jv jv_true(void); jv jv_false(void); jv jv_bool(int); +jv jv_number_full(double, int64_t); jv jv_number(double); double jv_number_value(jv); +int64_t jv_number_value_int64(jv); int jv_is_integer(jv); jv jv_array(void); diff --git a/src/jv_parse.c b/src/jv_parse.c index 84245b867e..b19ae7816f 100644 --- a/src/jv_parse.c +++ b/src/jv_parse.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "jv.h" #include "jv_dtoa.h" #include "jv_unicode.h" @@ -490,7 +491,12 @@ static pfunc check_literal(struct jv_parser* p) { double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end); if (end == 0 || *end != 0) return "Invalid numeric literal"; - TRY(value(p, jv_number(d))); + end = 0; + errno = 0; + int64_t i = strtoll(p->tokenbuf, &end, 10); + if (end == 0 || *end != 0 || errno != 0) + i = 0; + TRY(value(p, jv_number_full(d, i))); } p->tokenpos = 0; return 0; diff --git a/src/jv_print.c b/src/jv_print.c index 5f4f234b11..a7e514f7f9 100644 --- a/src/jv_print.c +++ b/src/jv_print.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -176,6 +177,13 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI put_str("true", F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_NUMBER: { + int64_t i = jv_number_value_int64(x); + if (i) { + char buf[21]; + snprintf(buf, sizeof(buf), "%" PRId64, i); + put_str(buf, F, S, flags & JV_PRINT_ISATTY); + break; + } double d = jv_number_value(x); if (d != d) { // JSON doesn't have NaN, so we'll render it as "null"