summaryrefslogtreecommitdiff
path: root/vere/pkg/noun/jets/e/json_en.c
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/pkg/noun/jets/e/json_en.c
claude is gud
Diffstat (limited to 'vere/pkg/noun/jets/e/json_en.c')
-rw-r--r--vere/pkg/noun/jets/e/json_en.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/vere/pkg/noun/jets/e/json_en.c b/vere/pkg/noun/jets/e/json_en.c
new file mode 100644
index 0000000..f605ab4
--- /dev/null
+++ b/vere/pkg/noun/jets/e/json_en.c
@@ -0,0 +1,416 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/*
+** structs
+*/
+
+typedef struct _json_buffer {
+ c3_y *buf_y;
+ c3_w len_w;
+} json_buffer;
+
+/*
+** constants
+*/
+
+const c3_y _JSON_NULL[] = "null";
+const c3_y _JSON_TRUE[] = "true";
+const c3_y _JSON_FALSE[] = "false";
+const c3_y _JSON_NEWLINE[] = "\\n";
+const c3_y _JSON_DOQ[] = "\\\"";
+const c3_y _JSON_BAS[] = "\\\\";
+const c3_y _JSON_DEL[] = "\\u007f";
+const c3_y *_JSON_UNICODES[] = {
+ (c3_y*)"\\u0000", // 0
+ (c3_y*)"\\u0001", // 1
+ (c3_y*)"\\u0002", // 2
+ (c3_y*)"\\u0003", // 3
+ (c3_y*)"\\u0004", // 4
+ (c3_y*)"\\u0005", // 5
+ (c3_y*)"\\u0006", // 6
+ (c3_y*)"\\u0007", // 7
+ (c3_y*)"\\u0008", // 8
+ (c3_y*)"\\u0009", // 9
+ (c3_y*)"\\u000a", // 10
+ (c3_y*)"\\u000b", // 11
+ (c3_y*)"\\u000c", // 12
+ (c3_y*)"\\u000d", // 13
+ (c3_y*)"\\u000e", // 14
+ (c3_y*)"\\u000f", // 15
+ (c3_y*)"\\u0010", // 16
+ (c3_y*)"\\u0011", // 17
+ (c3_y*)"\\u0012", // 18
+ (c3_y*)"\\u0013", // 19
+ (c3_y*)"\\u0014", // 20
+ (c3_y*)"\\u0015", // 21
+ (c3_y*)"\\u0016", // 22
+ (c3_y*)"\\u0017", // 23
+ (c3_y*)"\\u0018", // 24
+ (c3_y*)"\\u0019", // 25
+ (c3_y*)"\\u001a", // 26
+ (c3_y*)"\\u001b", // 27
+ (c3_y*)"\\u001c", // 28
+ (c3_y*)"\\u001d", // 29
+ (c3_y*)"\\u001e", // 30
+ (c3_y*)"\\u001f", // 31
+};
+
+/*
+** forward declarations
+*/
+
+static c3_w
+_measure(u3_noun a);
+
+static void
+_serialize(json_buffer*, u3_noun);
+
+/*
+** core jet logic
+*/
+
+static void
+_append_char(json_buffer *buf_u, c3_y c_y)
+{
+ buf_u->buf_y[(buf_u->len_w)++] = c_y;
+}
+
+static void
+_append_text(json_buffer *buf_u, const c3_y *buf_y, c3_w len_w)
+{
+ memcpy(&(buf_u->buf_y[buf_u->len_w]), buf_y, len_w);
+ buf_u->len_w += len_w;
+}
+
+static c3_w
+_measure_loobean(u3_noun a)
+{
+ switch ( a ) {
+ default: u3m_bail(c3__exit);
+ case c3y: return sizeof(_JSON_TRUE) - 1;
+ case c3n: return sizeof(_JSON_FALSE) - 1;
+ }
+}
+
+static void
+_serialize_loobean(json_buffer *buf_u, u3_noun a)
+{
+ switch ( a ) {
+ default: u3_assert(0);
+ case c3y: _append_text(buf_u, _JSON_TRUE, sizeof(_JSON_TRUE) - 1); break;
+ case c3n: _append_text(buf_u, _JSON_FALSE, sizeof(_JSON_FALSE) - 1); break;
+ }
+}
+
+static c3_w
+_measure_number(u3_noun a)
+{
+ if ( _(u3du(a)) ) {
+ u3m_bail(c3__exit);
+ }
+
+ return u3r_met(3, a);
+}
+
+static void
+_serialize_number(json_buffer *buf_u, u3_noun a)
+{
+ const c3_y *byt_y;
+
+ // XX assumes little-endian
+ //
+ if ( c3y == u3a_is_cat(a) ) {
+ byt_y = (c3_y*)&a;
+ }
+ else {
+ u3a_atom* vat_u = u3a_to_ptr(a);
+ byt_y = (c3_y*)vat_u->buf_w;
+ }
+
+ _append_text(buf_u, byt_y, u3r_met(3, a));
+}
+
+static c3_w
+_measure_string(u3_noun a)
+{
+ if ( _(u3du(a)) ) {
+ u3m_bail(c3__exit);
+ }
+
+ c3_w len_w = u3r_met(3, a);
+ c3_w siz_w = 0;
+
+ for (c3_w i = 0; i < len_w; ++i) {
+ c3_y c_y = u3r_byte(i, a);
+
+ switch ( c_y ) {
+ case 0 ... 9:
+ case 11 ... 31: {
+ siz_w += 6;
+ } break;
+
+ case 10: {
+ siz_w += sizeof(_JSON_NEWLINE) - 1;
+ } break;
+
+ case 34: {
+ siz_w += sizeof(_JSON_DOQ) - 1;
+ } break;
+
+ case 92: {
+ siz_w += sizeof(_JSON_BAS) - 1;
+ } break;
+
+ case 127: {
+ siz_w += sizeof(_JSON_DEL) - 1;
+ } break;
+
+ default: {
+ siz_w += 1;
+ } break;
+ }
+ }
+
+ // surrounding double quotes
+ return (siz_w + 2);
+}
+
+static void
+_serialize_string(json_buffer *buf_u, u3_noun a)
+{
+ c3_w len_w = u3r_met(3, a);
+
+ _append_char(buf_u, '"');
+ for (c3_w i = 0; i < len_w; ++i) {
+ c3_y c_y = u3r_byte(i, a);
+
+ switch ( c_y ) {
+ case 0 ... 9:
+ case 11 ... 31: {
+ _append_text(buf_u, _JSON_UNICODES[c_y], 6);
+ } break;
+
+ case 10: {
+ _append_text(buf_u, _JSON_NEWLINE, sizeof(_JSON_NEWLINE) - 1);
+ } break;
+
+ case 34: {
+ _append_text(buf_u, _JSON_DOQ, sizeof(_JSON_DOQ) - 1);
+ } break;
+
+ case 92: {
+ _append_text(buf_u, _JSON_BAS, sizeof(_JSON_BAS) - 1);
+ } break;
+
+ case 127: {
+ _append_text(buf_u, _JSON_DEL, sizeof(_JSON_DEL) - 1);
+ } break;
+
+ default: {
+ _append_char(buf_u, c_y);
+ } break;
+ }
+ }
+ _append_char(buf_u, '"');
+}
+
+static c3_w
+_measure_array(u3_noun a)
+{
+ if ( u3_nul != a ) {
+ u3_noun i, t = a;
+ // array open brace
+ c3_w siz_w = 1;
+
+ while ( u3_nul != t ) {
+ u3x_cell(t, &i, &t);
+ siz_w += _measure(i);
+ // comma or array close brace
+ siz_w += 1;
+ }
+
+ return siz_w;
+ }
+ else {
+ // empty array
+ return 2;
+ }
+}
+
+static void
+_serialize_array(json_buffer *buf_u, u3_noun a)
+{
+ _append_char(buf_u, '[');
+
+ if ( u3_nul != a ) {
+ u3_noun i, t = a;
+
+ while ( u3_nul != t ) {
+ u3x_cell(t, &i, &t);
+ _serialize(buf_u, i);
+ _append_char(buf_u, ',');
+ }
+
+ // Remove trailing comma from array contents
+ --buf_u->len_w;
+ }
+
+ _append_char(buf_u, ']');
+}
+
+static c3_w
+_measure_object_helper(u3_noun a)
+{
+ c3_w siz_w = 0;
+
+ if ( u3_nul != a ) {
+ u3_noun n_a, l_a, r_a;
+ u3_noun pn_a, qn_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_cell(n_a, &pn_a, &qn_a);
+
+ siz_w += _measure_object_helper(r_a);
+ siz_w += _measure_object_helper(l_a);
+
+ siz_w += _measure_string(pn_a);
+ siz_w += _measure(qn_a);
+
+ // colon and comma (or closing brace)
+ siz_w += 2;
+ }
+
+ return siz_w;
+}
+
+static void
+_serialize_object_helper(json_buffer *buf_u, u3_noun a)
+{
+ if ( u3_nul != a ) {
+ u3_noun n_a, l_a, r_a;
+ u3_noun pn_a, qn_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_cell(n_a, &pn_a, &qn_a);
+
+ // order is important to match unjetted tree traversal
+ _serialize_object_helper(buf_u, r_a);
+
+ _serialize_string(buf_u, pn_a);
+ _append_char(buf_u, ':');
+ _serialize(buf_u, qn_a);
+ _append_char(buf_u, ',');
+
+ _serialize_object_helper(buf_u, l_a);
+ }
+}
+
+static c3_w
+_measure_object(u3_noun a)
+{
+ if ( u3_nul != a ) {
+ // opening brace
+ return 1 + _measure_object_helper(a);
+ }
+ else {
+ // empty object
+ return 2;
+ }
+}
+
+static void
+_serialize_object(json_buffer *buf_u, u3_noun a)
+{
+ _append_char(buf_u, '{');
+
+ if ( u3_nul != a ) {
+ _serialize_object_helper(buf_u, a);
+
+ // Remove trailing comma from object contents
+ --buf_u->len_w;
+ }
+
+ _append_char(buf_u, '}');
+}
+
+static c3_w
+_measure(u3_noun a)
+{
+ if ( u3_nul == a ) {
+ return sizeof(_JSON_NULL) - 1;
+ }
+ else {
+ u3_noun s, p;
+ u3x_cell(a, &s, &p);
+
+ switch ( s ) {
+ default: u3m_bail(c3__fail);
+ case c3__a: return _measure_array(p);
+ case c3__o: return _measure_object(p);
+ case c3__b: return _measure_loobean(p);
+ case c3__n: return _measure_number(p);
+ case c3__s: return _measure_string(p);
+ }
+ }
+}
+
+static void
+_serialize(json_buffer *buf_u, u3_noun a)
+{
+ if ( u3_nul == a ) {
+ _append_text(buf_u, _JSON_NULL, sizeof(_JSON_NULL) - 1);
+ }
+ else {
+ u3_noun s, p;
+ u3x_cell(a, &s, &p);
+
+ switch ( s ) {
+ default: u3_assert(0);
+ case c3__a: _serialize_array(buf_u, p); break;
+ case c3__o: _serialize_object(buf_u, p); break;
+ case c3__b: _serialize_loobean(buf_u, p); break;
+ case c3__n: _serialize_number(buf_u, p); break;
+ case c3__s: _serialize_string(buf_u, p); break;
+ }
+ }
+}
+
+/*
+** jet interface functions
+*/
+
+u3_atom
+u3qe_json_en(u3_noun a)
+{
+ u3i_slab sab_u;
+ json_buffer bof_u;
+ json_buffer *buf_u = &bof_u;
+ c3_w siz_w = _measure(a);
+
+ u3i_slab_init(&sab_u, 3, siz_w);
+ buf_u->buf_y = sab_u.buf_y;
+ buf_u->len_w = 0;
+
+ // note that it's structurally integral to call measure before serialize
+ _serialize(buf_u, a);
+
+ return u3i_slab_mint_bytes(&sab_u);
+}
+
+u3_atom
+u3ke_json_en(u3_noun a)
+{
+ u3_atom res = u3qe_json_en(a);
+ u3z(a);
+ return res;
+}
+
+u3_atom
+u3we_json_en(u3_noun cor)
+{
+ return u3qe_json_en(u3x_at(u3x_sam, cor));
+}