Add std/json quirk_allow_inf_nan_numbers
diff --git a/internal/cgen/base/token-public.h b/internal/cgen/base/token-public.h
index 9f48d51..1c4c7c2 100644
--- a/internal/cgen/base/token-public.h
+++ b/internal/cgen/base/token-public.h
@@ -180,6 +180,11 @@
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080
+
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
// token length discriminates e.g. u16 little-endian vs u32 little-endian.
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index dac8f33..3f35fff 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -371,8 +371,8 @@
"" +
"// --------\n\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__UNDEFINED 0x00001\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__NULL 0x00002\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__FALSE 0x00004\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE 0x00008\n\n " +
"" +
- "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any one of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-endian, little-endian or text. For binary formats, the\n// token length discriminates e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_END" +
- "IAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n" +
+ "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any one of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-endian, li" +
+ "ttle-endian or text. For binary formats, the\n// token length discriminates e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n" +
"" +
"// --------\n\nstatic inline uint64_t //\nwuffs_base__token__value(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_major(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_MAJOR__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_MAJOR__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_minor(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_MINOR__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_base_category(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_base_detail(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_BASE_DETAIL__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_BASE_DETA" +
"IL__MASK;\n}\n\nstatic inline bool //\nwuffs_base__token__link_prev(const wuffs_base__token* t) {\n return t->repr & WUFFS_BASE__TOKEN__LINK_PREV;\n}\n\nstatic inline bool //\nwuffs_base__token__link_next(const wuffs_base__token* t) {\n return t->repr & WUFFS_BASE__TOKEN__LINK_NEXT;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__length(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__LENGTH__SHIFT) &\n WUFFS_BASE__TOKEN__LENGTH__MASK;\n}\n\n#ifdef __cplusplus\n\ninline uint64_t //\nwuffs_base__token::value() const {\n return wuffs_base__token__value(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_major() const {\n return wuffs_base__token__value_major(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_minor() const {\n return wuffs_base__token__value_minor(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_base_category() const {\n return wuffs_base__token__value_base_category(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_base_detail() const {\n return wuffs_base__to" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index b615ecc..d242f9a 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -1939,6 +1939,11 @@
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080
+
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
// token length discriminates e.g. u16 little-endian vs u32 little-endian.
@@ -6023,6 +6028,7 @@
uint32_t p_decode_tokens[1];
uint32_t p_decode_leading[1];
uint32_t p_decode_comment[1];
+ uint32_t p_decode_inf_nan[1];
uint32_t p_decode_trailing_new_line[1];
} private_impl;
@@ -6037,6 +6043,9 @@
struct {
uint32_t v_link_prev;
} s_decode_comment[1];
+ struct {
+ uint32_t v_neg;
+ } s_decode_inf_nan[1];
} private_data;
#ifdef __cplusplus
@@ -20295,10 +20304,10 @@
WUFFS_BASE__POTENTIALLY_UNUSED = {
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 1, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 2, 4, 15, 12, 4, 4, 4, 4, 4, 4,
+ 15, 15, 15, 15, 15, 15, 15, 11, 2, 4, 15, 12, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 7, 15, 8, 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 15, 15, 15, 15,
+ 15, 11, 15, 15, 15, 15, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 7, 15, 8, 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 15, 11, 15, 15,
15, 15, 11, 15, 15, 15, 15, 15, 10, 15, 15, 15, 15, 15, 15, 5, 15, 6,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
@@ -20376,6 +20385,11 @@
wuffs_base__io_buffer* a_src);
static wuffs_base__status //
+wuffs_json__decoder__decode_inf_nan(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status //
wuffs_json__decoder__decode_trailing_new_line(wuffs_json__decoder* self,
wuffs_base__token_buffer* a_dst,
wuffs_base__io_buffer* a_src);
@@ -21374,6 +21388,27 @@
}
}
if (v_number_status == 1) {
+ if (self->private_impl.f_quirk_enabled_allow_inf_nan_numbers) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(16);
+ status =
+ wuffs_json__decoder__decode_inf_nan(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__3__break;
+ }
status = wuffs_base__make_status(wuffs_json__error__bad_input);
goto exit;
} else if (v_number_status == 2) {
@@ -21383,11 +21418,11 @@
} else {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(16);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
while (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
status = wuffs_base__make_status(
wuffs_base__suspension__short_write);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(18);
}
}
}
@@ -21521,7 +21556,7 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(18);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(19);
goto label__outer__continue;
}
} else if (v_class == 10) {
@@ -21542,7 +21577,7 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(19);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(20);
goto label__outer__continue;
}
} else if (v_class == 11) {
@@ -21563,9 +21598,29 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(20);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(21);
goto label__outer__continue;
}
+ if (self->private_impl.f_quirk_enabled_allow_inf_nan_numbers) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(22);
+ status = wuffs_json__decoder__decode_inf_nan(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__goto_parsed_a_leaf_value__break;
+ }
} else if (v_class == 12) {
if (self->private_impl.f_quirk_enabled_allow_comment_block ||
self->private_impl.f_quirk_enabled_allow_comment_line) {
@@ -21575,7 +21630,7 @@
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(21);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(23);
status = wuffs_json__decoder__decode_comment(self, a_dst, a_src);
if (a_dst) {
iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
@@ -21606,7 +21661,7 @@
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(22);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(24);
status =
wuffs_json__decoder__decode_trailing_new_line(self, a_dst, a_src);
if (a_dst) {
@@ -22155,6 +22210,174 @@
return status;
}
+// -------- func json.decoder.decode_inf_nan
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_inf_nan(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint32_t v_c4 = 0;
+ uint32_t v_neg = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
+ }
+ }
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_inf_nan[0];
+ if (coro_susp_point) {
+ v_neg = self->private_data.s_decode_inf_nan[0].v_neg;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ label__0__continue:;
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ goto label__0__continue;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 2) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ goto label__0__continue;
+ }
+ v_c4 = ((uint32_t)(wuffs_base__load_u24le__no_bounds_check(iop_a_src)));
+ if ((v_c4 | 2105376) == 6712937) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) > 7) {
+ if ((wuffs_base__load_u64le__no_bounds_check(iop_a_src) |
+ 2314885530818453536) == 8751735898823356009) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485792))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(8)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 8, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ } else if (!(a_src && a_src->meta.closed)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ goto label__0__continue;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485792)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 3, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 | 2105376) == 7233902) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485888)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 3, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 & 255) == 43) {
+ v_neg = 0;
+ } else if ((v_c4 & 255) == 45) {
+ v_neg = 1;
+ } else {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 3) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ goto label__0__continue;
+ }
+ v_c4 = (wuffs_base__load_u32le__no_bounds_check(iop_a_src) >> 8);
+ if ((v_c4 | 2105376) == 6712937) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) > 8) {
+ if ((wuffs_base__load_u64le__no_bounds_check(iop_a_src + 1) |
+ 2314885530818453536) == 8751735898823356009) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(32)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(9)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 9, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ } else if (!(a_src && a_src->meta.closed)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+ goto label__0__continue;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(32)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(4)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 4, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 | 2105376) == 7233902) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(128)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(4)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 4, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_inf_nan[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_decode_inf_nan[0] =
+ wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_decode_inf_nan[0].v_neg = v_neg;
+
+ goto exit;
+exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
// -------- func json.decoder.decode_trailing_new_line
static wuffs_base__status //
diff --git a/std/json/common_consts.wuffs b/std/json/common_consts.wuffs
index 8a43b71..f92383d 100644
--- a/std/json/common_consts.wuffs
+++ b/std/json/common_consts.wuffs
@@ -196,7 +196,7 @@
// - 0x08 (bitmask 0x0100) is CLASS_CLOSE_SQUARE_BRACKET.
// - 0x09 (bitmask 0x0200) is CLASS_FALSE.
// - 0x0A (bitmask 0x0400) is CLASS_TRUE.
-// - 0x0B (bitmask 0x0800) is CLASS_NULL.
+// - 0x0B (bitmask 0x0800) is CLASS_NULL_NAN_INF.
// - 0x0C (bitmask 0x1000) is CLASS_COMMENT.
// - 0x0D (bitmask 0x2000) is reserved.
// - 0x0E (bitmask 0x4000) is reserved.
@@ -236,16 +236,16 @@
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x10 ..= 0x17.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x18 ..= 0x1F.
0x00, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x20 ..= 0x27. ' ', '"'.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x02, 0x04, 0x0F, 0x0C, // 0x28 ..= 0x2F. ',', '-', '/'.
+ 0x0F, 0x0F, 0x0F, 0x0B, 0x02, 0x04, 0x0F, 0x0C, // 0x28 ..= 0x2F. '+', ',', '-', '/'.
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, // 0x30 ..= 0x37. '0'-'7'.
0x04, 0x04, 0x03, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x38 ..= 0x3F. '8'-'9', ':'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x40 ..= 0x47.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x48 ..= 0x4F.
+ 0x0F, 0x0B, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x48 ..= 0x4F. 'I', 'N'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x50 ..= 0x57.
0x0F, 0x0F, 0x0F, 0x07, 0x0F, 0x08, 0x0F, 0x0F, // 0x58 ..= 0x5F. '[', ']'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x09, 0x0F, // 0x60 ..= 0x67. 'f'.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x68 ..= 0x6F. 'n'.
+ 0x0F, 0x0B, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x68 ..= 0x6F. 'i', 'n'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0A, 0x0F, 0x0F, 0x0F, // 0x70 ..= 0x77. 't'.
0x0F, 0x0F, 0x0F, 0x05, 0x0F, 0x06, 0x0F, 0x0F, // 0x78 ..= 0x7F. '{', '}'.
diff --git a/std/json/decode_json.wuffs b/std/json/decode_json.wuffs
index 566811d..3d99554 100644
--- a/std/json/decode_json.wuffs
+++ b/std/json/decode_json.wuffs
@@ -888,6 +888,10 @@
}
if number_status == 1 {
+ if this.quirk_enabled_allow_inf_nan_numbers {
+ this.decode_inf_nan?(dst: args.dst, src: args.src)
+ break
+ }
return "#bad input"
} else if number_status == 2 {
return "#unsupported number length"
@@ -1061,7 +1065,7 @@
continue.outer
}
- } else if class == 0x0B { // 0x0B is CLASS_NULL.
+ } else if class == 0x0B { // 0x0B is CLASS_NULL_NAN_INF.
match = args.src.match7(a: 0x6C_6C75_6E04) // 4 bytes "null".
if match == 0 {
args.dst.write_fast_token!(
@@ -1079,6 +1083,11 @@
continue.outer
}
+ if this.quirk_enabled_allow_inf_nan_numbers {
+ this.decode_inf_nan?(dst: args.dst, src: args.src)
+ break.goto_parsed_a_leaf_value
+ }
+
} else if class == 0x0C { // 0x0C is CLASS_COMMENT.
if this.quirk_enabled_allow_comment_block or this.quirk_enabled_allow_comment_line {
this.decode_comment?(dst: args.dst, src: args.src)
@@ -1463,6 +1472,111 @@
return "#bad input"
}
+pri func decoder.decode_inf_nan?(dst: base.token_writer, src: base.io_reader) {
+ var c4 : base.u32
+ var neg : base.u32[..= 1]
+
+ while true {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ continue
+ }
+ if args.src.available() <= 2 {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue
+ }
+
+ // Bitwise or'ing with 0x20 converts upper case ASCII to lower case.
+
+ c4 = args.src.peek_u24le_as_u32()
+ if (c4 | 0x20_2020) == 0x66_6E69 {
+ if args.src.available() > 7 {
+ if (args.src.peek_u64le() | 0x2020_2020_2020_2020) == 0x7974_696E_6966_6E69 {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0020,
+ link: 0x0,
+ length: 8)
+ args.src.skip32_fast!(actual: 8, worst_case: 8)
+ return ok
+ }
+ } else if not args.src.is_closed() {
+ yield? base."$short read"
+ continue
+ }
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0020,
+ link: 0x0,
+ length: 3)
+ args.src.skip32_fast!(actual: 3, worst_case: 3)
+ return ok
+
+ } else if (c4 | 0x20_2020) == 0x6E_616E {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0080,
+ link: 0x0,
+ length: 3)
+ args.src.skip32_fast!(actual: 3, worst_case: 3)
+ return ok
+ } else if (c4 & 0xFF) == 0x2B { // 0x2B is '+'.
+ neg = 0
+ } else if (c4 & 0xFF) == 0x2D { // 0x2D is '-'.
+ neg = 1
+ } else {
+ return "#bad input"
+ }
+
+ if args.src.available() <= 3 {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue
+ }
+
+ c4 = args.src.peek_u32le() >> 8
+ if (c4 | 0x20_2020) == 0x66_6E69 {
+ if args.src.available() > 8 {
+ if (args.src.peek_u64le_at(offset: 1) | 0x2020_2020_2020_2020) == 0x7974_696E_6966_6E69 {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x20 as base.u32) >> neg),
+ link: 0x0,
+ length: 9)
+ args.src.skip32_fast!(actual: 9, worst_case: 9)
+ return ok
+ }
+ } else if not args.src.is_closed() {
+ yield? base."$short read"
+ continue
+ }
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x20 as base.u32) >> neg),
+ link: 0x0,
+ length: 4)
+ args.src.skip32_fast!(actual: 4, worst_case: 4)
+ return ok
+
+ } else if (c4 | 0x20_2020) == 0x6E_616E {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x80 as base.u32) >> neg),
+ link: 0x0,
+ length: 4)
+ args.src.skip32_fast!(actual: 4, worst_case: 4)
+ return ok
+ }
+
+ return "#bad input"
+ }
+}
+
pri func decoder.decode_trailing_new_line?(dst: base.token_writer, src: base.io_reader) {
var c : base.u8
var whitespace_length : base.u32[..= 0xFFFE]
diff --git a/test/c/std/json.c b/test/c/std/json.c
index f1bfc1a..3cce8fd 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -1398,6 +1398,82 @@
}
const char* //
+test_wuffs_json_decode_quirk_allow_inf_nan_numbers() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 2 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "-X", .str = "InFiniTy"},
+ {.want = "-X", .str = "[+inf, -infinity, +nan,-NaN,NAN]"},
+ {.want = "-X", .str = "inf"},
+ {.want = "-+", .str = "infinit"},
+ {.want = "-+", .str = "infiQity"},
+ {.want = "-+", .str = "nana"},
+ {.want = "--", .str = "+-inf"},
+ {.want = "--", .str = "-+inf"},
+ {.want = "--", .str = "[infinit,"},
+ {.want = "--", .str = "[infiQity,"},
+ {.want = "--", .str = "[nana,"},
+ {.want = "--", .str = "∞"},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 2; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS, q & 1);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(global_have_token_slice);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src).repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
test_wuffs_json_decode_quirk_allow_comment_etc() {
CHECK_FOCUS(__func__);
@@ -2115,6 +2191,7 @@
test_wuffs_json_decode_quirk_allow_backslash_x,
test_wuffs_json_decode_quirk_allow_comment_etc,
test_wuffs_json_decode_quirk_allow_final_comma,
+ test_wuffs_json_decode_quirk_allow_inf_nan_numbers,
test_wuffs_json_decode_quirk_allow_leading_etc,
test_wuffs_json_decode_quirk_allow_trailing_etc,
test_wuffs_json_decode_quirk_replace_invalid_utf_8,