summaryrefslogtreecommitdiff
path: root/vere/pkg/noun
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
claude is gud
Diffstat (limited to 'vere/pkg/noun')
-rw-r--r--vere/pkg/noun/allocate.c2012
-rw-r--r--vere/pkg/noun/allocate.h854
-rw-r--r--vere/pkg/noun/build.zig439
-rw-r--r--vere/pkg/noun/build.zig.zon67
-rw-r--r--vere/pkg/noun/equality_tests.c164
-rw-r--r--vere/pkg/noun/error.h38
-rw-r--r--vere/pkg/noun/events.c1583
-rw-r--r--vere/pkg/noun/events.h131
-rw-r--r--vere/pkg/noun/hashtable.c1408
-rw-r--r--vere/pkg/noun/hashtable.h206
-rw-r--r--vere/pkg/noun/hashtable_tests.c301
-rw-r--r--vere/pkg/noun/imprison.c772
-rw-r--r--vere/pkg/noun/imprison.h170
-rw-r--r--vere/pkg/noun/jets.c2445
-rw-r--r--vere/pkg/noun/jets.h322
-rw-r--r--vere/pkg/noun/jets/136/tree.c1268
-rw-r--r--vere/pkg/noun/jets/137/tree.c1184
-rw-r--r--vere/pkg/noun/jets/a/add.c61
-rw-r--r--vere/pkg/noun/jets/a/dec.c57
-rw-r--r--vere/pkg/noun/jets/a/div.c57
-rw-r--r--vere/pkg/noun/jets/a/gte.c51
-rw-r--r--vere/pkg/noun/jets/a/gth.c60
-rw-r--r--vere/pkg/noun/jets/a/lte.c60
-rw-r--r--vere/pkg/noun/jets/a/lth.c51
-rw-r--r--vere/pkg/noun/jets/a/max.c60
-rw-r--r--vere/pkg/noun/jets/a/min.c62
-rw-r--r--vere/pkg/noun/jets/a/mod.c55
-rw-r--r--vere/pkg/noun/jets/a/mul.c58
-rw-r--r--vere/pkg/noun/jets/a/sub.c67
-rw-r--r--vere/pkg/noun/jets/b/bind.c30
-rw-r--r--vere/pkg/noun/jets/b/clap.c36
-rw-r--r--vere/pkg/noun/jets/b/find.c50
-rw-r--r--vere/pkg/noun/jets/b/flop.c34
-rw-r--r--vere/pkg/noun/jets/b/lent.c37
-rw-r--r--vere/pkg/noun/jets/b/levy.c51
-rw-r--r--vere/pkg/noun/jets/b/lien.c51
-rw-r--r--vere/pkg/noun/jets/b/mate.c30
-rw-r--r--vere/pkg/noun/jets/b/murn.c54
-rw-r--r--vere/pkg/noun/jets/b/need.c30
-rw-r--r--vere/pkg/noun/jets/b/reap.c41
-rw-r--r--vere/pkg/noun/jets/b/reel.c52
-rw-r--r--vere/pkg/noun/jets/b/roll.c44
-rw-r--r--vere/pkg/noun/jets/b/scag.c53
-rw-r--r--vere/pkg/noun/jets/b/skid.c62
-rw-r--r--vere/pkg/noun/jets/b/skim.c56
-rw-r--r--vere/pkg/noun/jets/b/skip.c56
-rw-r--r--vere/pkg/noun/jets/b/slag.c43
-rw-r--r--vere/pkg/noun/jets/b/snag.c44
-rw-r--r--vere/pkg/noun/jets/b/sort.c125
-rw-r--r--vere/pkg/noun/jets/b/turn.c49
-rw-r--r--vere/pkg/noun/jets/b/weld.c48
-rw-r--r--vere/pkg/noun/jets/b/zing.c47
-rw-r--r--vere/pkg/noun/jets/c/aor.c69
-rw-r--r--vere/pkg/noun/jets/c/bex.c55
-rw-r--r--vere/pkg/noun/jets/c/c0n.c55
-rw-r--r--vere/pkg/noun/jets/c/can.c85
-rw-r--r--vere/pkg/noun/jets/c/cap.c25
-rw-r--r--vere/pkg/noun/jets/c/cat.c54
-rw-r--r--vere/pkg/noun/jets/c/clz.c75
-rw-r--r--vere/pkg/noun/jets/c/ctz.c34
-rw-r--r--vere/pkg/noun/jets/c/cut.c68
-rw-r--r--vere/pkg/noun/jets/c/dis.c46
-rw-r--r--vere/pkg/noun/jets/c/dor.c49
-rw-r--r--vere/pkg/noun/jets/c/dvr.c46
-rw-r--r--vere/pkg/noun/jets/c/end.c51
-rw-r--r--vere/pkg/noun/jets/c/gor.c32
-rw-r--r--vere/pkg/noun/jets/c/ham.c27
-rw-r--r--vere/pkg/noun/jets/c/hew.c87
-rw-r--r--vere/pkg/noun/jets/c/lsh.c63
-rw-r--r--vere/pkg/noun/jets/c/mas.c48
-rw-r--r--vere/pkg/noun/jets/c/met.c42
-rw-r--r--vere/pkg/noun/jets/c/mix.c56
-rw-r--r--vere/pkg/noun/jets/c/mor.c31
-rw-r--r--vere/pkg/noun/jets/c/mug.c19
-rw-r--r--vere/pkg/noun/jets/c/muk.c76
-rw-r--r--vere/pkg/noun/jets/c/peg.c66
-rw-r--r--vere/pkg/noun/jets/c/po.c1427
-rw-r--r--vere/pkg/noun/jets/c/pow.c38
-rw-r--r--vere/pkg/noun/jets/c/rap.c88
-rw-r--r--vere/pkg/noun/jets/c/rep.c199
-rw-r--r--vere/pkg/noun/jets/c/rev.c51
-rw-r--r--vere/pkg/noun/jets/c/rig.c82
-rw-r--r--vere/pkg/noun/jets/c/rip.c192
-rw-r--r--vere/pkg/noun/jets/c/rsh.c60
-rw-r--r--vere/pkg/noun/jets/c/sew.c74
-rw-r--r--vere/pkg/noun/jets/c/sqt.c33
-rw-r--r--vere/pkg/noun/jets/c/swp.c50
-rw-r--r--vere/pkg/noun/jets/c/xeb.c32
-rw-r--r--vere/pkg/noun/jets/d/by_all.c51
-rw-r--r--vere/pkg/noun/jets/d/by_any.c51
-rw-r--r--vere/pkg/noun/jets/d/by_apt.c78
-rw-r--r--vere/pkg/noun/jets/d/by_bif.c74
-rw-r--r--vere/pkg/noun/jets/d/by_del.c93
-rw-r--r--vere/pkg/noun/jets/d/by_dif.c83
-rw-r--r--vere/pkg/noun/jets/d/by_gas.c44
-rw-r--r--vere/pkg/noun/jets/d/by_get.c63
-rw-r--r--vere/pkg/noun/jets/d/by_has.c47
-rw-r--r--vere/pkg/noun/jets/d/by_int.c72
-rw-r--r--vere/pkg/noun/jets/d/by_jab.c63
-rw-r--r--vere/pkg/noun/jets/d/by_key.c42
-rw-r--r--vere/pkg/noun/jets/d/by_put.c102
-rw-r--r--vere/pkg/noun/jets/d/by_run.c53
-rw-r--r--vere/pkg/noun/jets/d/by_uni.c101
-rw-r--r--vere/pkg/noun/jets/d/by_urn.c52
-rw-r--r--vere/pkg/noun/jets/d/in_apt.c121
-rw-r--r--vere/pkg/noun/jets/d/in_bif.c72
-rw-r--r--vere/pkg/noun/jets/d/in_del.c88
-rw-r--r--vere/pkg/noun/jets/d/in_dif.c82
-rw-r--r--vere/pkg/noun/jets/d/in_gas.c42
-rw-r--r--vere/pkg/noun/jets/d/in_has.c45
-rw-r--r--vere/pkg/noun/jets/d/in_int.c65
-rw-r--r--vere/pkg/noun/jets/d/in_put.c87
-rw-r--r--vere/pkg/noun/jets/d/in_rep.c52
-rw-r--r--vere/pkg/noun/jets/d/in_run.c59
-rw-r--r--vere/pkg/noun/jets/d/in_tap.c46
-rw-r--r--vere/pkg/noun/jets/d/in_uni.c98
-rw-r--r--vere/pkg/noun/jets/d/in_wyt.c35
-rw-r--r--vere/pkg/noun/jets/e/adler.c127
-rw-r--r--vere/pkg/noun/jets/e/aes_cbc.c182
-rw-r--r--vere/pkg/noun/jets/e/aes_ecb.c166
-rw-r--r--vere/pkg/noun/jets/e/aes_siv.c370
-rw-r--r--vere/pkg/noun/jets/e/argon2.c151
-rw-r--r--vere/pkg/noun/jets/e/base.c152
-rw-r--r--vere/pkg/noun/jets/e/blake.c163
-rw-r--r--vere/pkg/noun/jets/e/bytestream.c1247
-rw-r--r--vere/pkg/noun/jets/e/chacha.c74
-rw-r--r--vere/pkg/noun/jets/e/crc.c59
-rw-r--r--vere/pkg/noun/jets/e/cue.c27
-rw-r--r--vere/pkg/noun/jets/e/ed_add_double_scalarmult.c72
-rw-r--r--vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c66
-rw-r--r--vere/pkg/noun/jets/e/ed_luck.c37
-rw-r--r--vere/pkg/noun/jets/e/ed_point_add.c40
-rw-r--r--vere/pkg/noun/jets/e/ed_point_neg.c37
-rw-r--r--vere/pkg/noun/jets/e/ed_puck.c36
-rw-r--r--vere/pkg/noun/jets/e/ed_recs.c48
-rw-r--r--vere/pkg/noun/jets/e/ed_scad.c124
-rw-r--r--vere/pkg/noun/jets/e/ed_scalarmult.c54
-rw-r--r--vere/pkg/noun/jets/e/ed_scalarmult_base.c46
-rw-r--r--vere/pkg/noun/jets/e/ed_shar.c74
-rw-r--r--vere/pkg/noun/jets/e/ed_sign.c166
-rw-r--r--vere/pkg/noun/jets/e/ed_smac.c73
-rw-r--r--vere/pkg/noun/jets/e/ed_veri.c85
-rw-r--r--vere/pkg/noun/jets/e/fein_ob.c90
-rw-r--r--vere/pkg/noun/jets/e/fl.c441
-rw-r--r--vere/pkg/noun/jets/e/fynd_ob.c94
-rw-r--r--vere/pkg/noun/jets/e/hmac.c94
-rw-r--r--vere/pkg/noun/jets/e/jam.c60
-rw-r--r--vere/pkg/noun/jets/e/json_de.c258
-rw-r--r--vere/pkg/noun/jets/e/json_en.c416
-rw-r--r--vere/pkg/noun/jets/e/keccak.c42
-rw-r--r--vere/pkg/noun/jets/e/leer.c131
-rw-r--r--vere/pkg/noun/jets/e/loss.c297
-rw-r--r--vere/pkg/noun/jets/e/lune.c57
-rw-r--r--vere/pkg/noun/jets/e/mat.c49
-rw-r--r--vere/pkg/noun/jets/e/mice.c23
-rw-r--r--vere/pkg/noun/jets/e/mink.c27
-rw-r--r--vere/pkg/noun/jets/e/mole.c18
-rw-r--r--vere/pkg/noun/jets/e/mule.c19
-rw-r--r--vere/pkg/noun/jets/e/parse.c1052
-rw-r--r--vere/pkg/noun/jets/e/rd.c390
-rw-r--r--vere/pkg/noun/jets/e/rh.c390
-rw-r--r--vere/pkg/noun/jets/e/ripe.c45
-rw-r--r--vere/pkg/noun/jets/e/rq.c446
-rw-r--r--vere/pkg/noun/jets/e/rs.c390
-rw-r--r--vere/pkg/noun/jets/e/rub.c85
-rw-r--r--vere/pkg/noun/jets/e/scot.c30
-rw-r--r--vere/pkg/noun/jets/e/scow.c251
-rw-r--r--vere/pkg/noun/jets/e/scr.c227
-rw-r--r--vere/pkg/noun/jets/e/secp.c298
-rw-r--r--vere/pkg/noun/jets/e/sha1.c40
-rw-r--r--vere/pkg/noun/jets/e/shax.c194
-rw-r--r--vere/pkg/noun/jets/e/slaw.c477
-rw-r--r--vere/pkg/noun/jets/e/tape.c53
-rw-r--r--vere/pkg/noun/jets/e/trip.c33
-rw-r--r--vere/pkg/noun/jets/e/urwasm.c3086
-rw-r--r--vere/pkg/noun/jets/e/zlib.c225
-rw-r--r--vere/pkg/noun/jets/f/cell.c29
-rw-r--r--vere/pkg/noun/jets/f/comb.c70
-rw-r--r--vere/pkg/noun/jets/f/cons.c54
-rw-r--r--vere/pkg/noun/jets/f/core.c118
-rw-r--r--vere/pkg/noun/jets/f/face.c31
-rw-r--r--vere/pkg/noun/jets/f/fine.c35
-rw-r--r--vere/pkg/noun/jets/f/fitz.c75
-rw-r--r--vere/pkg/noun/jets/f/flan.c47
-rw-r--r--vere/pkg/noun/jets/f/flip.c39
-rw-r--r--vere/pkg/noun/jets/f/flor.c47
-rw-r--r--vere/pkg/noun/jets/f/fork.c79
-rw-r--r--vere/pkg/noun/jets/f/help.c31
-rw-r--r--vere/pkg/noun/jets/f/hint.c32
-rw-r--r--vere/pkg/noun/jets/f/look.c134
-rw-r--r--vere/pkg/noun/jets/f/loot.c133
-rw-r--r--vere/pkg/noun/jets/f/ut_crop.c34
-rw-r--r--vere/pkg/noun/jets/f/ut_fish.c35
-rw-r--r--vere/pkg/noun/jets/f/ut_fuse.c34
-rw-r--r--vere/pkg/noun/jets/f/ut_mint.c36
-rw-r--r--vere/pkg/noun/jets/f/ut_mull.c37
-rw-r--r--vere/pkg/noun/jets/f/ut_nest.c50
-rw-r--r--vere/pkg/noun/jets/f/ut_redo.c34
-rw-r--r--vere/pkg/noun/jets/f/ut_rest.c34
-rw-r--r--vere/pkg/noun/jets/g/plot.c364
-rw-r--r--vere/pkg/noun/jets/i/lagoon.c3315
-rw-r--r--vere/pkg/noun/jets/k.h185
-rw-r--r--vere/pkg/noun/jets/q.h306
-rw-r--r--vere/pkg/noun/jets/tree.c2658
-rw-r--r--vere/pkg/noun/jets/w.h433
-rw-r--r--vere/pkg/noun/jets_tests.c994
-rw-r--r--vere/pkg/noun/log.c40
-rw-r--r--vere/pkg/noun/log.h24
-rw-r--r--vere/pkg/noun/manage.c2615
-rw-r--r--vere/pkg/noun/manage.h215
-rw-r--r--vere/pkg/noun/nock.c3268
-rw-r--r--vere/pkg/noun/nock.h149
-rw-r--r--vere/pkg/noun/nock_tests.c83
-rw-r--r--vere/pkg/noun/noun.h26
-rw-r--r--vere/pkg/noun/options.c5
-rw-r--r--vere/pkg/noun/options.h59
-rw-r--r--vere/pkg/noun/palloc.c2400
-rw-r--r--vere/pkg/noun/palloc_tests.c91
-rw-r--r--vere/pkg/noun/platform/darwin/rsignal.h13
-rw-r--r--vere/pkg/noun/platform/linux/rsignal.h13
-rw-r--r--vere/pkg/noun/platform/windows/rsignal.c167
-rw-r--r--vere/pkg/noun/platform/windows/rsignal.h21
-rw-r--r--vere/pkg/noun/platform/windows/veh_handler.c26
-rw-r--r--vere/pkg/noun/platform/windows/veh_handler.h1
-rw-r--r--vere/pkg/noun/retrieve.c1943
-rw-r--r--vere/pkg/noun/retrieve.h547
-rw-r--r--vere/pkg/noun/retrieve_tests.c247
-rw-r--r--vere/pkg/noun/serial.c1456
-rw-r--r--vere/pkg/noun/serial.h137
-rw-r--r--vere/pkg/noun/serial_tests.c264
-rw-r--r--vere/pkg/noun/ship.c109
-rw-r--r--vere/pkg/noun/ship.h57
-rw-r--r--vere/pkg/noun/trace.c1242
-rw-r--r--vere/pkg/noun/trace.h230
-rw-r--r--vere/pkg/noun/types.h64
-rw-r--r--vere/pkg/noun/urth.c1042
-rw-r--r--vere/pkg/noun/urth.h49
-rw-r--r--vere/pkg/noun/version.h43
-rw-r--r--vere/pkg/noun/verstable.h1949
-rw-r--r--vere/pkg/noun/vortex.c411
-rw-r--r--vere/pkg/noun/vortex.h135
-rw-r--r--vere/pkg/noun/xtract.c33
-rw-r--r--vere/pkg/noun/xtract.h162
-rw-r--r--vere/pkg/noun/zave.c157
-rw-r--r--vere/pkg/noun/zave.h69
245 files changed, 63301 insertions, 0 deletions
diff --git a/vere/pkg/noun/allocate.c b/vere/pkg/noun/allocate.c
new file mode 100644
index 0000000..96a09b2
--- /dev/null
+++ b/vere/pkg/noun/allocate.c
@@ -0,0 +1,2012 @@
+/// @file
+
+#include "allocate.h"
+
+#include "hashtable.h"
+#include "log.h"
+#include "manage.h"
+#include "options.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "vortex.h"
+
+#include "palloc.c"
+
+u3_road* u3a_Road;
+u3a_mark u3a_Mark;
+u3a_gack u3a_Gack;
+u3a_hunk_dose u3a_Hunk[u3a_crag_no];
+
+#ifdef U3_MEMORY_DEBUG
+c3_w u3_Code;
+#endif
+
+c3_w u3a_to_pug(c3_w off);
+c3_w u3a_to_pom(c3_w off);
+
+void
+u3a_drop(const u3a_pile* pil_u);
+void*
+u3a_peek(const u3a_pile* pil_u);
+void*
+u3a_pop(const u3a_pile* pil_u);
+void*
+u3a_push(const u3a_pile* pil_u);
+c3_o
+u3a_pile_done(const u3a_pile* pil_u);
+
+void*
+u3a_into_fn(u3_post som_p)
+{
+ return u3a_into(som_p);
+}
+
+u3_post
+u3a_outa_fn(void* som_v)
+{
+ return u3a_outa(som_v);
+}
+
+u3_post
+u3a_to_off_fn(u3_noun som)
+{
+ return u3a_to_off(som);
+}
+
+u3a_noun*
+u3a_to_ptr_fn(u3_noun som)
+{
+ return u3a_to_ptr(som);
+}
+
+u3_noun
+u3a_head(u3_noun som)
+{
+ return u3h(som);
+}
+
+u3_noun
+u3a_tail(u3_noun som)
+{
+ return u3t(som);
+}
+
+void
+u3a_post_info(u3_post som_p)
+{
+ _post_status(som_p);
+}
+
+void
+u3a_init_once(void)
+{
+ _init_once();
+}
+
+void
+u3a_init_heap(void)
+{
+ _init_heap();
+}
+
+void
+u3a_drop_heap(u3_post cap_p, u3_post ear_p)
+{
+#ifdef ASAN_ENABLED
+ if ( cap_p > ear_p ) { // in north, drop inner south
+ _drop(ear_p, cap_p - ear_p);
+ }
+ else { // in south, drop inner north
+ _drop(cap_p, ear_p - cap_p);
+ }
+#else
+ (void)cap_p;
+ (void)ear_p;
+#endif
+}
+
+void
+u3a_mark_init(void)
+{
+ c3_w bit_w = (u3R->hep.len_w + 31) >> 5;
+
+ u3a_Mark.bit_w = c3_calloc(sizeof(c3_w) * bit_w);
+ u3a_Mark.siz_w = u3R->hep.siz_w * 2;
+ u3a_Mark.len_w = u3R->hep.len_w;
+ u3a_Mark.buf_w = c3_calloc(sizeof(c3_w) * u3a_Mark.siz_w);
+
+ memset(u3a_Mark.wee_w, 0, sizeof(c3_w) * u3a_crag_no);
+}
+
+void
+u3a_mark_done(void)
+{
+ c3_free(u3a_Mark.bit_w);
+ c3_free(u3a_Mark.buf_w);
+ memset(&u3a_Mark, 0, sizeof(u3a_Mark));
+}
+
+void*
+u3a_mark_alloc(c3_w len_w) // words
+{
+ void* ptr_v;
+
+ if ( len_w > (u3a_Mark.siz_w - u3a_Mark.len_w) ) {
+ u3a_Mark.siz_w += c3_max(u3a_Mark.len_w, len_w);
+ u3a_Mark.buf_w = c3_realloc(u3a_Mark.buf_w, sizeof(c3_w) * u3a_Mark.siz_w);
+ }
+
+ ptr_v = &(u3a_Mark.buf_w[u3a_Mark.len_w]);
+ u3a_Mark.len_w += len_w;
+
+ return ptr_v;
+}
+
+void
+u3a_pack_init(void)
+{
+ c3_w bit_w = (u3R->hep.len_w + 31) >> 5;
+ u3a_Gack.bit_w = c3_calloc(sizeof(c3_w) * bit_w);
+ u3a_Gack.pap_w = c3_calloc(sizeof(c3_w) * bit_w);
+ u3a_Gack.pum_w = c3_calloc(sizeof(c3_w) * bit_w);
+
+ u3a_Gack.siz_w = u3R->hep.siz_w * 2;
+ u3a_Gack.len_w = u3R->hep.len_w;
+ u3a_Gack.buf_w = c3_calloc(sizeof(c3_w) * u3a_Gack.siz_w);
+}
+
+void*
+u3a_pack_alloc(c3_w len_w) // words
+{
+ void* ptr_v;
+
+ if ( len_w > (u3a_Gack.siz_w - u3a_Gack.len_w) ) {
+ u3a_Gack.siz_w += c3_max(u3a_Gack.len_w, len_w);
+ u3a_Gack.buf_w = c3_realloc(u3a_Gack.buf_w, sizeof(c3_w) * u3a_Gack.siz_w);
+ }
+
+ ptr_v = &(u3a_Gack.buf_w[u3a_Gack.len_w]);
+ u3a_Gack.len_w += len_w;
+
+ return ptr_v;
+}
+
+void
+u3a_pack_done(void)
+{
+ c3_free(u3a_Gack.pap_w);
+ c3_free(u3a_Gack.pum_w);
+ c3_free(u3a_Gack.buf_w);
+}
+
+/* _box_count(): adjust memory count.
+*/
+#ifdef U3_CPU_DEBUG
+static void
+_box_count(c3_ws siz_ws)
+{
+ u3R->all.fre_w += siz_ws;
+
+ {
+ c3_w end_w = u3a_heap(u3R);
+ c3_w all_w = (end_w - u3R->all.fre_w);
+
+ if ( all_w > u3R->all.max_w ) {
+ u3R->all.max_w = all_w;
+ }
+ }
+}
+#else
+static void
+_box_count(c3_ws siz_ws) { }
+#endif
+
+/* _ca_reclaim_half(): reclaim from memoization cache.
+*/
+static void
+_ca_reclaim_half(void)
+{
+ // XX u3l_log avoid here, as it can
+ // cause problems when handling errors
+
+ if ( (0 == u3R->cax.har_p) ||
+ (0 == u3to(u3h_root, u3R->cax.har_p)->use_w) )
+ {
+ fprintf(stderr, "allocate: reclaim: memo cache: empty\r\n");
+ u3m_bail(c3__meme);
+ }
+
+#if 1
+ fprintf(stderr, "allocate: reclaim: half of %d entries\r\n",
+ u3to(u3h_root, u3R->cax.har_p)->use_w);
+
+ u3h_trim_to(u3R->cax.har_p, u3to(u3h_root, u3R->cax.har_p)->use_w / 2);
+#else
+ /* brutal and guaranteed effective
+ */
+ u3h_free(u3R->cax.har_p);
+ u3R->cax.har_p = u3h_new();
+#endif
+}
+
+/* u3a_walloc(): allocate storage words on hat heap.
+*/
+void*
+u3a_walloc(c3_w len_w)
+{
+ return u3a_into(_imalloc(len_w));
+}
+
+/* u3a_wealloc(): realloc in words.
+*/
+void*
+u3a_wealloc(void* lag_v, c3_w len_w)
+{
+ if ( !lag_v ) {
+ return u3a_walloc(len_w);
+ }
+
+ return u3a_into(_irealloc(u3a_outa(lag_v), len_w));
+}
+
+/* u3a_pile_prep(): initialize stack control.
+*/
+void
+u3a_pile_prep(u3a_pile* pil_u, c3_w len_w)
+{
+ // frame size, in words
+ //
+ c3_w wor_w = (len_w + 3) >> 2;
+ c3_o nor_o = u3a_is_north(u3R);
+
+ pil_u->mov_ws = (c3y == nor_o) ? -wor_w : wor_w;
+ pil_u->off_ws = (c3y == nor_o) ? 0 : -wor_w;
+ pil_u->top_p = u3R->cap_p;
+
+#ifdef U3_MEMORY_DEBUG
+ pil_u->rod_u = u3R;
+#endif
+}
+
+/* u3a_wfree(): free storage.
+*/
+void
+u3a_wfree(void* tox_v)
+{
+ if ( tox_v ) {
+ _ifree(u3a_outa(tox_v));
+ }
+}
+
+/* u3a_wtrim(): trim storage.
+
+ old_w - old length
+ len_w - new length
+*/
+void
+u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w)
+{
+ // XX realloc?
+}
+
+/* u3a_calloc(): allocate and zero-initialize array
+*/
+void*
+u3a_calloc(size_t num_i, size_t len_i)
+{
+ size_t byt_i = num_i * len_i;
+ c3_w* out_w;
+
+ u3_assert(byt_i / len_i == num_i);
+ out_w = u3a_malloc(byt_i);
+ memset(out_w, 0, byt_i);
+
+ return out_w;
+}
+
+/* u3a_malloc(): aligned storage measured in bytes.
+
+ Internally pads allocations to 16-byte alignment independent of DWORD
+ alignment ensured for word sized allocations.
+
+*/
+void*
+u3a_malloc(size_t len_i)
+{
+ return u3a_walloc((len_i + 3) >> 2);
+}
+
+/* u3a_celloc(): allocate a cell.
+*/
+c3_w*
+u3a_celloc(void)
+{
+ u3a_cell *cel_u;
+ u3_post *cel_p;
+
+ if ( u3R->cel.cel_p ) {
+ cel_p = u3to(u3_post, u3R->cel.cel_p);
+
+ if ( !u3R->cel.hav_w ) {
+ _rake_chunks(c3_wiseof(*cel_u), (1U << u3a_page),
+ (u3R->cel.bat_w++ & 1), &u3R->cel.hav_w, cel_p);
+ }
+
+ cel_u = u3to(u3a_cell, cel_p[--u3R->cel.hav_w]);
+ }
+ else {
+ cel_u = u3a_walloc(c3_wiseof(*cel_u));
+ }
+
+#ifdef U3_CPU_DEBUG
+ u3R->pro.cel_d++;
+#endif
+
+ return (c3_w*)cel_u;
+}
+
+
+/* u3a_cfree(): free a cell.
+*/
+void
+u3a_cfree(c3_w* cel_w)
+{
+ u3_post *cel_p;
+
+ if ( u3R->cel.cel_p ) {
+ if ( u3R->cel.hav_w < (1U << u3a_page) ) {
+ cel_p = u3to(u3_post, u3R->cel.cel_p);
+ cel_p[u3R->cel.hav_w++] = u3a_outa(cel_w);
+ return;
+ }
+ }
+
+ u3a_wfree(cel_w);
+}
+
+/* u3a_realloc(): aligned realloc in bytes.
+*/
+void*
+u3a_realloc(void* lag_v, size_t len_i)
+{
+ if ( !lag_v ) {
+ return u3a_malloc(len_i);
+ }
+
+ return u3a_wealloc(lag_v, (len_i + 3) >> 2);
+}
+
+/* u3a_free(): free for aligned malloc.
+*/
+void
+u3a_free(void* tox_v)
+{
+ u3a_wfree((c3_w*)tox_v);
+}
+
+/* _me_wash_north(): clean up mug slots after copy.
+*/
+static void _me_wash_north(u3_noun dog);
+static void
+_me_wash_north_in(u3_noun som)
+{
+ if ( _(u3a_is_cat(som)) ) return;
+ if ( !_(u3a_north_is_junior(u3R, som)) ) return;
+
+ _me_wash_north(som);
+}
+static void
+_me_wash_north(u3_noun dog)
+{
+ u3_assert(c3y == u3a_is_dog(dog));
+ // u3_assert(c3y == u3a_north_is_junior(u3R, dog));
+ {
+ u3a_noun* dog_u = u3a_to_ptr(dog);
+
+ if ( dog_u->mug_w == 0 ) return;
+
+ dog_u->mug_w = 0; // power wash
+ // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; }
+
+ if ( _(u3a_is_pom(dog)) ) {
+ u3a_cell* god_u = (u3a_cell *)(void *)dog_u;
+
+ _me_wash_north_in(god_u->hed);
+ _me_wash_north_in(god_u->tel);
+ }
+ }
+}
+
+/* _me_wash_south(): clean up mug slots after copy.
+*/
+static void _me_wash_south(u3_noun dog);
+static void
+_me_wash_south_in(u3_noun som)
+{
+ if ( _(u3a_is_cat(som)) ) return;
+ if ( !_(u3a_south_is_junior(u3R, som)) ) return;
+
+ _me_wash_south(som);
+}
+static void
+_me_wash_south(u3_noun dog)
+{
+ u3_assert(c3y == u3a_is_dog(dog));
+ // u3_assert(c3y == u3a_south_is_junior(u3R, dog));
+ {
+ u3a_noun* dog_u = u3a_to_ptr(dog);
+
+ if ( dog_u->mug_w == 0 ) return;
+
+ dog_u->mug_w = 0; // power wash
+ // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; }
+
+ if ( _(u3a_is_pom(dog)) ) {
+ u3a_cell* god_u = (u3a_cell *)(void *)dog_u;
+
+ _me_wash_south_in(god_u->hed);
+ _me_wash_south_in(god_u->tel);
+ }
+ }
+}
+
+/* u3a_wash(): wash all lazy mugs. RETAIN.
+*/
+void
+u3a_wash(u3_noun som)
+{
+ if ( _(u3a_is_cat(som)) ) {
+ return;
+ }
+ if ( _(u3a_is_north(u3R)) ) {
+ if ( _(u3a_north_is_junior(u3R, som)) ) {
+ _me_wash_north(som);
+ }
+ }
+ else {
+ if ( _(u3a_south_is_junior(u3R, som)) ) {
+ _me_wash_south(som);
+ }
+ }
+}
+
+/* _me_gain_use(): increment use count.
+*/
+static void
+_me_gain_use(u3_noun dog)
+{
+ u3a_noun* box_u = u3a_to_ptr(dog);
+
+ if ( 0x7fffffff == box_u->use_w ) {
+ u3l_log("fail in _me_gain_use");
+ u3m_bail(c3__fail);
+ }
+ else {
+ if ( box_u->use_w == 0 ) {
+ u3m_bail(c3__foul);
+ }
+ box_u->use_w += 1;
+
+#ifdef U3_MEMORY_DEBUG
+ // enable to (maybe) help track down leaks
+ //
+ // if ( u3_Code && !box_u->cod_w ) { box_u->cod_w = u3_Code; }
+#endif
+ }
+}
+
+#undef VERBOSE_TAKE
+
+/* _ca_take_atom(): reallocate an indirect atom off the stack.
+*/
+static inline u3_atom
+_ca_take_atom(u3a_atom* old_u)
+{
+ c3_w* new_w = u3a_walloc(old_u->len_w + c3_wiseof(u3a_atom));
+ u3a_atom* new_u = (u3a_atom*)(void *)new_w;
+ u3_noun new = u3a_to_pug(u3a_outa(new_u));
+
+ new_u->use_w = 1;
+
+#ifdef VERBOSE_TAKE
+ u3l_log("%s: atom %p to %p", ( c3y == u3a_is_north(u3R) )
+ ? "north"
+ : "south",
+ old_u,
+ new_u);
+#endif
+
+ // XX use memcpy?
+ //
+ new_u->mug_w = old_u->mug_w;
+ new_u->len_w = old_u->len_w;
+ {
+ c3_w i_w;
+
+ for ( i_w=0; i_w < old_u->len_w; i_w++ ) {
+ new_u->buf_w[i_w] = old_u->buf_w[i_w];
+ }
+ }
+
+ // borrow mug slot to record new destination in [old_u]
+ //
+ old_u->mug_w = new;
+
+ return new;
+}
+
+/* _ca_take_cell(): reallocate a cell off the stack.
+*/
+static inline u3_cell
+_ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel)
+{
+ c3_w* new_w = u3a_celloc();
+ u3a_cell* new_u = (u3a_cell*)(void *)new_w;
+ u3_cell new = u3a_to_pom(u3a_outa(new_u));
+
+#ifdef VERBOSE_TAKE
+ u3l_log("%s: cell %p to %p", ( c3y == u3a_is_north(u3R) )
+ ? "north"
+ : "south",
+ old_u,
+ new_u);
+#endif
+
+ new_u->use_w = 1;
+ new_u->mug_w = old_u->mug_w;
+ new_u->hed = hed;
+ new_u->tel = tel;
+
+ // borrow mug slot to record new destination in [old_u]
+ //
+ old_u->mug_w = new;
+
+ return new;
+}
+
+/* _ca_take: stack frame for recording cell travesal
+** (u3_none == hed) == head-frame
+*/
+typedef struct _ca_take
+{
+ u3_weak hed; // taken head
+ u3_cell old; // old cell
+} _ca_take;
+
+/* _ca_take_next_south: take next noun, pushing cells on stack.
+*/
+static inline u3_noun
+_ca_take_next_north(u3a_pile* pil_u, u3_noun veb)
+{
+ while ( 1 ) {
+ // direct atoms and senior refs are not counted.
+ //
+ if ( (c3y == u3a_is_cat(veb))
+ || (c3y == u3a_north_is_senior(u3R, veb)) )
+ {
+ return veb;
+ }
+ // not junior; normal (heap) refs on our road are counted.
+ //
+ else if ( c3n == u3a_north_is_junior(u3R, veb) ) {
+ _me_gain_use(veb); // bypass branches in u3k()
+ return veb;
+ }
+ // junior (stack) refs are copied.
+ //
+ else {
+ u3a_noun* veb_u = u3a_to_ptr(veb);
+
+ // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref.
+ //
+ if ( veb_u->mug_w >> 31 ) {
+ u3_noun nov = (u3_noun)veb_u->mug_w;
+
+ u3_assert( c3y == u3a_north_is_normal(u3R, nov) );
+
+#ifdef VERBOSE_TAKE
+ u3l_log("north: %p is already %p", veb_u, u3a_to_ptr(nov));
+#endif
+
+ _me_gain_use(nov); // bypass branches in u3k()
+ return nov;
+ }
+ else if ( c3y == u3a_is_atom(veb) ) {
+ return _ca_take_atom((u3a_atom*)veb_u);
+ }
+ else {
+ u3a_cell* old_u = (u3a_cell*)veb_u;
+ _ca_take* fam_u = u3a_push(pil_u);
+
+ fam_u->hed = u3_none;
+ fam_u->old = veb;
+
+ veb = old_u->hed;
+ continue;
+ }
+ }
+ }
+}
+
+/* _ca_take_next_south: take next noun, pushing cells on stack.
+*/
+static inline u3_noun
+_ca_take_next_south(u3a_pile* pil_u, u3_noun veb)
+{
+ while ( 1 ) {
+ // direct atoms and senior refs are not counted.
+ //
+ if ( (c3y == u3a_is_cat(veb))
+ || (c3y == u3a_south_is_senior(u3R, veb)) )
+ {
+ return veb;
+ }
+ // not junior; a normal pointer in our road -- refcounted
+ //
+ else if ( c3n == u3a_south_is_junior(u3R, veb) ) {
+ _me_gain_use(veb); // bypass branches in u3k()
+ return veb;
+ }
+ // junior (stack) refs are copied.
+ //
+ else {
+ u3a_noun* veb_u = u3a_to_ptr(veb);
+
+ // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref.
+ //
+ if ( veb_u->mug_w >> 31 ) {
+ u3_noun nov = (u3_noun)veb_u->mug_w;
+
+ u3_assert( c3y == u3a_south_is_normal(u3R, nov) );
+
+#ifdef VERBOSE_TAKE
+ u3l_log("south: %p is already %p", veb_u, u3a_to_ptr(nov));
+#endif
+
+ _me_gain_use(nov); // bypass branches in u3k()
+ return nov;
+ }
+ else if ( c3y == u3a_is_atom(veb) ) {
+ return _ca_take_atom((u3a_atom*)veb_u);
+ }
+ else {
+ u3a_cell* old_u = (u3a_cell*)veb_u;
+ _ca_take* fam_u = u3a_push(pil_u);
+
+ fam_u->hed = u3_none;
+ fam_u->old = veb;
+
+ veb = old_u->hed;
+ continue;
+ }
+ }
+ }
+}
+
+/* _ca_take_north(): in a north road, gain, copying juniors (from stack).
+*/
+static u3_noun
+_ca_take_north(u3_noun veb)
+{
+ u3_noun pro;
+ _ca_take* fam_u;
+ u3a_pile pil_u;
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // commence taking
+ //
+ pro = _ca_take_next_north(&pil_u, veb);
+
+ // process cell results
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // head-frame: stash copy and continue into the tail
+ //
+ if ( u3_none == fam_u->hed ) {
+ u3a_cell* old_u = u3a_to_ptr(fam_u->old);
+ fam_u->hed = pro;
+ pro = _ca_take_next_north(&pil_u, old_u->tel);
+ fam_u = u3a_peek(&pil_u);
+ }
+ // tail-frame: copy cell and pop the stack
+ //
+ else {
+ u3a_cell* old_u = u3a_to_ptr(fam_u->old);
+ pro = _ca_take_cell(old_u, fam_u->hed, pro);
+ fam_u = u3a_pop(&pil_u);
+ }
+ } while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ return pro;
+}
+/* _ca_take_south(): in a south road, gain, copying juniors (from stack).
+*/
+static u3_noun
+_ca_take_south(u3_noun veb)
+{
+ u3_noun pro;
+ _ca_take* fam_u;
+ u3a_pile pil_u;
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // commence taking
+ //
+ pro = _ca_take_next_south(&pil_u, veb);
+
+ // process cell results
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // head-frame: stash copy and continue into the tail
+ //
+ if ( u3_none == fam_u->hed ) {
+ u3a_cell* old_u = u3a_to_ptr(fam_u->old);
+ fam_u->hed = pro;
+ pro = _ca_take_next_south(&pil_u, old_u->tel);
+ fam_u = u3a_peek(&pil_u);
+ }
+ // tail-frame: copy cell and pop the stack
+ //
+ else {
+ u3a_cell* old_u = u3a_to_ptr(fam_u->old);
+ pro = _ca_take_cell(old_u, fam_u->hed, pro);
+ fam_u = u3a_pop(&pil_u);
+ }
+ } while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ return pro;
+}
+
+/* u3a_take(): gain, copying juniors.
+*/
+u3_noun
+u3a_take(u3_noun veb)
+{
+ u3_noun pro;
+ u3t_on(coy_o);
+
+ u3_assert(u3_none != veb);
+
+ pro = ( c3y == u3a_is_north(u3R) )
+ ? _ca_take_north(veb)
+ : _ca_take_south(veb);
+
+ u3t_off(coy_o);
+ return pro;
+}
+
+/* u3a_left(): true of junior if preserved.
+*/
+c3_o
+u3a_left(u3_noun som)
+{
+ if ( _(u3a_is_cat(som)) ||
+ !_(u3a_is_junior(u3R, som)) )
+ {
+ return c3y;
+ }
+ else {
+ u3a_noun* dog_u = u3a_to_ptr(som);
+
+ return __(0 != (dog_u->mug_w >> 31));
+ }
+}
+
+/* _me_gain_north(): gain on a north road.
+*/
+static u3_noun
+_me_gain_north(u3_noun dog)
+{
+ if ( c3y == u3a_north_is_senior(u3R, dog) ) {
+ /* senior pointers are not refcounted
+ */
+ return dog;
+ }
+ else {
+ /* junior nouns are disallowed
+ */
+ u3_assert(!_(u3a_north_is_junior(u3R, dog)));
+
+ /* normal pointers are refcounted
+ */
+ _me_gain_use(dog);
+ return dog;
+ }
+}
+
+/* _me_gain_south(): gain on a south road.
+*/
+static u3_noun
+_me_gain_south(u3_noun dog)
+{
+ if ( c3y == u3a_south_is_senior(u3R, dog) ) {
+ /* senior pointers are not refcounted
+ */
+ return dog;
+ }
+ else {
+ /* junior nouns are disallowed
+ */
+ u3_assert(!_(u3a_south_is_junior(u3R, dog)));
+
+ /* normal nouns are refcounted
+ */
+ _me_gain_use(dog);
+ return dog;
+ }
+}
+
+/* _me_lose_north(): lose on a north road.
+*/
+static void
+_me_lose_north(u3_noun dog)
+{
+top:
+ if ( c3y == u3a_north_is_normal(u3R, dog) ) {
+ u3a_noun* box_u = u3a_to_ptr(dog);
+
+ if ( box_u->use_w > 1 ) {
+ box_u->use_w -= 1;
+ }
+ else {
+ if ( 0 == box_u->use_w ) {
+ u3m_bail(c3__foul);
+ }
+ else {
+ if ( _(u3a_is_pom(dog)) ) {
+ u3a_cell* dog_u = (void*)box_u;
+ u3_noun h_dog = dog_u->hed;
+ u3_noun t_dog = dog_u->tel;
+
+ if ( !_(u3a_is_cat(h_dog)) ) {
+ _me_lose_north(h_dog);
+ }
+ u3a_cfree((c3_w*)dog_u);
+ if ( !_(u3a_is_cat(t_dog)) ) {
+ dog = t_dog;
+ goto top;
+ }
+ }
+ else {
+ u3a_wfree(box_u);
+ }
+ }
+ }
+ }
+}
+
+/* _me_lose_south(): lose on a south road.
+*/
+static void
+_me_lose_south(u3_noun dog)
+{
+top:
+ if ( c3y == u3a_south_is_normal(u3R, dog) ) {
+ u3a_noun* box_u = u3a_to_ptr(dog);
+
+ if ( box_u->use_w > 1 ) {
+ box_u->use_w -= 1;
+ }
+ else {
+ if ( 0 == box_u->use_w ) {
+ u3m_bail(c3__foul);
+ }
+ else {
+ if ( _(u3a_is_pom(dog)) ) {
+ u3a_cell* dog_u = (void*)box_u;
+ u3_noun h_dog = dog_u->hed;
+ u3_noun t_dog = dog_u->tel;
+
+ if ( !_(u3a_is_cat(h_dog)) ) {
+ _me_lose_south(h_dog);
+ }
+ u3a_cfree((c3_w*)dog_u);
+ if ( !_(u3a_is_cat(t_dog)) ) {
+ dog = t_dog;
+ goto top;
+ }
+ }
+ else {
+ u3a_wfree(box_u);
+ }
+ }
+ }
+ }
+}
+
+/* u3a_gain(): gain a reference count in normal space.
+*/
+u3_noun
+u3a_gain(u3_noun som)
+{
+ u3t_on(mal_o);
+ u3_assert(u3_none != som);
+
+ if ( !_(u3a_is_cat(som)) ) {
+ som = _(u3a_is_north(u3R))
+ ? _me_gain_north(som)
+ : _me_gain_south(som);
+ }
+ u3t_off(mal_o);
+
+ return som;
+}
+
+/* u3a_lose(): lose a reference count.
+*/
+void
+u3a_lose(u3_noun som)
+{
+ u3t_on(mal_o);
+ if ( !_(u3a_is_cat(som)) ) {
+ if ( _(u3a_is_north(u3R)) ) {
+ _me_lose_north(som);
+ } else {
+ _me_lose_south(som);
+ }
+ }
+ u3t_off(mal_o);
+}
+
+/* u3a_use(): reference count.
+*/
+c3_w
+u3a_use(u3_noun som)
+{
+ if ( _(u3a_is_cat(som)) ) {
+ return 1;
+ }
+ else {
+ u3a_noun* box_u = u3a_to_ptr(som);
+ return box_u->use_w;
+ }
+}
+
+#define SWAP(l, r) \
+ do { typeof(l) t = l; l = r; r = t; } while (0)
+
+/* _ca_wed_our(): unify [a] and [b] on u3R.
+*/
+static inline c3_o
+_ca_wed_our(u3_noun *restrict a, u3_noun *restrict b)
+{
+ c3_t asr_t = ( c3y == u3a_is_senior(u3R, *a) );
+ c3_t bsr_t = ( c3y == u3a_is_senior(u3R, *b) );
+
+ if ( asr_t == bsr_t ) {
+ // both [a] and [b] are senior; we can't unify on u3R
+ //
+ if ( asr_t ) return c3n;
+
+ // both are on u3R; keep the deeper address
+ // (and gain a reference)
+ //
+ // (N && <) || (S && >)
+ // XX consider keeping higher refcount instead
+ //
+ if ( (*a > *b) == (c3y == u3a_is_north(u3R)) ) SWAP(a, b);
+
+ _me_gain_use(*a);
+ }
+ // one of [a] or [b] are senior; keep it
+ //
+ else if ( !asr_t ) SWAP(a, b);
+
+ u3z(*b);
+ *b = *a;
+ return c3y;
+}
+
+/* _ca_wed_you(): unify [a] and [b] on senior [rod_u]. leaks
+*/
+static c3_o
+_ca_wed_you(u3a_road* rod_u, u3_noun *restrict a, u3_noun *restrict b)
+{
+ // XX assume( rod_u != u3R )
+ c3_t asr_t = ( c3y == u3a_is_senior(rod_u, *a) );
+ c3_t bsr_t = ( c3y == u3a_is_senior(rod_u, *b) );
+
+ if ( asr_t == bsr_t ) {
+ // both [a] and [b] are senior; we can't unify on [rod_u]
+ //
+ if ( asr_t ) return c3n;
+
+ // both are on [rod_u]; keep the deeper address
+ // (and gain a reference)
+ //
+ // (N && <) || (S && >)
+ // XX consider keeping higher refcount instead
+ //
+ if ( (*a > *b) == (c3y == u3a_is_north(rod_u)) ) SWAP(a, b);
+
+ _me_gain_use(*a);
+ }
+ // one of [a] or [b] are senior; keep it
+ //
+ else if ( !asr_t ) SWAP(a, b);
+
+ *b = *a;
+ return c3y;
+}
+
+#undef SWAP
+
+/* u3a_wed(): unify noun references.
+*/
+void
+u3a_wed(u3_noun *restrict a, u3_noun *restrict b)
+{
+ // XX assume( *a != *b )
+ u3_road* rod_u = u3R;
+ c3_o wed_o;
+
+ if ( rod_u->kid_p ) return;
+
+ wed_o = _ca_wed_our(a, b);
+
+#ifdef U3_MEMORY_DEBUG
+ return;
+#else
+ if ( u3C.wag_w & u3o_debug_ram ) return;
+#endif
+
+ // while not at home, attempt to unify
+ //
+ // we try to unify on our road, and retry on senior roads
+ // until we succeed or reach the home road.
+ //
+ // we can't perform this kind of butchery on the home road,
+ // where asynchronous things can allocate.
+ // (XX anything besides u3t_samp?)
+ //
+ // when unifying on a higher road, we can't free nouns,
+ // because we can't track junior nouns that point into
+ // that road.
+ //
+ // this is just an implementation issue -- we could set use
+ // counts to 0 without actually freeing. but the allocator
+ // would have to be actually designed for this.
+ // (alternately, we could keep a deferred free-list)
+ //
+ // not freeing may generate spurious leaks, so we disable
+ // senior unification when debugging memory. this will
+ // cause a very slow boot process as the compiler compiles
+ // itself, constantly running into duplicates.
+ //
+
+ while ( (c3n == wed_o)
+ && rod_u->par_p
+ && (&u3H->rod_u != (rod_u = u3to(u3_road, rod_u->par_p))) )
+ {
+ wed_o = _ca_wed_you(rod_u, a, b);
+ }
+}
+
+/* u3a_luse(): check refcount sanity.
+*/
+void
+u3a_luse(u3_noun som)
+{
+ if ( 0 == u3a_use(som) ) {
+ fprintf(stderr, "loom: insane %d 0x%x\r\n", som, som);
+ abort();
+ }
+ if ( _(u3du(som)) ) {
+ u3a_luse(u3h(som));
+ u3a_luse(u3t(som));
+ }
+}
+
+/* u3a_mark_ptr(): mark a pointer for gc. Produce size if first mark.
+*/
+c3_w
+u3a_mark_ptr(void* ptr_v)
+{
+ // XX restore loom-bounds check
+ u3_post som_p = u3a_outa(ptr_v);
+ c3_w siz_w = !(u3C.wag_w & u3o_debug_ram)
+ ? _mark_post(som_p)
+ : _count_post(som_p, 0);
+
+ return siz_w;
+}
+
+/* u3a_relocate_post(): replace post with relocation pointer (unchecked).
+*/
+void
+u3a_relocate_post(u3_post *som_p)
+{
+ *som_p = _pack_relocate(*som_p);
+}
+
+/* u3a_mark_relocate_post(): replace post with relocation pointer (checked).
+*/
+u3_post
+u3a_mark_relocate_post(u3_post som_p, c3_t *fir_t)
+{
+ return _pack_relocate_mark(som_p, fir_t);
+}
+
+/* u3a_relocate_noun(): replace noun with relocation reference, recursively.
+*/
+void
+u3a_relocate_noun(u3_noun *som)
+{
+ u3_post old_p, new_p;
+ u3_noun old;
+ u3a_cell* cel_u;
+ c3_t fir_t;
+
+ while ( 1 ) {
+ old = *som;
+
+ if ( c3y == u3a_is_cat(old) ) return;
+
+ old_p = u3a_to_off(old);
+
+ if ( c3n == u3a_is_cell(old) ) {
+ new_p = _pack_relocate(old_p);
+ *som = u3a_to_pug(new_p);
+ return;
+ }
+
+ new_p = _pack_relocate_mark(old_p, &fir_t);
+ *som = u3a_to_pom(new_p);
+
+ if ( !fir_t ) return;
+
+ cel_u = u3to(u3a_cell, old_p);
+ u3a_relocate_noun(&(cel_u->hed));
+ som = &(cel_u->tel);
+ }
+}
+
+/* u3a_mark_mptr(): mark a malloc-allocated ptr for gc.
+*/
+c3_w
+u3a_mark_mptr(void* ptr_v)
+{
+ return u3a_mark_ptr(ptr_v);
+}
+
+/* u3a_mark_rptr(): mark a refcounted, word-aligned ptr for gc.
+*/
+c3_w
+u3a_mark_rptr(void* ptr_v)
+{
+ u3_post som_p = u3a_outa(ptr_v);
+ c3_w siz_w = !(u3C.wag_w & u3o_debug_ram)
+ ? _mark_post(som_p)
+ : _count_post(som_p, 1);
+
+ return siz_w;
+}
+
+/* u3a_mark_noun(): mark a noun for gc. Produce size.
+*/
+c3_w
+u3a_mark_noun(u3_noun som)
+{
+ c3_w siz_w = 0;
+
+ while ( 1 ) {
+ if ( _(u3a_is_senior(u3R, som)) ) {
+ return siz_w;
+ }
+ else {
+ c3_w* dog_w = u3a_to_ptr(som);
+ c3_w new_w = u3a_mark_rptr(dog_w);
+
+ if ( 0 == new_w || 0xffffffff == new_w ) { // see u3a_mark_ptr()
+ return siz_w;
+ }
+ else {
+ siz_w += new_w;
+ if ( _(u3du(som)) ) {
+ siz_w += u3a_mark_noun(u3h(som));
+ som = u3t(som);
+ }
+ else return siz_w;
+ }
+ }
+ }
+}
+
+/* u3a_count_noun(): count size of pointer.
+*/
+c3_w
+u3a_count_ptr(void* ptr_v)
+{
+#if 0
+ if ( _(u3a_is_north(u3R)) ) {
+ if ( !((ptr_v >= u3a_into(u3R->rut_p)) &&
+ (ptr_v < u3a_into(u3R->hat_p))) )
+ {
+ return 0;
+ }
+ }
+ else {
+ if ( !((ptr_v >= u3a_into(u3R->hat_p)) &&
+ (ptr_v < u3a_into(u3R->rut_p))) )
+ {
+ return 0;
+ }
+ }
+ {
+ u3a_box* box_u = u3a_botox(ptr_v);
+ c3_w siz_w;
+
+ c3_ws use_ws = (c3_ws)box_u->use_w;
+
+ if ( use_ws == 0 ) {
+ fprintf(stderr, "%p is bogus\r\n", ptr_v);
+ siz_w = 0;
+ }
+ else {
+ u3_assert(use_ws != 0);
+
+ if ( use_ws < 0 ) {
+ siz_w = 0;
+ }
+ else {
+ use_ws = -use_ws;
+ siz_w = box_u->siz_w;
+ }
+ box_u->use_w = (c3_w)use_ws;
+ }
+ return siz_w;
+ }
+#endif
+ return 0;
+}
+
+/* u3a_count_noun(): count size of noun.
+*/
+c3_w
+u3a_count_noun(u3_noun som)
+{
+ c3_w siz_w = 0;
+
+ while ( 1 ) {
+ if ( _(u3a_is_senior(u3R, som)) ) {
+ return siz_w;
+ }
+ else {
+ c3_w* dog_w = u3a_to_ptr(som);
+ c3_w new_w = u3a_count_ptr(dog_w);
+
+ if ( 0 == new_w ) {
+ return siz_w;
+ }
+ else {
+ siz_w += new_w;
+ if ( _(u3du(som)) ) {
+ siz_w += u3a_count_noun(u3h(som));
+ som = u3t(som);
+ }
+ else return siz_w;
+ }
+ }
+ }
+}
+
+/* u3a_discount_ptr(): clean up after counting a pointer.
+*/
+c3_w
+u3a_discount_ptr(void* ptr_v)
+{
+#if 0
+ if ( _(u3a_is_north(u3R)) ) {
+ if ( !((ptr_v >= u3a_into(u3R->rut_p)) &&
+ (ptr_v < u3a_into(u3R->hat_p))) )
+ {
+ return 0;
+ }
+ }
+ else {
+ if ( !((ptr_v >= u3a_into(u3R->hat_p)) &&
+ (ptr_v < u3a_into(u3R->rut_p))) )
+ {
+ return 0;
+ }
+ }
+ u3a_box* box_u = u3a_botox(ptr_v);
+ c3_w siz_w;
+
+ c3_ws use_ws = (c3_ws)box_u->use_w;
+
+ if ( use_ws == 0 ) {
+ fprintf(stderr, "%p is bogus\r\n", ptr_v);
+ siz_w = 0;
+ }
+ else {
+ u3_assert(use_ws != 0);
+
+ if ( use_ws < 0 ) {
+ use_ws = -use_ws;
+ siz_w = box_u->siz_w;
+ }
+ else {
+ siz_w = 0;
+ }
+ box_u->use_w = (c3_w)use_ws;
+ }
+
+ return siz_w;
+#endif
+ return 0;
+}
+
+/* u3a_discount_noun(): clean up after counting a noun.
+*/
+c3_w
+u3a_discount_noun(u3_noun som)
+{
+ c3_w siz_w = 0;
+
+ while ( 1 ) {
+ if ( _(u3a_is_senior(u3R, som)) ) {
+ return siz_w;
+ }
+ else {
+ c3_w* dog_w = u3a_to_ptr(som);
+ c3_w new_w = u3a_discount_ptr(dog_w);
+
+ if ( 0 == new_w ) {
+ return siz_w;
+ }
+ else {
+ siz_w += new_w;
+ if ( _(u3du(som)) ) {
+ siz_w += u3a_discount_noun(u3h(som));
+ som = u3t(som);
+ }
+ else return siz_w;
+ }
+ }
+ }
+}
+
+/* u3a_print_time: print microsecond time.
+*/
+void
+u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d)
+{
+ u3_assert( 0 != str_c );
+
+ c3_w sec_w = (mic_d / 1000000);
+ c3_w mec_w = (mic_d % 1000000) / 1000;
+ c3_w mic_w = (mic_d % 1000);
+
+ if ( sec_w ) {
+ sprintf(str_c, "%s s/%d.%03d.%03d", cap_c, sec_w, mec_w, mic_w);
+ }
+ else if ( mec_w ) {
+ sprintf(str_c, "%s ms/%d.%03d", cap_c, mec_w, mic_w);
+ }
+ else {
+ sprintf(str_c, "%s \xc2\xb5s/%d", cap_c, mic_w);
+ }
+}
+
+/* u3a_print_memory: print memory amount to file descriptor.
+*/
+void
+u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w)
+{
+ u3_assert( 0 != fil_u );
+
+ c3_z byt_z = ((c3_z)wor_w * 4);
+ c3_z gib_z = (byt_z / 1000000000);
+ c3_z mib_z = (byt_z % 1000000000) / 1000000;
+ c3_z kib_z = (byt_z % 1000000) / 1000;
+ c3_z bib_z = (byt_z % 1000);
+
+ if ( byt_z ) {
+ if ( gib_z ) {
+ fprintf(fil_u, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, gib_z, mib_z, kib_z, bib_z);
+ }
+ else if ( mib_z ) {
+ fprintf(fil_u, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, mib_z, kib_z, bib_z);
+ }
+ else if ( kib_z ) {
+ fprintf(fil_u, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, kib_z, bib_z);
+ }
+ else if ( bib_z ) {
+ fprintf(fil_u, "%s: B/%" PRIc3_z "\r\n",
+ cap_c, bib_z);
+ }
+ }
+}
+
+/* u3a_print_memory_str: print memory amount to string.
+*/
+void
+u3a_print_memory_str(c3_c* str_c, c3_c* cap_c, c3_w wor_w)
+{
+ u3_assert( 0 != str_c );
+
+ c3_z byt_z = ((c3_z)wor_w * 4);
+ c3_z gib_z = (byt_z / 1000000000);
+ c3_z mib_z = (byt_z % 1000000000) / 1000000;
+ c3_z kib_z = (byt_z % 1000000) / 1000;
+ c3_z bib_z = (byt_z % 1000);
+
+ if ( byt_z ) {
+ if ( gib_z ) {
+ sprintf(str_c, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, gib_z, mib_z, kib_z, bib_z);
+ }
+ else if ( mib_z ) {
+ sprintf(str_c, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, mib_z, kib_z, bib_z);
+ }
+ else if ( kib_z ) {
+ sprintf(str_c, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n",
+ cap_c, kib_z, bib_z);
+ }
+ else if ( bib_z ) {
+ sprintf(str_c, "%s: B/%" PRIc3_z "\r\n",
+ cap_c, bib_z);
+ }
+ }
+}
+
+/* u3a_maid(): maybe print memory.
+*/
+c3_w
+u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w)
+{
+ if ( 0 != fil_u ) {
+ u3a_print_memory(fil_u, cap_c, wor_w);
+ }
+ return wor_w;
+}
+
+/* _ca_print_memory(): un-captioned u3a_print_memory().
+*/
+static void
+_ca_print_memory(FILE* fil_u, c3_w byt_w)
+{
+ c3_w gib_w = (byt_w / 1000000000);
+ c3_w mib_w = (byt_w % 1000000000) / 1000000;
+ c3_w kib_w = (byt_w % 1000000) / 1000;
+ c3_w bib_w = (byt_w % 1000);
+
+ if ( gib_w ) {
+ fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n",
+ gib_w, mib_w, kib_w, bib_w);
+ }
+ else if ( mib_w ) {
+ fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w);
+ }
+ else if ( kib_w ) {
+ fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w);
+ }
+ else {
+ fprintf(fil_u, "B/%d\r\n", bib_w);
+ }
+}
+
+/* u3a_quac_free: free quac memory.
+*/
+void
+u3a_quac_free(u3m_quac* qua_u)
+{
+ c3_w i_w = 0;
+ while ( qua_u->qua_u[i_w] != NULL ) {
+ u3a_quac_free(qua_u->qua_u[i_w]);
+ i_w++;
+ }
+ c3_free(qua_u->nam_c);
+ c3_free(qua_u->qua_u);
+ c3_free(qua_u);
+}
+
+static c3_w
+_ca_prof_mark(u3_noun som)
+{
+ if ( c3y == u3a_is_senior(u3R, som) ) {
+ return 0;
+ }
+
+ // marking memory-profile entries under u3o_debug_ram
+ // requires special care to avoid over-incrementing the refcount,
+ // as the entries in the profile are not true roots:
+ // they either belong to arvo or the profile itself.
+ // we measure them here, but account for them elsewhere (subsequently)
+ // from a refcounting standpoint
+ //
+ u3_post som_p = u3a_to_off(som);
+ c3_w siz_w = !(u3C.wag_w & u3o_debug_ram)
+ ? _mark_post(som_p)
+ : _count_post(som_p, 2);
+
+ if ( !siz_w ) {
+ return 0;
+ }
+
+ if ( c3y == u3a_is_cell(som) ) {
+ siz_w += u3a_mark_noun(u3h(som));
+ siz_w += u3a_mark_noun(u3t(som));
+ }
+
+ return siz_w;
+}
+
+/* u3a_prof(): mark/measure/print memory profile. RETAIN.
+*/
+u3m_quac*
+u3a_prof(FILE* fil_u, u3_noun mas)
+{
+ u3m_quac* pro_u = c3_calloc(sizeof(*pro_u));
+ u3_noun h_mas, t_mas;
+
+ if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) {
+ fprintf(fil_u, "mistyped mass\r\n");
+ c3_free(pro_u);
+ return NULL;
+ }
+ else if ( c3y == u3du(h_mas) ) {
+ fprintf(fil_u, "mistyped mass head\r\n");
+ {
+ c3_c* lab_c = u3m_pretty(h_mas);
+ fprintf(fil_u, "h_mas: %s", lab_c);
+ c3_free(lab_c);
+ }
+ c3_free(pro_u);
+ return NULL;
+ }
+ else {
+
+ u3_noun it_mas, tt_mas;
+
+ if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) {
+ fprintf(fil_u, "mistyped mass tail\r\n");
+ c3_free(pro_u);
+ return NULL;
+ }
+ else if ( c3y == it_mas ) {
+ c3_w siz_w = _ca_prof_mark(tt_mas);
+
+ pro_u->nam_c = u3r_string(h_mas);
+ pro_u->siz_w = siz_w*4;
+ pro_u->qua_u = NULL;
+ return pro_u;
+
+ }
+ else if ( c3n == it_mas ) {
+ pro_u->qua_u = c3_malloc(sizeof(pro_u->qua_u));
+ c3_w i_w = 0;
+ c3_t bad_t = 0;
+ while ( c3y == u3du(tt_mas) ) {
+ u3m_quac* new_u = u3a_prof(fil_u, u3h(tt_mas));
+ if ( NULL == new_u ) {
+ bad_t = 1;
+ } else {
+ pro_u->qua_u = c3_realloc(pro_u->qua_u, (i_w + 2) * sizeof(pro_u->qua_u));
+ pro_u->siz_w += new_u->siz_w;
+ pro_u->qua_u[i_w] = new_u;
+ }
+ tt_mas = u3t(tt_mas);
+ i_w++;
+ }
+ pro_u->qua_u[i_w] = NULL;
+
+ if ( bad_t ) {
+ i_w = 0;
+ while ( pro_u->qua_u[i_w] != NULL ) {
+ u3a_quac_free(pro_u->qua_u[i_w]);
+ i_w++;
+ }
+ c3_free(pro_u->qua_u);
+ c3_free(pro_u);
+ return NULL;
+ } else {
+ pro_u->nam_c = u3r_string(h_mas);
+ return pro_u;
+ }
+ }
+ else {
+ fprintf(fil_u, "mistyped (strange) mass tail\r\n");
+ c3_free(pro_u);
+ return NULL;
+ }
+ }
+}
+
+
+/* u3a_print_quac: print a memory report.
+*/
+
+void
+u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u)
+{
+ u3_assert( 0 != fil_u );
+
+ if ( mas_u->siz_w ) {
+ fprintf(fil_u, "%*s%s: ", den_w, "", mas_u->nam_c);
+
+ if ( mas_u->qua_u == NULL ) {
+ _ca_print_memory(fil_u, mas_u->siz_w);
+ } else {
+ fprintf(fil_u, "\r\n");
+ c3_w i_w = 0;
+ while ( mas_u->qua_u[i_w] != NULL ) {
+ u3a_print_quac(fil_u, den_w+2, mas_u->qua_u[i_w]);
+ i_w++;
+ }
+ fprintf(fil_u, "%*s--", den_w, "");
+ _ca_print_memory(fil_u, mas_u->siz_w);
+ }
+ }
+}
+
+/* u3a_mark_road(): mark ad-hoc persistent road structures.
+*/
+u3m_quac*
+u3a_mark_road()
+{
+ u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 14);
+
+ qua_u[0] = c3_calloc(sizeof(*qua_u[0]));
+ qua_u[0]->nam_c = strdup("namespace");
+ qua_u[0]->siz_w = u3a_mark_noun(u3R->ski.gul) * 4;
+
+ qua_u[1] = c3_calloc(sizeof(*qua_u[1]));
+ qua_u[1]->nam_c = strdup("trace stack");
+ qua_u[1]->siz_w = u3a_mark_noun(u3R->bug.tax) * 4;
+
+ qua_u[2] = c3_calloc(sizeof(*qua_u[2]));
+ qua_u[2]->nam_c = strdup("trace buffer");
+ qua_u[2]->siz_w = u3a_mark_noun(u3R->bug.mer) * 4;
+
+ qua_u[3] = c3_calloc(sizeof(*qua_u[3]));
+ qua_u[3]->nam_c = strdup("profile batteries");
+ qua_u[3]->siz_w = u3a_mark_noun(u3R->pro.don) * 4;
+
+ qua_u[4] = c3_calloc(sizeof(*qua_u[4]));
+ qua_u[4]->nam_c = strdup("profile doss");
+ qua_u[4]->siz_w = u3a_mark_noun(u3R->pro.day) * 4;
+
+ qua_u[5] = c3_calloc(sizeof(*qua_u[5]));
+ qua_u[5]->nam_c = strdup("new profile trace");
+ qua_u[5]->siz_w = u3a_mark_noun(u3R->pro.trace) * 4;
+
+ qua_u[6] = c3_calloc(sizeof(*qua_u[6]));
+ qua_u[6]->nam_c = strdup("transient memoization cache");
+ qua_u[6]->siz_w = u3h_mark(u3R->cax.har_p) * 4;
+
+ qua_u[7] = c3_calloc(sizeof(*qua_u[7]));
+ qua_u[7]->nam_c = strdup("persistent memoization cache");
+ qua_u[7]->siz_w = u3h_mark(u3R->cax.per_p) * 4;
+
+ qua_u[8] = c3_calloc(sizeof(*qua_u[8]));
+ qua_u[8]->nam_c = strdup("page directory");
+ qua_u[8]->siz_w = u3a_mark_ptr(u3a_into(u3R->hep.pag_p)) * 4;
+
+ qua_u[9] = c3_calloc(sizeof(*qua_u[9]));
+ qua_u[9]->nam_c = strdup("cell pool");
+
+ {
+ u3_post *cel_p;
+ c3_w cel_w = 0;
+
+ if ( u3R->cel.cel_p ) {
+ cel_p = u3to(u3_post, u3R->cel.cel_p);
+ cel_w += u3a_mark_ptr(cel_p);
+
+ for ( c3_w i_w = 0; i_w < u3R->cel.hav_w; i_w++ ) {
+ cel_w += u3a_mark_ptr(u3a_into(cel_p[i_w]));
+ }
+ }
+
+ qua_u[9]->siz_w = cel_w * 4;
+ }
+
+ qua_u[10] = c3_calloc(sizeof(*qua_u[10]));
+ qua_u[10]->nam_c = strdup("free list");
+
+ {
+ u3a_dell *fre_u = u3tn(u3a_dell, u3R->hep.fre_p);
+ c3_w fre_w = 0;
+
+ while ( fre_u ) {
+ fre_w += u3a_mark_ptr(fre_u);
+ fre_u = u3tn(u3a_dell, fre_u->nex_p);
+ }
+
+ if ( u3R->hep.cac_p ) {
+ fre_w += u3a_mark_ptr(u3a_into(u3R->hep.cac_p));
+ }
+
+ qua_u[10]->siz_w = fre_w * 4;
+ }
+
+ qua_u[11] = c3_calloc(sizeof(*qua_u[11]));
+ qua_u[11]->nam_c = strdup("metadata");
+
+ {
+ c3_w wee_w = 0;
+
+ for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) {
+ wee_w += u3a_Mark.wee_w[i_w];
+ }
+
+ qua_u[11]->siz_w = wee_w * 4;
+ }
+
+ qua_u[12] = NULL;
+
+ c3_w sum_w = 0;
+ for (c3_w i_w = 0; qua_u[i_w]; i_w++) {
+ sum_w += qua_u[i_w]->siz_w;
+ }
+
+ u3m_quac* tot_u = c3_malloc(sizeof(*tot_u));
+ tot_u->nam_c = strdup("total road stuff");
+ tot_u->siz_w = sum_w;
+ tot_u->qua_u = qua_u;
+
+ return tot_u;
+}
+
+/* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3a_reclaim(void)
+{
+ // clear the memoization cache
+ //
+ u3h_free(u3R->cax.har_p);
+ u3R->cax.har_p = u3h_new();
+}
+
+/* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures.
+*/
+void
+u3a_rewrite_compact(void)
+{
+ // XX relocate cel_p
+ u3a_relocate_noun(&(u3R->ski.gul));
+ u3a_relocate_noun(&(u3R->bug.tax));
+ u3a_relocate_noun(&(u3R->bug.mer));
+ u3a_relocate_noun(&(u3R->pro.don));
+ u3a_relocate_noun(&(u3R->pro.day));
+ u3a_relocate_noun(&(u3R->pro.trace));
+ u3h_relocate(&(u3R->cax.har_p));
+ u3h_relocate(&(u3R->cax.per_p));
+}
+
+/* u3a_idle(): measure free-lists in [rod_u]
+*/
+c3_w
+u3a_idle(u3a_road* rod_u)
+{
+ // XX ignores argument
+ c3_w pag_w = _idle_pages();
+ if ( pag_w ) {
+ fprintf(stderr, "loom: idle %u complete pages\r\n", pag_w);
+ }
+ return (pag_w << u3a_page) + _idle_words();
+}
+
+void
+u3a_ream(void)
+{
+ _poison_pages();
+ _poison_words();
+}
+
+void
+u3a_wait(void)
+{
+ _unpoison_words();
+}
+
+void
+u3a_dash(void)
+{
+ _poison_words();
+}
+
+/* u3a_sweep(): sweep a fully marked road.
+*/
+c3_w
+u3a_sweep(void)
+{
+ c3_w siz_w = !(u3C.wag_w & u3o_debug_ram)
+ ? _sweep_directory()
+ : _sweep_counts();
+
+ return siz_w;
+}
+
+/* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses.
+*/
+void
+u3a_pack_seek(u3a_road* rod_u)
+{
+ u3a_pack_init();
+
+ // XX clear cell pool on inner roads?
+
+ // XX use road argument
+ _pack_seek();
+ _pack_relocate_heap();
+}
+
+/* u3a_pack_move(): sweep the heap, moving boxes to new addresses.
+*/
+void
+u3a_pack_move(u3a_road* rod_u)
+{
+ // XX use road argument
+ _pack_move();
+
+ u3a_pack_done();
+
+ u3_post old_p = u3R->hat_p;
+
+ // XX move me?
+ //
+ u3R->hat_p = u3R->rut_p + (u3R->hep.dir_ws * (c3_ws)(u3R->hep.len_w << u3a_page));
+
+ u3a_drop_heap(old_p, u3R->hat_p);
+}
+
+#if 0
+/* _ca_detect(): in u3a_detect().
+*/
+static c3_d
+_ca_detect(u3p(u3h_root) har_p, u3_noun fum, u3_noun som, c3_d axe_d)
+{
+ while ( 1 ) {
+ if ( som == fum ) {
+ return axe_d;
+ }
+ else if ( !_(u3du(fum)) || (u3_none != u3h_get(har_p, fum)) ) {
+ return 0;
+ }
+ else {
+ c3_d eax_d;
+
+ u3h_put(har_p, fum, 0);
+
+ if ( 0 != (eax_d = _ca_detect(har_p, u3h(fum), som, 2ULL * axe_d)) ) {
+ return c3y;
+ }
+ else {
+ fum = u3t(fum);
+ axe_d = (2ULL * axe_d) + 1;
+ }
+ }
+ }
+}
+
+/* u3a_detect(): for debugging, check if (som) is referenced from (fum).
+**
+** (som) and (fum) are both RETAINED.
+*/
+c3_d
+u3a_detect(u3_noun fum, u3_noun som)
+{
+ u3p(u3h_root) har_p = u3h_new();
+ c3_o ret_o;
+
+ ret_o = _ca_detect(har_p, fum, som, 1);
+ u3h_free(har_p);
+
+ return ret_o;
+}
+#endif
+
+#ifdef U3_MEMORY_DEBUG
+/* u3a_lush(): leak push.
+*/
+c3_w
+u3a_lush(c3_w lab_w)
+{
+ c3_w cod_w = u3_Code;
+
+ u3_Code = lab_w;
+ return cod_w;
+}
+
+/* u3a_lop(): leak pop.
+*/
+void
+u3a_lop(c3_w lab_w)
+{
+ u3_Code = lab_w;
+}
+#else
+/* u3a_lush(): leak push.
+*/
+c3_w
+u3a_lush(c3_w lab_w)
+{
+ return 0;
+}
+
+/* u3a_lop(): leak pop.
+*/
+void
+u3a_lop(c3_w lab_w)
+{
+}
+#endif
+
+/* u3a_walk_fore(): preorder traversal, visits ever limb of a noun.
+**
+** cells are visited *before* their heads and tails
+** and can shortcircuit traversal by returning [c3n]
+*/
+void
+u3a_walk_fore(u3_noun a,
+ void* ptr_v,
+ void (*pat_f)(u3_atom, void*),
+ c3_o (*cel_f)(u3_noun, void*))
+{
+ u3_noun* top;
+ u3a_pile pil_u;
+
+ // initialize stack control; push argument
+ //
+ u3a_pile_prep(&pil_u, sizeof(u3_noun));
+ top = u3a_push(&pil_u);
+ *top = a;
+
+ while ( c3n == u3a_pile_done(&pil_u) ) {
+ // visit an atom, then pop the stack
+ //
+ if ( c3y == u3a_is_atom(a) ) {
+ pat_f(a, ptr_v);
+ top = u3a_pop(&pil_u);
+ }
+ // vist a cell, if c3n, pop the stack
+ //
+ else if ( c3n == cel_f(a, ptr_v) ) {
+ top = u3a_pop(&pil_u);
+ }
+ // otherwise, push the tail and continue into the head
+ //
+ else {
+ *top = u3t(a);
+ top = u3a_push(&pil_u);
+ *top = u3h(a);
+ }
+
+ a = *top;
+ }
+}
+
+/* u3a_string(): `a` as an on-loom c-string.
+*/
+c3_c*
+u3a_string(u3_atom a)
+{
+ c3_w met_w = u3r_met(3, a);
+ c3_c* str_c = u3a_malloc(met_w + 1);
+
+ u3r_bytes(0, met_w, (c3_y*)str_c, a);
+ str_c[met_w] = 0;
+ return str_c;
+}
+
+/* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption
+ */
+void
+u3a_loom_sane(void)
+{
+}
diff --git a/vere/pkg/noun/allocate.h b/vere/pkg/noun/allocate.h
new file mode 100644
index 0000000..418db1a
--- /dev/null
+++ b/vere/pkg/noun/allocate.h
@@ -0,0 +1,854 @@
+#ifndef U3_ALLOCATE_H
+#define U3_ALLOCATE_H
+
+#include "error.h"
+#include "manage.h"
+
+ /** Constants.
+ **/
+ /* u3a_bits: number of bits in word-addressed pointer. 29 == 2GB.
+ */
+# define u3a_bits U3_OS_LoomBits /* 30 */
+
+ /* u3a_vits: number of virtual bits in a noun reference gained via shifting
+ */
+# define u3a_vits 2
+
+ /* u3a_walign: references into the loom are guaranteed to be word-aligned to:
+ */
+# define u3a_walign (1 << u3a_vits)
+
+ /* u3a_balign: u3a_walign in bytes
+ */
+# define u3a_balign (sizeof(c3_w)*u3a_walign)
+
+ /* u3a_bits_max: max loom bex
+ */
+# define u3a_bits_max (8 * sizeof(c3_w) + u3a_vits)
+
+ /* u3a_page: number of bits in word-addressed page. 12 == 16K page
+ */
+# define u3a_page 12ULL
+
+ /* u3a_pages: maximum number of pages in memory.
+ */
+# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) )
+
+ /* u3a_words: maximum number of words in memory.
+ */
+# define u3a_words ( 1ULL << (u3a_bits + u3a_vits))
+
+ /* u3a_bytes: maximum number of bytes in memory.
+ */
+# define u3a_bytes ((sizeof(c3_w) * u3a_words))
+
+ /* u3a_cells: number of representable cells.
+ */
+# define u3a_cells (( u3a_words / u3a_minimum ))
+
+ /* u3a_maximum: maximum loom object size (largest possible atom).
+ */
+# define u3a_maximum (u3a_words - c3_wiseof(u3a_atom))
+
+ /* u3a_minimum: minimum loom object size (actual size of a cell).
+ */
+# define u3a_minimum ((c3_w)c3_wiseof(u3a_cell))
+
+ /* u3a_min_log: log2(u3a_minimum)
+ */
+# define u3a_min_log 2
+
+ /* u3a_crag_no: number of hunk (small allocation) sizes
+ */
+# define u3a_crag_no (u3a_page - u3a_min_log)
+
+ /* page table constants
+ */
+# define u3a_free_pg (u3p(u3a_crag))0
+# define u3a_head_pg (u3p(u3a_crag))1
+# define u3a_rest_pg (u3p(u3a_crag))2
+
+ /** Structures.
+ **/
+ typedef struct {
+ c3_w use_w;
+ c3_w buf_w[0];
+ } u3a_rate;
+ /* u3a_atom, u3a_cell: logical atom and cell structures.
+ */
+ typedef struct {
+ c3_w use_w;
+ c3_w mug_w;
+ } u3a_noun;
+
+ typedef struct {
+ c3_w use_w;
+ c3_w mug_w;
+ c3_w len_w;
+ c3_w buf_w[0];
+ } u3a_atom;
+
+ typedef struct {
+ c3_w use_w;
+ c3_w mug_w;
+ u3_noun hed;
+ u3_noun tel;
+ } u3a_cell;
+
+STATIC_ASSERT( (1U << u3a_min_log) == u3a_minimum,
+ "log2 minimum allocation" );
+STATIC_ASSERT( u3a_vits <= u3a_min_log,
+ "virtual-bit alignment" );
+
+ /* u3a_crag: hunk-page metadata
+ */
+ typedef struct _u3a_crag {
+ u3p(struct _u3a_crag) nex_p; // next
+ c3_w pag_w; // page index
+ c3_s log_s; // size log2
+ c3_s fre_s; // free chunks
+ c3_w map_w[1]; // free-chunk bitmap
+ } u3a_crag;
+
+ /* u3a_dell: page free-list entry
+ */
+ typedef struct _u3a_dell {
+ u3p(struct _u3a_dell) nex_p; // next
+ u3p(struct _u3a_dell) pre_p; // prev
+ c3_w pag_w; // page index
+ c3_w siz_w; // number of pages
+ } u3a_dell;
+
+ /* u3a_jets: jet dashboard
+ */
+ typedef struct _u3a_jets {
+ u3p(u3h_root) hot_p; // hot state (home road only)
+ u3p(u3h_root) war_p; // warm state
+ u3p(u3h_root) cod_p; // cold state
+ u3p(u3h_root) han_p; // hank cache
+ u3p(u3h_root) bas_p; // battery hashes
+ } u3a_jets;
+
+ /* u3a_road: contiguous allocation and execution context.
+ */
+ typedef struct _u3a_road {
+ u3p(struct _u3a_road) par_p; // parent road
+ u3p(struct _u3a_road) kid_p; // child road list
+ u3p(struct _u3a_road) nex_p; // sibling road
+
+ u3p(c3_w) cap_p; // top of transient region
+ u3p(c3_w) hat_p; // top of durable region
+ u3p(c3_w) mat_p; // bottom of transient region
+ u3p(c3_w) rut_p; // bottom of durable region
+ u3p(c3_w) ear_p; // original cap if kid is live
+
+ c3_w off_w; // spin stack offset
+ c3_w fow_w; // spin stack overflow count
+
+ c3_w fut_w[30]; // futureproof buffer
+
+ struct { // escape buffer
+ union {
+ jmp_buf buf;
+ c3_w buf_w[256]; // futureproofing
+ };
+ } esc;
+
+ struct { // miscellaneous config
+ c3_w fag_w; // flag bits
+ } how; //
+
+ // XX re/move
+ struct { // allocation pools
+ c3_w fre_w; // number of free words
+ c3_w max_w; // maximum allocated
+ } all;
+
+ struct { // heap allocator
+ u3p(u3a_dell) fre_p; // free list entry
+ u3p(u3a_dell) erf_p; // free list exit
+ u3p(u3a_dell) cac_p; // cached pgfree struct
+ c3_ws dir_ws; // 1 || -1 (multiplicand for local offsets)
+ c3_ws off_ws; // 0 || -1 (word-offset for hat && rut)
+ c3_w siz_w; // directory size
+ c3_w len_w; // directory entries
+ u3p(u3a_crag*) pag_p; // directory
+ u3p(u3a_crag) wee_p[u3a_crag_no]; // chunk lists
+ } hep;
+
+ struct { // cell pool
+ u3_post cel_p; // array of cells
+ c3_w hav_w; // length
+ c3_w bat_w; // batch counter
+ } cel;
+
+ u3a_jets jed; // jet dashboard
+
+ struct { // bytecode state
+ u3p(u3h_root) har_p; // formula->post of bytecode
+ } byc;
+
+ struct { // scry namespace
+ u3_noun gul; // (list $+(* (unit (unit)))) now
+ } ski;
+
+ struct { // trace stack
+ u3_noun tax; // (list ,*)
+ u3_noun mer; // emergency buffer to release
+ } bug;
+
+ struct { // profile stack
+ c3_d nox_d; // nock steps
+ c3_d cel_d; // cell allocations
+ u3_noun don; // (list batt)
+ u3_noun trace; // (list trace)
+ u3_noun day; // doss, only in u3H (moveme)
+ } pro;
+
+ struct { // memoization caches
+ u3p(u3h_root) har_p; // transient
+ u3p(u3h_root) per_p; // persistent
+ } cax;
+ } u3a_road;
+ typedef u3a_road u3_road;
+
+ /* u3a_flag: flags for how.fag_w. All arena related.
+ */
+ enum u3a_flag {
+ u3a_flag_sand = 0x1, // bump allocation (XX not impl)
+ };
+
+ /* u3a_pile: stack control, abstracted over road direction.
+ */
+ typedef struct _u3a_pile {
+ c3_ws mov_ws;
+ c3_ws off_ws;
+ u3_post top_p;
+#ifdef U3_MEMORY_DEBUG
+ u3a_road* rod_u;
+#endif
+ } u3a_pile;
+
+ /** Macros. Should be better commented.
+ **/
+ /* u3a_is_cat(): yes if noun [som] is direct atom.
+ */
+# define u3a_is_cat(som) (((som) >> 31) ? c3n : c3y)
+
+ /* u3a_is_dog(): yes if noun [som] is indirect noun.
+ */
+# define u3a_is_dog(som) (((som) >> 31) ? c3y : c3n)
+
+ /* u3a_is_pug(): yes if noun [som] is indirect atom.
+ */
+# define u3a_is_pug(som) ((0b10 == ((som) >> 30)) ? c3y : c3n)
+
+ /* u3a_is_pom(): yes if noun [som] is indirect cell.
+ */
+# define u3a_is_pom(som) ((0b11 == ((som) >> 30)) ? c3y : c3n)
+
+ /* u3a_is_atom(): yes if noun [som] is direct atom or indirect atom.
+ */
+# define u3a_is_atom(som) c3o(u3a_is_cat(som), \
+ u3a_is_pug(som))
+# define u3ud(som) u3a_is_atom(som)
+
+ /* u3a_is_cell: yes if noun [som] is cell.
+ */
+# define u3a_is_cell(som) u3a_is_pom(som)
+# define u3du(som) u3a_is_cell(som)
+
+ /* u3a_h(): get head of cell [som]. Bail if [som] is not cell.
+ */
+# define u3a_h(som) \
+ ( _(u3a_is_cell(som)) \
+ ? ( ((u3a_cell *)u3a_to_ptr(som))->hed )\
+ : u3m_bail(c3__exit) )
+# define u3h(som) u3a_h(som)
+
+ /* u3a_t(): get tail of cell [som]. Bail if [som] is not cell.
+ */
+# define u3a_t(som) \
+ ( _(u3a_is_cell(som)) \
+ ? ( ((u3a_cell *)u3a_to_ptr(som))->tel )\
+ : u3m_bail(c3__exit) )
+# define u3t(som) u3a_t(som)
+
+# define u3to(type, x) ((type *)u3a_into(x))
+# define u3tn(type, x) (x) ? (type*)u3a_into(x) : (void*)NULL
+
+# define u3of(type, x) (u3a_outa((type*)x))
+
+ /* u3a_is_north(): yes if road [r] is north road.
+ */
+# define u3a_is_north(r) __((r)->cap_p > (r)->hat_p)
+
+ /* u3a_is_south(): yes if road [r] is south road.
+ */
+# define u3a_is_south(r) !u3a_is_north((r))
+
+ /* u3a_open(): words of contiguous free space in road [r]
+ */
+# define u3a_open(r) ( (c3y == u3a_is_north(r)) \
+ ? (c3_w)((r)->cap_p - (r)->hat_p) \
+ : (c3_w)((r)->hat_p - (r)->cap_p) )
+
+ /* u3a_full(): total words in road [r];
+ ** u3a_full(r) == u3a_heap(r) + u3a_temp(r) + u3a_open(r)
+ */
+# define u3a_full(r) ( (c3y == u3a_is_north(r)) \
+ ? (c3_w)((r)->mat_p - (r)->rut_p) \
+ : (c3_w)((r)->rut_p - (r)->mat_p) )
+
+ /* u3a_heap(): words of heap in road [r]
+ */
+# define u3a_heap(r) ( (c3y == u3a_is_north(r)) \
+ ? (c3_w)((r)->hat_p - (r)->rut_p) \
+ : (c3_w)((r)->rut_p - (r)->hat_p) )
+
+ /* u3a_temp(): words of stack in road [r]
+ */
+# define u3a_temp(r) ( (c3y == u3a_is_north(r)) \
+ ? (c3_w)((r)->mat_p - (r)->cap_p) \
+ : (c3_w)((r)->cap_p - (r)->mat_p) )
+
+# define u3a_north_is_senior(r, dog) \
+ __((u3a_to_off(dog) < (r)->rut_p) || \
+ (u3a_to_off(dog) >= (r)->mat_p))
+
+# define u3a_north_is_junior(r, dog) \
+ __((u3a_to_off(dog) >= (r)->cap_p) && \
+ (u3a_to_off(dog) < (r)->mat_p))
+
+# define u3a_north_is_normal(r, dog) \
+ c3a(!(u3a_north_is_senior(r, dog)), \
+ !(u3a_north_is_junior(r, dog)))
+
+# define u3a_south_is_senior(r, dog) \
+ __((u3a_to_off(dog) < (r)->mat_p) || \
+ (u3a_to_off(dog) >= (r)->rut_p))
+
+# define u3a_south_is_junior(r, dog) \
+ __((u3a_to_off(dog) < (r)->cap_p) && \
+ (u3a_to_off(dog) >= (r)->mat_p))
+
+# define u3a_south_is_normal(r, dog) \
+ c3a(!(u3a_south_is_senior(r, dog)), \
+ !(u3a_south_is_junior(r, dog)))
+
+# define u3a_is_junior(r, som) \
+ ( _(u3a_is_cat(som)) \
+ ? c3n \
+ : _(u3a_is_north(r)) \
+ ? u3a_north_is_junior(r, som) \
+ : u3a_south_is_junior(r, som) )
+
+# define u3a_is_senior(r, som) \
+ ( _(u3a_is_cat(som)) \
+ ? c3y \
+ : _(u3a_is_north(r)) \
+ ? u3a_north_is_senior(r, som) \
+ : u3a_south_is_senior(r, som) )
+
+# define u3a_is_mutable(r, som) \
+ ( _(u3a_is_atom(som)) \
+ ? c3n \
+ : _(u3a_is_senior(r, som)) \
+ ? c3n \
+ : _(u3a_is_junior(r, som)) \
+ ? c3n \
+ : (((u3a_rate*)u3a_to_ptr(som))->use_w == 1) \
+ ? c3y : c3n )
+
+/* like _box_vaal but for rods. Again, probably want to prefix validation
+ functions at the very least. Maybe they can be defined in their own header.
+
+ ps. while arguably cooler to have this compile to
+
+ do {(void(0));(void(0));} while(0)
+
+ It may be nicer to just wrap an inline function in #ifdef C3DBG guards. You
+ could even return the then validated road like
+
+ u3a_road f() {
+ u3a_road rod_u;
+ ...
+ return _rod_vaal(rod_u);
+ }
+*/
+# define _rod_vaal(rod_u) \
+ do { \
+ c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \
+ & u3a_walign-1) == 0); \
+ } while(0)
+
+
+typedef struct _u3a_mark {
+ c3_w wee_w[u3a_crag_no];
+ c3_w* bit_w;
+ // XX factor out?
+ c3_w siz_w;
+ c3_w len_w;
+ c3_w* buf_w;
+} u3a_mark;
+
+typedef struct _u3a_gack {
+ c3_w *bit_w; // mark bits
+ c3_w *pap_w; // global page bitmap
+ c3_w *pum_w; // global cumulative sums
+ // XX factor out?
+ c3_w siz_w;
+ c3_w len_w;
+ c3_w *buf_w;
+} u3a_gack;
+
+typedef struct {
+ c3_s log_s; // size log2
+ c3_s len_s; // 1U << log_s
+ c3_s tot_s; // total chunks
+ c3_s map_s; // bitmap size
+ c3_s siz_s; // wiseof(crag) - 1 + map_s
+ c3_s hun_s; // chunks reserved
+ c3_s ful_s; // tot_s - hun_s
+} u3a_hunk_dose;
+
+ extern u3a_gack u3a_Gack;
+
+ extern u3a_mark u3a_Mark;
+
+ extern u3a_hunk_dose u3a_Hunk[u3a_crag_no];
+
+ /** Globals.
+ **/
+ /// Current road (thread-local).
+ extern u3_road* u3a_Road;
+# define u3R u3a_Road
+
+ /* u3_Code: memory code.
+ */
+#ifdef U3_MEMORY_DEBUG
+ extern c3_w u3_Code;
+#endif
+
+# define u3_Loom ((c3_w *)(void *)U3_OS_LoomBase)
+
+ /* u3a_into(): convert loom offset [x] into generic pointer.
+ */
+# define u3a_into(x) ((void *)(u3_Loom + (x)))
+
+ /* u3a_outa(): convert pointer [p] into word offset into loom.
+ */
+# define u3a_outa(p) ((c3_w *)(void *)(p) - u3_Loom)
+
+ /* u3a_to_off(): mask off bits 30 and 31 from noun [som].
+ */
+# define u3a_to_off(som) (((som) & 0x3fffffff) << u3a_vits)
+
+ /* u3a_to_ptr(): convert noun [som] into generic pointer into loom.
+ */
+# define u3a_to_ptr(som) (u3a_into(u3a_to_off(som)))
+
+ /* u3a_to_wtr(): convert noun [som] into word pointer into loom.
+ */
+# define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som))
+
+ /** Inline functions.
+ **/
+ /* u3a_to_pug(): set bit 31 of [off].
+ */
+ inline c3_w u3a_to_pug(c3_w off) {
+ c3_dessert((off & u3a_walign-1) == 0);
+ return (off >> u3a_vits) | 0x80000000;
+ }
+
+ /* u3a_to_pom(): set bits 30 and 31 of [off].
+ */
+ inline c3_w u3a_to_pom(c3_w off) {
+ c3_dessert((off & u3a_walign-1) == 0);
+ return (off >> u3a_vits) | 0xc0000000;
+ }
+
+ /** road stack.
+ **/
+ /* u3a_drop(): drop a road stack frame per [pil_u].
+ */
+ inline void
+ u3a_drop(const u3a_pile* pil_u)
+ {
+ u3R->cap_p -= pil_u->mov_ws;
+ }
+
+ /* u3a_peek(): examine the top of the road stack.
+ */
+ inline void*
+ u3a_peek(const u3a_pile* pil_u)
+ {
+ return u3to(void, (u3R->cap_p + pil_u->off_ws));
+ }
+
+ /* u3a_pop(): drop a road stack frame, peek at the new top.
+ */
+ inline void*
+ u3a_pop(const u3a_pile* pil_u)
+ {
+ u3a_drop(pil_u);
+ return u3a_peek(pil_u);
+ }
+
+ /* u3a_push(): push a frame onto the road stack, per [pil_u].
+ */
+ inline void*
+ u3a_push(const u3a_pile* pil_u)
+ {
+ u3R->cap_p += pil_u->mov_ws;
+
+#ifndef U3_GUARD_PAGE
+ // !off means we're on a north road
+ //
+ if ( !pil_u->off_ws ) {
+ if( !(u3R->cap_p > u3R->hat_p) ) {
+ u3m_bail(c3__meme);
+ }
+# ifdef U3_MEMORY_DEBUG
+ u3_assert( pil_u->top_p >= u3R->cap_p );
+# endif
+ }
+ else {
+ if( !(u3R->cap_p < u3R->hat_p) ) {
+ u3m_bail(c3__meme);
+ }
+# ifdef U3_MEMORY_DEBUG
+ u3_assert( pil_u->top_p <= u3R->cap_p );
+# endif
+ }
+#endif /* ifndef U3_GUARD_PAGE */
+
+#ifdef U3_MEMORY_DEBUG
+ u3_assert( pil_u->rod_u == u3R );
+#endif
+
+ return u3a_peek(pil_u);
+ }
+
+ /* u3a_pile_done(): assert valid upon completion.
+ */
+ inline c3_o
+ u3a_pile_done(const u3a_pile* pil_u)
+ {
+ return (pil_u->top_p == u3R->cap_p) ? c3y : c3n;
+ }
+
+ /** Functions.
+ **/
+
+void
+u3a_init_once(void);
+void
+u3a_init_heap(void);
+void
+u3a_drop_heap(u3_post cap_p, u3_post ear_p);
+void
+u3a_mark_init(void);
+void*
+u3a_mark_alloc(c3_w len_w);
+void
+u3a_mark_done(void);
+
+void
+u3a_pack_init(void);
+void*
+u3a_pack_alloc(c3_w len_w);
+void
+u3a_pack_done(void);
+
+void*
+u3a_into_fn(u3_post);
+u3_post
+u3a_outa_fn(void*);
+u3_post
+u3a_to_off_fn(u3_noun);
+u3a_noun*
+u3a_to_ptr_fn(u3_noun);
+u3_noun
+u3a_head(u3_noun);
+u3_noun
+u3a_tail(u3_noun);
+void
+u3a_post_info(u3_post);
+
+ /** Allocation.
+ **/
+ /* Word-aligned allocation.
+ */
+ /* u3a_walloc(): allocate storage measured in words.
+ */
+ void*
+ u3a_walloc(c3_w len_w);
+
+ /* u3a_celloc(): allocate a cell. Faster, sometimes.
+ */
+ c3_w*
+ u3a_celloc(void);
+
+ /* u3a_wfree(): free storage.
+ */
+ void
+ u3a_wfree(void* lag_v);
+
+ /* u3a_wtrim(): trim storage.
+ */
+ void
+ u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w);
+
+ /* u3a_wealloc(): word realloc.
+ */
+ void*
+ u3a_wealloc(void* lag_v, c3_w len_w);
+
+ /* u3a_pile_prep(): initialize stack control.
+ */
+ void
+ u3a_pile_prep(u3a_pile* pil_u, c3_w len_w);
+
+ /* C-style aligned allocation - *not* compatible with above.
+ */
+ /* u3a_malloc(): aligned storage measured in bytes.
+ */
+ void*
+ u3a_malloc(size_t len_i);
+
+ /* u3a_calloc(): aligned storage measured in bytes.
+ */
+ void*
+ u3a_calloc(size_t num_i, size_t len_i);
+
+ /* u3a_realloc(): aligned realloc in bytes.
+ */
+ void*
+ u3a_realloc(void* lag_v, size_t len_i);
+
+ /* u3a_free(): free for aligned malloc.
+ */
+ void
+ u3a_free(void* tox_v);
+
+ /* Reference and arena control.
+ */
+ /* u3a_gain(): gain a reference count in normal space.
+ */
+ u3_weak
+ u3a_gain(u3_weak som);
+# define u3k(som) u3a_gain(som)
+
+ /* u3a_take(): gain, copying juniors.
+ */
+ u3_noun
+ u3a_take(u3_noun som);
+
+ /* u3a_left(): true of junior if preserved.
+ */
+ c3_o
+ u3a_left(u3_noun som);
+
+ /* u3a_lose(): lose a reference.
+ */
+ void
+ u3a_lose(u3_weak som);
+# define u3z(som) u3a_lose(som)
+
+ /* u3a_wash(): wash all lazy mugs in subtree. RETAIN.
+ */
+ void
+ u3a_wash(u3_noun som);
+
+ /* u3a_use(): reference count.
+ */
+ c3_w
+ u3a_use(u3_noun som);
+
+ /* u3a_wed(): unify noun references.
+ */
+ void
+ u3a_wed(u3_noun *restrict a, u3_noun *restrict b);
+
+ /* u3a_luse(): check refcount sanity.
+ */
+ void
+ u3a_luse(u3_noun som);
+
+ /* u3a_mark_ptr(): mark a pointer for gc. Produce size.
+ */
+ c3_w
+ u3a_mark_ptr(void* ptr_v);
+
+ /* u3a_mark_mptr(): mark a u3_malloc-allocated ptr for gc.
+ */
+ c3_w
+ u3a_mark_mptr(void* ptr_v);
+
+ /* u3a_mark_noun(): mark a noun for gc. Produce size.
+ */
+ c3_w
+ u3a_mark_noun(u3_noun som);
+
+ /* u3a_mark_road(): mark ad-hoc persistent road structures.
+ */
+ u3m_quac*
+ u3a_mark_road();
+
+ /* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3a_reclaim(void);
+
+ /* u3a_relocate_post(): replace post with relocation pointer (unchecked).
+ */
+ void
+ u3a_relocate_post(u3_post *som_p);
+
+ /* u3a_mark_relocate_post(): replace post with relocation pointer (checked).
+ */
+ u3_post
+ u3a_mark_relocate_post(u3_post som_p, c3_t *fir_t);
+
+ /* u3a_relocate_noun(): replace noun with relocation reference, recursively.
+ */
+ void
+ u3a_relocate_noun(u3_noun *som);
+
+ /* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures.
+ */
+ void
+ u3a_rewrite_compact(void);
+
+ /* u3a_count_noun(): count size of noun.
+ */
+ c3_w
+ u3a_count_noun(u3_noun som);
+
+ /* u3a_discount_noun(): clean up after counting a noun.
+ */
+ c3_w
+ u3a_discount_noun(u3_noun som);
+
+ /* u3a_count_ptr(): count a pointer for gc. Produce size. */
+ c3_w
+ u3a_count_ptr(void* ptr_v);
+
+ /* u3a_discount_ptr(): discount a pointer for gc. Produce size. */
+ c3_w
+ u3a_discount_ptr(void* ptr_v);
+
+ /* u3a_idle(): measure free-lists in [rod_u]
+ */
+ c3_w
+ u3a_idle(u3a_road* rod_u);
+
+ /* u3a_ream(): ream free-lists.
+ */
+ void
+ u3a_ream(void);
+
+void
+u3a_wait(void);
+
+void
+u3a_dash(void);
+
+ /* u3a_sweep(): sweep a fully marked road.
+ */
+ c3_w
+ u3a_sweep(void);
+
+ /* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses.
+ */
+ void
+ u3a_pack_seek(u3a_road* rod_u);
+
+ /* u3a_pack_move(): sweep the heap, moving boxes to new addresses.
+ */
+ void
+ u3a_pack_move(u3a_road* rod_u);
+
+ /* u3a_sane(): check allocator sanity.
+ */
+ void
+ u3a_sane(void);
+
+ /* u3a_lush(): leak push.
+ */
+ c3_w
+ u3a_lush(c3_w lab_w);
+
+ /* u3a_lop(): leak pop.
+ */
+ void
+ u3a_lop(c3_w lab_w);
+
+ /* u3a_print_time: print microsecond time.
+ */
+ void
+ u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d);
+
+ /* u3a_print_quac: print a quac memory report.
+ */
+ void
+ u3a_print_quac(FILE* fil_u, c3_w den_w, u3m_quac* mas_u);
+
+ /* u3a_print_memory(): print memory amount to file descriptor.
+ */
+ void
+ u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w);
+
+ /* u3a_print_memory(): print memory amount to string.
+ */
+ void
+ u3a_print_memory_str(c3_c* str_c, c3_c* cap_c, c3_w wor_w);
+
+ /* u3a_prof(): mark/measure/print memory profile. RETAIN.
+ */
+ u3m_quac*
+ u3a_prof(FILE* fil_u, u3_noun mas);
+
+ /* u3a_maid(): maybe print memory.
+ */
+ c3_w
+ u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w);
+
+ /* u3a_quac_free(): free quac memory.
+ */
+ void
+ u3a_quac_free(u3m_quac* qua_u);
+
+ /* u3a_uncap_print_memory(): un-captioned print memory amount.
+ */
+ void
+ u3a_uncap_print_memory(FILE* fil_u, c3_w byt_w);
+
+ /* u3a_deadbeef(): write 0xdeadbeef from hat to cap.
+ */
+ void
+ u3a_deadbeef(void);
+
+ /* u3a_walk_fore(): preorder traversal, visits ever limb of a noun.
+ **
+ ** cells are visited *before* their heads and tails
+ ** and can shortcircuit traversal by returning [c3n]
+ */
+ void
+ u3a_walk_fore(u3_noun a,
+ void* ptr_v,
+ void (*pat_f)(u3_atom, void*),
+ c3_o (*cel_f)(u3_noun, void*));
+
+ /* u3a_string(): `a` as an on-loom c-string.
+ */
+ c3_c*
+ u3a_string(u3_atom a);
+
+ /* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption
+ */
+ void
+ u3a_loom_sane(void);
+
+#endif /* ifndef U3_ALLOCATE_H */
diff --git a/vere/pkg/noun/build.zig b/vere/pkg/noun/build.zig
new file mode 100644
index 0000000..2a3550f
--- /dev/null
+++ b/vere/pkg/noun/build.zig
@@ -0,0 +1,439 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) !void {
+ const target = b.standardTargetOptions(.{});
+ const optimize = b.standardOptimizeOption(.{});
+ const t = target.result;
+
+ const copts: []const []const u8 =
+ b.option([]const []const u8, "copt", "") orelse &.{};
+
+ // Parse Tracy-related compiler options from copts to determine if Tracy is enabled
+ var tracy_enabled = false;
+ var tracy_callstack = false;
+ var tracy_no_exit = false;
+
+ for (copts) |opt| {
+ if (std.mem.eql(u8, opt, "-DTRACY_ENABLE")) {
+ tracy_enabled = true;
+ } else if (std.mem.eql(u8, opt, "-DTRACY_CALLSTACK")) {
+ tracy_callstack = true;
+ } else if (std.mem.eql(u8, opt, "-DTRACY_NO_EXIT")) {
+ tracy_no_exit = true;
+ }
+ }
+
+ const pkg_noun = b.addStaticLibrary(.{
+ .name = "noun",
+ .target = target,
+ .optimize = optimize,
+ });
+
+ if (target.result.os.tag.isDarwin() and !target.query.isNative()) {
+ const macos_sdk = b.lazyDependency("macos_sdk", .{
+ .target = target,
+ .optimize = optimize,
+ });
+ if (macos_sdk != null) {
+ pkg_noun.addSystemIncludePath(macos_sdk.?.path("usr/include"));
+ pkg_noun.addLibraryPath(macos_sdk.?.path("usr/lib"));
+ pkg_noun.addFrameworkPath(macos_sdk.?.path("System/Library/Frameworks"));
+ }
+ }
+
+ const pkg_c3 = b.dependency("pkg_c3", .{
+ .target = target,
+ .optimize = optimize,
+ .copt = copts,
+ });
+
+ const pkg_ent = b.dependency("pkg_ent", .{
+ .target = target,
+ .optimize = optimize,
+ .copt = copts,
+ });
+
+ const pkg_ur = b.dependency("pkg_ur", .{
+ .target = target,
+ .optimize = optimize,
+ .copt = copts,
+ });
+
+ const backtrace = b.dependency("backtrace", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const gmp = b.dependency("gmp", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const murmur3 = b.dependency("murmur3", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const openssl = b.dependency("openssl", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const pdjson = b.dependency("pdjson", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const sigsegv = b.dependency("sigsegv", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const softblas = b.dependency("softblas", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const softfloat = b.dependency("softfloat", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const unwind = b.dependency("unwind", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const urcrypt = b.dependency("urcrypt", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const whereami = b.dependency("whereami", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const zlib = b.dependency("zlib", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const wasm3 = b.dependency("wasm3", .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const tracy = if (tracy_enabled) b.dependency("tracy", .{
+ .target = target,
+ .optimize = optimize,
+ }) else null;
+
+ pkg_noun.linkLibC();
+
+ pkg_noun.linkLibrary(pkg_c3.artifact("c3"));
+ pkg_noun.linkLibrary(pkg_ent.artifact("ent"));
+ pkg_noun.linkLibrary(pkg_ur.artifact("ur"));
+
+ pkg_noun.linkLibrary(backtrace.artifact("backtrace"));
+ pkg_noun.linkLibrary(gmp.artifact("gmp"));
+
+
+
+ pkg_noun.linkLibrary(murmur3.artifact("murmur3"));
+ pkg_noun.linkLibrary(openssl.artifact("ssl"));
+ pkg_noun.linkLibrary(pdjson.artifact("pdjson"));
+ if (t.os.tag != .windows) {
+ pkg_noun.linkLibrary(sigsegv.artifact("sigsegv"));
+ }
+ pkg_noun.linkLibrary(softblas.artifact("softblas"));
+ pkg_noun.linkLibrary(softfloat.artifact("softfloat"));
+ if (t.os.tag == .linux)
+ pkg_noun.linkLibrary(unwind.artifact("unwind"));
+ pkg_noun.linkLibrary(urcrypt.artifact("urcrypt"));
+ pkg_noun.linkLibrary(whereami.artifact("whereami"));
+ pkg_noun.linkLibrary(zlib.artifact("z"));
+ pkg_noun.linkLibrary(wasm3.artifact("wasm3"));
+
+ if (tracy_enabled) {
+ pkg_noun.linkLibrary(tracy.?.artifact("tracy"));
+ pkg_noun.addIncludePath(tracy.?.path(""));
+ }
+
+ pkg_noun.addIncludePath(b.path(""));
+ if (t.os.tag.isDarwin())
+ pkg_noun.addIncludePath(b.path("platform/darwin"));
+ if (t.os.tag == .linux)
+ pkg_noun.addIncludePath(b.path("platform/linux"));
+ if (t.os.tag == .windows)
+ pkg_noun.addIncludePath(b.path("platform/windows"));
+
+ var flags = std.ArrayList([]const u8).init(b.allocator);
+ defer flags.deinit();
+ try flags.appendSlice(&.{
+ // "-pedantic",
+ "-std=gnu23",
+ });
+ try flags.appendSlice(copts);
+
+ pkg_noun.addCSourceFiles(.{
+ .root = b.path(""),
+ .files = &c_source_files,
+ .flags = flags.items,
+ });
+
+ if (t.os.tag == .windows) {
+ pkg_noun.addCSourceFiles(.{
+ .root = b.path("platform/windows"),
+ .files = &.{"veh_handler.c", "rsignal.c"},
+ .flags = flags.items,
+ });
+ }
+
+ for (install_headers) |h| pkg_noun.installHeader(b.path(h), h);
+
+ pkg_noun.installHeader(b.path(switch (t.os.tag) {
+ .macos => "platform/darwin/rsignal.h",
+ .linux => "platform/linux/rsignal.h",
+ .windows => "platform/windows/rsignal.h",
+ else => "",
+ }), "platform/rsignal.h");
+
+ b.installArtifact(pkg_noun);
+}
+
+const c_source_files = [_][]const u8{
+ "allocate.c",
+ "events.c",
+ "hashtable.c",
+ "imprison.c",
+ "jets.c",
+ "jets/a/add.c",
+ "jets/a/dec.c",
+ "jets/a/div.c",
+ "jets/a/gte.c",
+ "jets/a/gth.c",
+ "jets/a/lte.c",
+ "jets/a/lth.c",
+ "jets/a/max.c",
+ "jets/a/min.c",
+ "jets/a/mod.c",
+ "jets/a/mul.c",
+ "jets/a/sub.c",
+ "jets/b/bind.c",
+ "jets/b/clap.c",
+ "jets/b/find.c",
+ "jets/b/flop.c",
+ "jets/b/lent.c",
+ "jets/b/levy.c",
+ "jets/b/lien.c",
+ "jets/b/mate.c",
+ "jets/b/murn.c",
+ "jets/b/need.c",
+ "jets/b/reap.c",
+ "jets/b/reel.c",
+ "jets/b/roll.c",
+ "jets/b/scag.c",
+ "jets/b/skid.c",
+ "jets/b/skim.c",
+ "jets/b/skip.c",
+ "jets/b/slag.c",
+ "jets/b/snag.c",
+ "jets/b/sort.c",
+ "jets/b/turn.c",
+ "jets/b/weld.c",
+ "jets/b/zing.c",
+ "jets/c/aor.c",
+ "jets/c/bex.c",
+ "jets/c/c0n.c",
+ "jets/c/can.c",
+ "jets/c/cap.c",
+ "jets/c/cat.c",
+ "jets/c/clz.c",
+ "jets/c/ctz.c",
+ "jets/c/cut.c",
+ "jets/c/dis.c",
+ "jets/c/dor.c",
+ "jets/c/dvr.c",
+ "jets/c/end.c",
+ "jets/c/gor.c",
+ "jets/c/ham.c",
+ "jets/c/hew.c",
+ "jets/c/lsh.c",
+ "jets/c/mas.c",
+ "jets/c/met.c",
+ "jets/c/mix.c",
+ "jets/c/mor.c",
+ "jets/c/mug.c",
+ "jets/c/muk.c",
+ "jets/c/peg.c",
+ "jets/c/po.c",
+ "jets/c/pow.c",
+ "jets/c/rap.c",
+ "jets/c/rep.c",
+ "jets/c/rev.c",
+ "jets/c/rig.c",
+ "jets/c/rip.c",
+ "jets/c/rsh.c",
+ "jets/c/sew.c",
+ "jets/c/sqt.c",
+ "jets/c/swp.c",
+ "jets/c/xeb.c",
+ "jets/d/by_all.c",
+ "jets/d/by_any.c",
+ "jets/d/by_apt.c",
+ "jets/d/by_bif.c",
+ "jets/d/by_del.c",
+ "jets/d/by_dif.c",
+ "jets/d/by_gas.c",
+ "jets/d/by_get.c",
+ "jets/d/by_has.c",
+ "jets/d/by_int.c",
+ "jets/d/by_jab.c",
+ "jets/d/by_key.c",
+ "jets/d/by_put.c",
+ "jets/d/by_run.c",
+ "jets/d/by_uni.c",
+ "jets/d/by_urn.c",
+ "jets/d/in_apt.c",
+ "jets/d/in_bif.c",
+ "jets/d/in_del.c",
+ "jets/d/in_dif.c",
+ "jets/d/in_gas.c",
+ "jets/d/in_has.c",
+ "jets/d/in_int.c",
+ "jets/d/in_put.c",
+ "jets/d/in_rep.c",
+ "jets/d/in_run.c",
+ "jets/d/in_tap.c",
+ "jets/d/in_uni.c",
+ "jets/d/in_wyt.c",
+ "jets/e/adler.c",
+ "jets/e/aes_cbc.c",
+ "jets/e/aes_ecb.c",
+ "jets/e/aes_siv.c",
+ "jets/e/argon2.c",
+ "jets/e/base.c",
+ "jets/e/blake.c",
+ "jets/e/bytestream.c",
+ "jets/e/chacha.c",
+ "jets/e/crc.c",
+ "jets/e/cue.c",
+ "jets/e/ed_add_double_scalarmult.c",
+ "jets/e/ed_add_scalarmult_scalarmult_base.c",
+ "jets/e/ed_point_add.c",
+ "jets/e/ed_point_neg.c",
+ "jets/e/ed_scad.c",
+ "jets/e/ed_recs.c",
+ "jets/e/ed_smac.c",
+ "jets/e/ed_puck.c",
+ "jets/e/ed_luck.c",
+ "jets/e/ed_scalarmult.c",
+ "jets/e/ed_scalarmult_base.c",
+ "jets/e/ed_shar.c",
+ "jets/e/ed_sign.c",
+ "jets/e/ed_veri.c",
+ "jets/e/fein_ob.c",
+ "jets/e/fl.c",
+ "jets/e/fynd_ob.c",
+ "jets/e/hmac.c",
+ "jets/e/jam.c",
+ "jets/e/json_de.c",
+ "jets/e/json_en.c",
+ "jets/e/keccak.c",
+ "jets/e/leer.c",
+ "jets/e/loss.c",
+ "jets/e/lune.c",
+ "jets/e/mat.c",
+ "jets/e/mice.c",
+ "jets/e/mink.c",
+ "jets/e/mole.c",
+ "jets/e/mule.c",
+ "jets/e/parse.c",
+ "jets/e/rd.c",
+ "jets/e/rh.c",
+ "jets/e/ripe.c",
+ "jets/e/rq.c",
+ "jets/e/rs.c",
+ "jets/e/rub.c",
+ "jets/e/scot.c",
+ "jets/e/scow.c",
+ "jets/e/scr.c",
+ "jets/e/secp.c",
+ "jets/e/sha1.c",
+ "jets/e/shax.c",
+ "jets/e/slaw.c",
+ "jets/e/tape.c",
+ "jets/e/trip.c",
+ "jets/e/urwasm.c",
+ "jets/e/zlib.c",
+ "jets/f/cell.c",
+ "jets/f/comb.c",
+ "jets/f/cons.c",
+ "jets/f/core.c",
+ "jets/f/face.c",
+ "jets/f/fine.c",
+ "jets/f/fitz.c",
+ "jets/f/flan.c",
+ "jets/f/flip.c",
+ "jets/f/flor.c",
+ "jets/f/fork.c",
+ "jets/f/help.c",
+ "jets/f/hint.c",
+ "jets/f/look.c",
+ "jets/f/loot.c",
+ "jets/f/ut_crop.c",
+ "jets/f/ut_fish.c",
+ "jets/f/ut_fuse.c",
+ "jets/f/ut_redo.c",
+ "jets/f/ut_mint.c",
+ "jets/f/ut_mull.c",
+ "jets/f/ut_nest.c",
+ "jets/f/ut_rest.c",
+ "jets/g/plot.c",
+ "jets/i/lagoon.c",
+ "jets/tree.c",
+ "jets/137/tree.c",
+ "jets/136/tree.c",
+ "log.c",
+ "manage.c",
+ "palloc.c",
+ "nock.c",
+ "options.c",
+ "retrieve.c",
+ "ship.c",
+ "serial.c",
+ "trace.c",
+ "urth.c",
+ "vortex.c",
+ "xtract.c",
+ "zave.c",
+};
+
+const install_headers = [_][]const u8{
+ "allocate.h",
+ "error.h",
+ "events.h",
+ "hashtable.h",
+ "imprison.h",
+ "jets.h",
+ "jets/k.h",
+ "jets/q.h",
+ "jets/w.h",
+ "log.h",
+ "manage.h",
+ "nock.h",
+ "noun.h",
+ "options.h",
+ "retrieve.h",
+ "serial.h",
+ "ship.h",
+ "trace.h",
+ "types.h",
+ "urth.h",
+ "version.h",
+ "vortex.h",
+ "xtract.h",
+ "zave.h",
+ "verstable.h",
+};
diff --git a/vere/pkg/noun/build.zig.zon b/vere/pkg/noun/build.zig.zon
new file mode 100644
index 0000000..a5c72a9
--- /dev/null
+++ b/vere/pkg/noun/build.zig.zon
@@ -0,0 +1,67 @@
+.{
+ .name = .noun,
+ .fingerprint = 0x417412dd00c7ed8c,
+ .version = "0.0.1",
+ .dependencies = .{
+ .macos_sdk = .{
+ .url = "https://github.com/joseluisq/macosx-sdks/releases/download/14.5/MacOSX14.5.sdk.tar.xz",
+ .hash = "N-V-__8AAKtK4FMzqcFsY_ZrpMg9bGH0h7BqZDXtVyAerMtM",
+ .lazy = true,
+ },
+ .pkg_c3 = .{
+ .path = "../c3",
+ },
+ .pkg_ent = .{
+ .path = "../ent",
+ },
+ .pkg_ur = .{
+ .path = "../ur",
+ },
+ .backtrace = .{
+ .path = "../../ext/backtrace",
+ },
+ .gmp = .{
+ .path = "../../ext/gmp",
+ },
+ .murmur3 = .{
+ .path = "../../ext/murmur3",
+ },
+ .openssl = .{
+ .path = "../../ext/openssl",
+ },
+ .pdjson = .{
+ .path = "../../ext/pdjson",
+ },
+ .sigsegv = .{
+ .path = "../../ext/sigsegv",
+ },
+ .softblas = .{
+ .path = "../../ext/softblas",
+ },
+ .softfloat = .{
+ .path = "../../ext/softfloat",
+ },
+ .unwind = .{
+ .path = "../../ext/unwind",
+ },
+ .urcrypt = .{
+ .path = "../../ext/urcrypt",
+ },
+ .whereami = .{
+ .path = "../../ext/whereami",
+ },
+ .zlib = .{
+ .url = "https://github.com/allyourcodebase/zlib/archive/61e7df7e996ec5a5f13a653db3c419adb340d6ef.tar.gz",
+ .hash = "zlib-1.3.1-ZZQ7lbYMAAB1hTSOKSXAKAgHsfDcyWNH_37ojw5WSpgR",
+ },
+ .wasm3 = .{
+ .path = "../../ext/wasm3",
+ },
+ .tracy = .{
+ .path = "../../ext/tracy",
+ },
+ },
+ .paths = .{
+ "",
+ },
+}
diff --git a/vere/pkg/noun/equality_tests.c b/vere/pkg/noun/equality_tests.c
new file mode 100644
index 0000000..83a5026
--- /dev/null
+++ b/vere/pkg/noun/equality_tests.c
@@ -0,0 +1,164 @@
+/// @file
+
+#include "noun.h"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_boot_lite(1 << 24);
+}
+
+static c3_i
+_test_unify_home(void)
+{
+ c3_i ret_i = 1;
+
+ u3_noun a = u3nt(0, 0, 0);
+ u3_noun b = u3nt(0, 0, 0);
+ c3_w kep_w;
+
+ u3_assert( u3t(a) < u3t(b) );
+ kep_w = u3t(a);
+
+ (void)u3r_sing(a, b);
+
+ if ( u3t(a) != u3t(b) ) {
+ fprintf(stderr, "test: unify home: failed\r\n");
+ ret_i = 0;
+ }
+ else if ( kep_w != u3t(b) ) {
+ fprintf(stderr, "test: unify home: deeper failed\r\n");
+ ret_i = 0;
+ }
+
+ u3z(a); u3z(b);
+
+ return ret_i;
+}
+
+static c3_i
+_test_unify_inner(void)
+{
+ c3_i ret_i = 1;
+ c3_w kep_w;
+ u3_noun a, b;
+
+ a = u3nt(0, 0, 0);
+ kep_w = u3t(a);
+
+ u3m_hate(0);
+
+ b = u3nt(0, 0, 0);
+
+ (void)u3r_sing(a, b);
+
+ if ( u3t(a) != u3t(b) ) {
+ fprintf(stderr, "test: unify inner 1: failed\r\n");
+ ret_i = 0;
+ }
+ else if ( kep_w != u3t(b) ) {
+ fprintf(stderr, "test: unify inner 1: deeper failed\r\n");
+ ret_i = 0;
+ }
+
+ b = u3m_love(0);
+
+ u3z(a); u3z(b);
+
+ // --------
+
+ b = u3nt(0, 0, 0);
+ kep_w = u3t(b);
+
+ u3m_hate(0);
+
+ a = u3nt(0, 0, 0);
+
+ u3m_hate(0);
+
+ (void)u3r_sing(a, b);
+
+ if ( u3t(a) != u3t(b) ) {
+ fprintf(stderr, "test: unify inner 2: failed\r\n");
+ ret_i = 0;
+ }
+ else if ( kep_w != u3t(a) ) {
+ fprintf(stderr, "test: unify inner 2: deeper failed\r\n");
+ ret_i = 0;
+ }
+
+ a = u3m_love(u3m_love(0));
+
+ u3z(a); u3z(b);
+
+ return ret_i;
+}
+
+static c3_i
+_test_unify_inner_home(void)
+{
+ c3_i ret_i = 1;
+
+ u3_noun a = u3nt(0, 0, 0);
+ u3_noun b = u3nt(0, 0, 0);
+
+ u3m_hate(0);
+
+ (void)u3r_sing(a, b);
+
+ if ( u3t(a) == u3t(b) ) {
+ fprintf(stderr, "test: unify inner-home: succeeded?\r\n");
+ ret_i = 0;
+ }
+
+ u3m_love(0);
+
+ u3z(a); u3z(b);
+
+ return ret_i;
+}
+
+static c3_i
+_test_equality(void)
+{
+ c3_i ret_i = 1;
+
+ if ( !_test_unify_home() ) {
+ fprintf(stderr, "test: equality: unify home: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_unify_inner() ) {
+ fprintf(stderr, "test: equality: unify inner: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_unify_inner_home() ) {
+ fprintf(stderr, "test: equality: unify inner-home: failed\r\n");
+ ret_i = 0;
+ }
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_equality() ) {
+ fprintf(stderr, "test equality: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test equality: ok\r\n");
+ return 0;
+}
diff --git a/vere/pkg/noun/error.h b/vere/pkg/noun/error.h
new file mode 100644
index 0000000..57932bf
--- /dev/null
+++ b/vere/pkg/noun/error.h
@@ -0,0 +1,38 @@
+/// @file
+
+#ifndef U3_ERROR_H
+#define U3_ERROR_H
+
+#include "manage.h"
+
+/* Assert. Good to capture.
+
+ TODO: determine which u3_assert calls can rather call c3_dessert, i.e. in
+ public releases, which calls to u3_assert should abort and which should
+ no-op? If the latter, is the assert useful inter-development to validate
+ conditions we might accidentally break or not useful at all?
+*/
+
+#if defined(ASAN_ENABLED) && defined(__clang__)
+# define u3_assert(x) \
+ do { \
+ if (!(x)) { \
+ u3m_bail(c3__oops); \
+ abort(); \
+ } \
+ } while(0)
+#else
+# define u3_assert(x) \
+ do { \
+ if (!(x)) { \
+ fflush(stderr); \
+ fprintf(stderr, "\rAssertion '%s' " \
+ "failed in %s:%d\r\n", \
+ #x, __FILE__, __LINE__); \
+ u3m_bail(c3__oops); \
+ abort(); \
+ } \
+ } while(0)
+#endif /* if defined(ASAN_ENABLED) && defined(__clang__) */
+
+#endif /* ifndef U3_ERROR_H */
diff --git a/vere/pkg/noun/events.c b/vere/pkg/noun/events.c
new file mode 100644
index 0000000..956b87d
--- /dev/null
+++ b/vere/pkg/noun/events.c
@@ -0,0 +1,1583 @@
+//! @file events.c
+//!
+//! incremental, orthogonal, paginated loom snapshots
+//!
+//! ### components
+//!
+//! - page: 16KB chunk of the loom.
+//! - image (u3e_image, image.bin): low contiguous loom pages,
+//! (in practice, the home road heap). indexed from low to high:
+//! in-order on disk. in a file-backed mapping by default.
+//! - patch memory (memory.bin): new or changed pages since the last snapshot
+//! - patch control (u3e_control control.bin): patch metadata, watermarks,
+//! and indices/checksums for pages in patch memory.
+//!
+//! ### initialization (u3e_live())
+//!
+//! - with the loom already mapped, all pages are marked dirty in a bitmap.
+//! - if snapshot is missing or partial, empty segments are created.
+//! - if a patch is present, it's applied (crash recovery).
+//! - snapshot segments are mapped or copied onto the loom;
+//! all included pages are marked clean and protected (read-only).
+//!
+//! #### page faults (u3e_fault())
+//!
+//! - stores into protected pages generate faults (currently SIGSEGV,
+//! handled outside this module).
+//! - faults are handled by dirtying the page and switching protections to
+//! read/write.
+//! - a guard page is initially placed in the approximate middle of the free
+//! space between the heap and stack at the time of the first page fault.
+//! when a fault is detected in the guard page, the guard page is recentered
+//! in the free space of the current road. if the guard page cannot be
+//! recentered, then memory exhaustion has occurred.
+//!
+//! ### updates (u3e_save())
+//!
+//! - all updates to a snapshot are made through a patch.
+//! - high/low watermarks are established,
+//! and dirty pages below the low mark are added to the patch.
+//! - modifications have been caught by the fault handler.
+//! - newly-used pages are automatically included (preemptively dirtied).
+//! - unused, innermost pages are reclaimed (segments are truncated to the
+//! high/low watermarks; the last page in each is always adjacent to the
+//! contiguous free space).
+//! - patch pages are written to memory.bin, metadata to control.bin.
+//! - the patch is applied to the snapshot segments, in-place.
+//! - segments are fsync'd; patch files are deleted.
+//! - memory protections (and file-backed mappings) are re-established.
+//!
+//! ### invariants
+//!
+//! definitions:
+//! - a clean page is PROT_READ and 0 in the bitmap
+//! - a dirty page is (PROT_READ|PROT_WRITE) and 1 in the bitmap
+//! - the guard page is PROT_NONE and 1 in the bitmap
+//!
+//! assumptions:
+//! - all memory access patterns are outside-in, a page at a time
+//! - ad-hoc exceptions are supported by calling u3e_ward()
+//!
+//! - there is a single guard page, between the segments
+//! - dirty pages only become clean by being:
+//! - loaded from a snapshot during initialization
+//! - present in a snapshot after save
+//! - clean pages only become dirty by being:
+//! - modified (and caught by the fault handler)
+//! - orphaned due to segment truncation (explicitly dirtied)
+//! - at points of quiescence (initialization, after save)
+//! - all pages of the image are clean
+//! - all other pages are dirty
+//!
+//! ### limitations
+//!
+//! - loom page size is fixed (16 KB), and must be a multiple of the
+//! system page size.
+//! - update atomicity is crucial:
+//! - patch application must either completely succeed or
+//! leave on-disk segments (memory image) intact.
+//! - unapplied patches can be discarded (triggering event replay),
+//! but once patch application begins it must succeed.
+//! - may require integration into the overall signal-handling regime.
+//! - any errors are handled with assertions; error messages are poor;
+//! failed/partial writes are not retried.
+//!
+//! ### enhancements
+//!
+//! - use platform specific page fault mechanism (mach rpc, userfaultfd, &c).
+//! - parallelism (conflicts with demand paging)
+//!
+
+#include "events.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#include "log.h"
+#include "murmur3.h"
+#include "options.h"
+
+/* _ce_len: byte length of pages
+** _ce_len_words: word length of pages
+** _ce_page: byte length of a single page
+** _ce_ptr: void pointer to a page
+*/
+#define _ce_len(i) ((size_t)(i) << (u3a_page + 2))
+#define _ce_len_words(i) ((size_t)(i) << u3a_page)
+#define _ce_page _ce_len(1)
+#define _ce_ptr(i) ((void *)((c3_c*)u3_Loom + _ce_len(i)))
+
+/// Snapshotting system.
+u3e_pool u3e_Pool;
+
+static c3_w
+_ce_muk_buf(c3_w len_w, void* ptr_v)
+{
+ c3_w haz_w;
+ MurmurHash3_x86_32(ptr_v, len_w, 0xcafebabeU, &haz_w);
+ return haz_w;
+}
+
+static c3_w
+_ce_muk_page(void* ptr_v)
+{
+ return _ce_muk_buf(_ce_page, ptr_v);
+}
+
+/* _ce_flaw_mmap(): remap non-guard page after fault.
+*/
+static inline c3_i
+_ce_flaw_mmap(c3_w pag_w)
+{
+ // NB: must be static, since the stack is grown via page faults, and
+ // we're already in a page fault handler.
+ //
+ static c3_y con_y[_ce_page];
+
+ // save contents of page, to be restored after the mmap
+ //
+ memcpy(con_y, _ce_ptr(pag_w), _ce_page);
+
+ // map the dirty page into the ephemeral file
+ //
+ if ( MAP_FAILED == mmap(_ce_ptr(pag_w),
+ _ce_page,
+ (PROT_READ | PROT_WRITE),
+ (MAP_FIXED | MAP_SHARED),
+ u3P.eph_i, _ce_len(pag_w)) )
+ {
+ fprintf(stderr, "loom: fault mmap failed (%u): %s\r\n",
+ pag_w, strerror(errno));
+ return 1;
+ }
+
+ // restore contents of page
+ //
+ memcpy(_ce_ptr(pag_w), con_y, _ce_page);
+
+ return 0;
+}
+
+/* _ce_flaw_mprotect(): protect page after fault.
+*/
+static inline c3_i
+_ce_flaw_mprotect(c3_w pag_w)
+{
+ if ( 0 != mprotect(_ce_ptr(pag_w), _ce_page, (PROT_READ | PROT_WRITE)) ) {
+ fprintf(stderr, "loom: fault mprotect (%u): %s\r\n",
+ pag_w, strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef U3_GUARD_PAGE
+/* _ce_ward_protect(): protect the guard page.
+*/
+static inline c3_i
+_ce_ward_protect(void)
+{
+ if ( 0 != mprotect(_ce_ptr(u3P.gar_w), _ce_page, PROT_NONE) ) {
+ fprintf(stderr, "loom: failed to protect guard page (%u): %s\r\n",
+ u3P.gar_w, strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+/* _ce_ward_post(): set the guard page.
+*/
+static inline c3_i
+_ce_ward_post(c3_w nop_w, c3_w sop_w)
+{
+ u3P.gar_w = nop_w + ((sop_w - nop_w) / 2);
+ return _ce_ward_protect();
+}
+
+/* _ce_ward_clip(): hit the guard page.
+*/
+static inline u3e_flaw
+_ce_ward_clip(c3_w nop_w, c3_w sop_w)
+{
+ c3_w old_w = u3P.gar_w;
+
+ if ( !u3P.gar_w || ((nop_w < u3P.gar_w) && (sop_w > u3P.gar_w)) ) {
+ fprintf(stderr, "loom: ward bogus (>%u %u %u<)\r\n",
+ nop_w, u3P.gar_w, sop_w);
+ return u3e_flaw_sham;
+ }
+
+ if ( sop_w <= (nop_w + 1) ) {
+ return u3e_flaw_meme;
+ }
+
+ if ( _ce_ward_post(nop_w, sop_w) ) {
+ return u3e_flaw_base;
+ }
+
+ u3_assert( old_w != u3P.gar_w );
+
+ return u3e_flaw_good;
+}
+#endif /* ifdef U3_GUARD_PAGE */
+
+/* u3e_fault(): handle a memory fault.
+*/
+u3e_flaw
+u3e_fault(u3_post low_p, u3_post hig_p, u3_post off_p)
+{
+ c3_w pag_w = off_p >> u3a_page;
+ c3_w blk_w = pag_w >> 5;
+ c3_w bit_w = pag_w & 31;
+
+#ifdef U3_GUARD_PAGE
+ c3_w gar_w = u3P.gar_w;
+
+ if ( pag_w == gar_w ) {
+ u3e_flaw fal_e = _ce_ward_clip(low_p >> u3a_page, hig_p >> u3a_page);
+
+ if ( u3e_flaw_good != fal_e ) {
+ return fal_e;
+ }
+
+ if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) ) {
+ fprintf(stderr, "loom: strange guard (%d)\r\n", pag_w);
+ return u3e_flaw_sham;
+ }
+
+ if ( _ce_flaw_mprotect(pag_w) ) {
+ return u3e_flaw_base;
+ }
+
+ return u3e_flaw_good;
+ }
+#endif
+
+ if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) {
+ fprintf(stderr, "loom: strange page (%d): %x\r\n", pag_w, off_p);
+ return u3e_flaw_sham;
+ }
+
+ u3P.dit_w[blk_w] |= ((c3_w)1 << bit_w);
+
+ if ( u3P.eph_i ) {
+ if ( _ce_flaw_mmap(pag_w) ) {
+ return u3e_flaw_base;
+ }
+ }
+ else if ( _ce_flaw_mprotect(pag_w) ) {
+ return u3e_flaw_base;
+ }
+
+ return u3e_flaw_good;
+}
+
+typedef enum {
+ _ce_img_good = 0,
+ _ce_img_fail = 1,
+ _ce_img_size = 2
+} _ce_img_stat;
+
+/* _ce_image_stat(): measure image.
+*/
+static _ce_img_stat
+_ce_image_stat(u3e_image* img_u, c3_w* pgs_w)
+{
+ struct stat buf_u;
+
+ if ( -1 == fstat(img_u->fid_i, &buf_u) ) {
+ fprintf(stderr, "loom: image stat: %s\r\n", strerror(errno));
+ u3_assert(0);
+ return _ce_img_fail;
+ }
+ else {
+ c3_z siz_z = buf_u.st_size;
+ c3_z pgs_z = (siz_z + (_ce_page - 1)) >> (u3a_page + 2);
+
+ if ( !siz_z ) {
+ *pgs_w = 0;
+ return _ce_img_good;
+ }
+ else if ( siz_z != _ce_len(pgs_z) ) {
+ fprintf(stderr, "loom: image corrupt size %zu\r\n", siz_z);
+ return _ce_img_size;
+ }
+ else if ( pgs_z > UINT32_MAX ) {
+ fprintf(stderr, "loom: image overflow %zu\r\n", siz_z);
+ return _ce_img_fail;
+ }
+ else {
+ *pgs_w = (c3_w)pgs_z;
+ return _ce_img_good;
+ }
+ }
+}
+
+/* _ce_ephemeral_open(): open or create ephemeral file
+*/
+static c3_o
+_ce_ephemeral_open(c3_i* eph_i)
+{
+ c3_i mod_i = O_RDWR | O_CREAT;
+ c3_c ful_c[8193];
+
+ if ( u3C.eph_c == 0 ) {
+ snprintf(ful_c, 8192, "%s", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/limbo.bin", u3P.dir_c);
+ u3C.eph_c = strdup(ful_c);
+ }
+
+ if ( -1 == (*eph_i = c3_open(u3C.eph_c, mod_i, 0666)) ) {
+ fprintf(stderr, "loom: ephemeral c3_open %s: %s\r\n", u3C.eph_c,
+ strerror(errno));
+ return c3n;
+ }
+
+ if ( ftruncate(*eph_i, _ce_len(u3P.pag_w)) < 0 ) {
+ fprintf(stderr, "loom: ephemeral ftruncate %s: %s\r\n", u3C.eph_c,
+ strerror(errno));
+ return c3n;
+ }
+ return c3y;
+}
+
+/* _ce_image_open(): open or create image.
+*/
+static _ce_img_stat
+_ce_image_open(u3e_image* img_u, c3_c* ful_c)
+{
+ c3_i mod_i = O_RDWR | O_CREAT;
+
+ c3_c pax_c[8192];
+ snprintf(pax_c, 8192, "%s/%s.bin", ful_c, img_u->nam_c);
+ if ( -1 == (img_u->fid_i = c3_open(pax_c, mod_i, 0666)) ) {
+ fprintf(stderr, "loom: c3_open %s: %s\r\n", pax_c, strerror(errno));
+ return _ce_img_fail;
+ }
+
+ return _ce_image_stat(img_u, &img_u->pgs_w);
+}
+
+c3_i
+u3e_image_open_any(c3_c* nam_c, c3_c* dir_c, c3_z* len_z)
+{
+ u3e_image img_u = { .nam_c = nam_c };
+
+ switch ( _ce_image_open(&img_u, dir_c) ) {
+ case _ce_img_good: {
+ *len_z = _ce_len(img_u.pgs_w);
+ return img_u.fid_i;
+ } break;
+
+ case _ce_img_fail:
+ case _ce_img_size: {
+ *len_z = 0;
+ return -1;
+ } break;
+ }
+}
+
+/* _ce_patch_write_control(): write control block file.
+*/
+static void
+_ce_patch_write_control(u3_ce_patch* pat_u)
+{
+ ssize_t ret_i;
+ c3_w len_w = sizeof(u3e_control) +
+ (pat_u->con_u->pgs_w * sizeof(u3e_line));
+
+ if ( len_w != (ret_i = write(pat_u->ctl_i, pat_u->con_u, len_w)) ) {
+ if ( 0 < ret_i ) {
+ fprintf(stderr, "loom: patch ctl partial write: %zu\r\n", (size_t)ret_i);
+ }
+ else {
+ fprintf(stderr, "loom: patch ctl write: %s\r\n", strerror(errno));
+ }
+ u3_assert(0);
+ }
+}
+
+/* _ce_patch_read_control(): read control block file.
+*/
+static c3_o
+_ce_patch_read_control(u3_ce_patch* pat_u)
+{
+ c3_w len_w;
+
+ u3_assert(0 == pat_u->con_u);
+ {
+ struct stat buf_u;
+
+ if ( -1 == fstat(pat_u->ctl_i, &buf_u) ) {
+ u3_assert(0);
+ return c3n;
+ }
+ len_w = (c3_w) buf_u.st_size;
+ }
+
+ if (0 == len_w) {
+ return c3n;
+ }
+
+ pat_u->con_u = c3_malloc(len_w);
+ if ( (len_w != read(pat_u->ctl_i, pat_u->con_u, len_w)) ||
+ (len_w != sizeof(u3e_control) +
+ (pat_u->con_u->pgs_w * sizeof(u3e_line))) )
+ {
+ c3_free(pat_u->con_u);
+ pat_u->con_u = 0;
+ return c3n;
+ }
+ return c3y;
+}
+
+/* _ce_patch_create(): create patch files.
+*/
+static void
+_ce_patch_create(u3_ce_patch* pat_u)
+{
+ c3_c ful_c[8193];
+
+ snprintf(ful_c, 8192, "%s", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
+ if ( -1 == (pat_u->ctl_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
+ fprintf(stderr, "loom: patch c3_open control.bin: %s\r\n", strerror(errno));
+ u3_assert(0);
+ }
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
+ if ( -1 == (pat_u->mem_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
+ fprintf(stderr, "loom: patch c3_open memory.bin: %s\r\n", strerror(errno));
+ u3_assert(0);
+ }
+}
+
+/* _ce_patch_delete(): delete a patch.
+*/
+static void
+_ce_patch_delete(void)
+{
+ c3_c ful_c[8193];
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
+ if ( unlink(ful_c) ) {
+ fprintf(stderr, "loom: failed to delete control.bin: %s\r\n",
+ strerror(errno));
+ }
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
+ if ( unlink(ful_c) ) {
+ fprintf(stderr, "loom: failed to remove memory.bin: %s\r\n",
+ strerror(errno));
+ }
+}
+
+/* _ce_patch_verify(): check patch data checksum.
+*/
+static c3_o
+_ce_patch_verify(u3_ce_patch* pat_u)
+{
+ c3_w pag_w, has_w;
+ c3_y buf_y[_ce_page];
+ c3_zs ret_zs;
+
+ if ( U3P_VERLAT != pat_u->con_u->ver_w ) {
+ fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_w", need %u\r\n",
+ pat_u->con_u->ver_w,
+ U3P_VERLAT);
+ return c3n;
+ }
+
+ {
+ c3_w len_w = sizeof(u3e_control) + (pat_u->con_u->pgs_w * sizeof(u3e_line));
+ c3_w off_w = offsetof(u3e_control, tot_w);
+ c3_y *ptr_y = (c3_y*)pat_u->con_u + off_w;
+ c3_w has_w = _ce_muk_buf(len_w - off_w, ptr_y);
+
+ if ( has_w != pat_u->con_u->has_w ) {
+ fprintf(stderr, "loom: patch meta checksum fail: "
+ "have=0x%"PRIxc3_w", need=0x%"PRIxc3_w"\r\n",
+ has_w, pat_u->con_u->has_w);
+ return c3n;
+ }
+ }
+
+ // XX check for sorted page numbers?
+ //
+ for ( c3_z i_z = 0; i_z < pat_u->con_u->pgs_w; i_z++ ) {
+ pag_w = pat_u->con_u->mem_u[i_z].pag_w;
+ has_w = pat_u->con_u->mem_u[i_z].has_w;
+
+ if ( _ce_page !=
+ (ret_zs = pread(pat_u->mem_i, buf_y, _ce_page, _ce_len(i_z))) )
+ {
+ if ( 0 < ret_zs ) {
+ fprintf(stderr, "loom: patch partial read: %"PRIc3_zs"\r\n", ret_zs);
+ }
+ else {
+ fprintf(stderr, "loom: patch read: fail %s\r\n", strerror(errno));
+ }
+ return c3n;
+ }
+
+ {
+ c3_w nas_w = _ce_muk_page(buf_y);
+
+ if ( has_w != nas_w ) {
+ fprintf(stderr, "loom: patch page (%"PRIc3_w") checksum fail: "
+ "have=0x%"PRIxc3_w", need=0x%"PRIxc3_w"\r\n",
+ pag_w, nas_w, has_w);
+ return c3n;
+ }
+#if 0
+ else {
+ u3l_log("verify: patch %"PRIc3_w"/%"PRIc3_z", %"PRIxc3_w"\r\n", pag_w, i_z, has_w);
+ }
+#endif
+ }
+ }
+
+ return c3y;
+}
+
+/* _ce_patch_free(): free a patch.
+*/
+static void
+_ce_patch_free(u3_ce_patch* pat_u)
+{
+ c3_free(pat_u->con_u);
+ close(pat_u->ctl_i);
+ close(pat_u->mem_i);
+ c3_free(pat_u);
+}
+
+/* _ce_patch_open(): open patch, if any.
+*/
+static u3_ce_patch*
+_ce_patch_open(void)
+{
+ u3_ce_patch* pat_u;
+ c3_c ful_c[8193];
+ c3_i ctl_i, mem_i;
+
+ snprintf(ful_c, 8192, "%s", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
+ c3_mkdir(ful_c, 0700);
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
+ if ( -1 == (ctl_i = c3_open(ful_c, O_RDWR)) ) {
+ return 0;
+ }
+
+ snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
+ if ( -1 == (mem_i = c3_open(ful_c, O_RDWR)) ) {
+ close(ctl_i);
+
+ _ce_patch_delete();
+ return 0;
+ }
+ pat_u = c3_malloc(sizeof(u3_ce_patch));
+ pat_u->ctl_i = ctl_i;
+ pat_u->mem_i = mem_i;
+ pat_u->con_u = 0;
+
+ if ( c3n == _ce_patch_read_control(pat_u) ) {
+ close(pat_u->ctl_i);
+ close(pat_u->mem_i);
+ c3_free(pat_u);
+
+ _ce_patch_delete();
+ return 0;
+ }
+ if ( c3n == _ce_patch_verify(pat_u) ) {
+ _ce_patch_free(pat_u);
+ _ce_patch_delete();
+ return 0;
+ }
+ return pat_u;
+}
+
+/* _ce_patch_write_page(): write a page of patch memory.
+*/
+static void
+_ce_patch_write_page(u3_ce_patch* pat_u,
+ c3_w pgc_w,
+ c3_w* mem_w)
+{
+ c3_zs ret_zs;
+
+ if ( _ce_page !=
+ (ret_zs = pwrite(pat_u->mem_i, mem_w, _ce_page, _ce_len(pgc_w))) )
+ {
+ if ( 0 < ret_zs ) {
+ fprintf(stderr, "loom: patch partial write: %"PRIc3_zs"\r\n", ret_zs);
+ }
+ else {
+ fprintf(stderr, "loom: patch write: fail: %s\r\n", strerror(errno));
+ }
+ fprintf(stderr, "info: you probably have insufficient disk space");
+ u3_assert(0);
+ }
+}
+
+/* _ce_patch_count_page(): count a page, producing new counter.
+*/
+static c3_w
+_ce_patch_count_page(c3_w pag_w,
+ c3_w off_w,
+ c3_w pgc_w)
+{
+ c3_w blk_w = (pag_w >> 5);
+ c3_w bit_w = (pag_w & 31);
+
+ if ( (u3P.dit_w[blk_w] & ((c3_w)1 << bit_w))
+ && ( (pag_w < off_w)
+ || (u3R->hep.len_w <= (pag_w - off_w))
+ || (u3a_free_pg != (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) ) )
+ {
+ pgc_w += 1;
+ }
+
+ return pgc_w;
+}
+
+/* _ce_patch_save_page(): save a page, producing new page counter.
+*/
+static c3_w
+_ce_patch_save_page(u3_ce_patch* pat_u,
+ c3_w pag_w,
+ c3_w off_w,
+ c3_w pgc_w)
+{
+ c3_w blk_w = (pag_w >> 5);
+ c3_w bit_w = (pag_w & 31);
+
+ if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) {
+ if ( (pag_w >= off_w)
+ && (u3R->hep.len_w > (pag_w - off_w))
+ && (u3a_free_pg == (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) )
+ {
+ // fprintf(stderr, "save: skip %u\r\n", pag_w);
+ pat_u->sip_w++;
+ return pgc_w;
+ }
+
+ c3_w* mem_w = _ce_ptr(pag_w);
+
+ pat_u->con_u->mem_u[pgc_w].pag_w = pag_w;
+ pat_u->con_u->mem_u[pgc_w].has_w = _ce_muk_page(mem_w);
+
+#if 0
+ fprintf(stderr, "loom: save page %d %x\r\n",
+ pag_w, pat_u->con_u->mem_u[pgc_w].has_w);
+#endif
+ _ce_patch_write_page(pat_u, pgc_w, mem_w);
+
+ pgc_w += 1;
+ }
+ return pgc_w;
+}
+
+/* _ce_patch_compose(): make and write current patch.
+*/
+static u3_ce_patch*
+_ce_patch_compose(c3_w max_w)
+{
+ c3_w pgs_w = 0;
+ c3_w off_w = u3R->rut_p >> u3a_page;
+
+ /* Count dirty pages.
+ */
+ {
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ pgs_w = _ce_patch_count_page(i_w, off_w, pgs_w);
+ }
+ }
+
+ if ( !pgs_w ) {
+ return 0;
+ }
+ else {
+ u3_ce_patch* pat_u = c3_malloc(sizeof(u3_ce_patch));
+ c3_w i_w, len_w, pgc_w;
+
+ pat_u->sip_w = 0;
+
+ _ce_patch_create(pat_u);
+ len_w = sizeof(u3e_control) + (pgs_w * sizeof(u3e_line));
+ pat_u->con_u = c3_malloc(len_w);
+ pat_u->con_u->ver_w = U3P_VERLAT;
+ pgc_w = 0;
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ pgc_w = _ce_patch_save_page(pat_u, i_w, off_w, pgc_w);
+ }
+
+ u3_assert( pgc_w == pgs_w );
+
+ pat_u->con_u->tot_w = max_w;
+ pat_u->con_u->pgs_w = pgc_w;
+
+ {
+ c3_w off_w = offsetof(u3e_control, tot_w);
+ c3_y *ptr_y = (c3_y*)pat_u->con_u + off_w;
+
+ pat_u->con_u->has_w = _ce_muk_buf(len_w - off_w, ptr_y);
+ }
+
+ _ce_patch_write_control(pat_u);
+ return pat_u;
+ }
+}
+
+/* _ce_patch_sync(): make sure patch is synced to disk.
+*/
+static void
+_ce_patch_sync(u3_ce_patch* pat_u)
+{
+ if ( -1 == c3_sync(pat_u->ctl_i) ) {
+ fprintf(stderr, "loom: control file sync failed: %s\r\n",
+ strerror(errno));
+ u3_assert(!"loom: control sync");
+ }
+
+ if ( -1 == c3_sync(pat_u->mem_i) ) {
+ fprintf(stderr, "loom: patch file sync failed: %s\r\n",
+ strerror(errno));
+ u3_assert(!"loom: patch sync");
+ }
+}
+
+/* _ce_image_sync(): make sure image is synced to disk.
+*/
+static c3_o
+_ce_image_sync(u3e_image* img_u)
+{
+ if ( -1 == c3_sync(img_u->fid_i) ) {
+ fprintf(stderr, "loom: image sync failed: %s\r\n", strerror(errno));
+ return c3n;
+ }
+
+ return c3y;
+}
+
+/* _ce_image_resize(): resize image, truncating if it shrunk.
+*/
+static void
+_ce_image_resize(u3e_image* img_u, c3_w pgs_w)
+{
+ c3_z off_z = _ce_len(pgs_w);
+ off_t off_i = (off_t)off_z;
+
+ if ( img_u->pgs_w > pgs_w ) {
+ if ( off_z != (size_t)off_i ) {
+ fprintf(stderr, "loom: image truncate: "
+ "offset overflow (%" PRId64 ") for page %u\r\n",
+ (c3_ds)off_i, pgs_w);
+ u3_assert(0);
+ }
+
+ if ( ftruncate(img_u->fid_i, off_i) ) {
+ fprintf(stderr, "loom: image truncate: %s\r\n", strerror(errno));
+ u3_assert(0);
+ }
+ }
+
+ img_u->pgs_w = pgs_w;
+}
+
+/* _ce_patch_apply(): apply patch to images.
+*/
+static void
+_ce_patch_apply(u3_ce_patch* pat_u)
+{
+ c3_zs ret_zs;
+ c3_w i_w;
+
+ // resize images
+ //
+ _ce_image_resize(&u3P.img_u, pat_u->con_u->tot_w);
+
+ // seek to begining of patch
+ //
+ if ( -1 == lseek(pat_u->mem_i, 0, SEEK_SET) ) {
+ fprintf(stderr, "loom: patch apply seek: %s\r\n", strerror(errno));
+ u3_assert(0);
+ }
+
+ c3_i fid_i = u3P.img_u.fid_i;
+
+ // write patch pages into the appropriate image
+ //
+ for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) {
+ c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w;
+ c3_y buf_y[_ce_page];
+ c3_z off_z = _ce_len(pag_w);
+
+ if ( _ce_page != (ret_zs = read(pat_u->mem_i, buf_y, _ce_page)) ) {
+ if ( 0 < ret_zs ) {
+ fprintf(stderr, "loom: patch apply partial read: %"PRIc3_zs"\r\n",
+ ret_zs);
+ }
+ else {
+ fprintf(stderr, "loom: patch apply read: %s\r\n", strerror(errno));
+ }
+ u3_assert(0);
+ }
+ else {
+ if ( _ce_page !=
+ (ret_zs = pwrite(fid_i, buf_y, _ce_page, off_z)) )
+ {
+ if ( 0 < ret_zs ) {
+ fprintf(stderr, "loom: patch apply partial write: %"PRIc3_zs"\r\n",
+ ret_zs);
+ }
+ else {
+ fprintf(stderr, "loom: patch apply write: %s\r\n", strerror(errno));
+ }
+ fprintf(stderr, "info: you probably have insufficient disk space");
+ u3_assert(0);
+ }
+ }
+#if 0
+ u3l_log("apply: %d, %x", pag_w, _ce_muk_page(buf_y));
+#endif
+ }
+}
+
+/* _ce_loom_track_sane(): quiescent page state invariants.
+*/
+static c3_o
+_ce_loom_track_sane(void)
+{
+ c3_w blk_w, bit_w, max_w, i_w = 0;
+ c3_o san_o = c3y;
+
+ max_w = u3P.img_u.pgs_w;
+
+ for ( ; i_w < max_w; i_w++ ) {
+ blk_w = i_w >> 5;
+ bit_w = i_w & 31;
+
+ if ( u3P.dit_w[blk_w] & ((c3_w)1 << bit_w) ) {
+ fprintf(stderr, "loom: insane image %u\r\n", i_w);
+ san_o = c3n;
+ }
+ }
+
+ max_w = u3P.pag_w;
+
+ for ( ; i_w < max_w; i_w++ ) {
+ blk_w = i_w >> 5;
+ bit_w = i_w & 31;
+
+ if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w)) ) {
+ fprintf(stderr, "loom: insane open %u\r\n", i_w);
+ san_o = c3n;
+ }
+ }
+
+ return san_o;
+}
+
+/* _ce_loom_track(): [pgs_w] clean, followed by [dif_w] dirty.
+*/
+void
+_ce_loom_track(c3_w pgs_w, c3_w dif_w)
+{
+ c3_w blk_w, bit_w, i_w = 0, max_w = pgs_w;
+
+ for ( ; i_w < max_w; i_w++ ) {
+ blk_w = i_w >> 5;
+ bit_w = i_w & 31;
+ u3P.dit_w[blk_w] &= ~((c3_w)1 << bit_w);
+ }
+
+ max_w += dif_w;
+
+ for ( ; i_w < max_w; i_w++ ) {
+ blk_w = i_w >> 5;
+ bit_w = i_w & 31;
+ u3P.dit_w[blk_w] |= ((c3_w)1 << bit_w);
+ }
+}
+
+/* _ce_loom_protect(): protect/track pages from the bottom of memory.
+*/
+static void
+_ce_loom_protect(c3_w pgs_w, c3_w old_w)
+{
+ c3_w dif_w = 0;
+
+ if ( pgs_w ) {
+ if ( 0 != mprotect(_ce_ptr(0), _ce_len(pgs_w), PROT_READ) ) {
+ fprintf(stderr, "loom: pure (%u pages): %s\r\n",
+ pgs_w, strerror(errno));
+ u3_assert(0);
+ }
+ }
+
+ if ( old_w > pgs_w ) {
+ dif_w = old_w - pgs_w;
+
+ if ( 0 != mprotect(_ce_ptr(pgs_w),
+ _ce_len(dif_w),
+ (PROT_READ | PROT_WRITE)) )
+ {
+ fprintf(stderr, "loom: foul (%u pages, %u old): %s\r\n",
+ pgs_w, old_w, strerror(errno));
+ u3_assert(0);
+ }
+
+#ifdef U3_GUARD_PAGE
+ // protect guard page if clobbered
+ //
+ // NB: < pgs_w is precluded by assertion in u3e_save()
+ //
+ if ( u3P.gar_w < old_w ) {
+ fprintf(stderr, "loom: guard on reprotect\r\n");
+ u3_assert( !_ce_ward_protect() );
+ }
+#endif
+ }
+
+ _ce_loom_track(pgs_w, dif_w);
+}
+
+/* _ce_loom_mapf_ephemeral(): map entire loom into ephemeral file
+*/
+static void
+_ce_loom_mapf_ephemeral(void)
+{
+ if ( MAP_FAILED == mmap(_ce_ptr(0),
+ _ce_len(u3P.pag_w),
+ (PROT_READ | PROT_WRITE),
+ (MAP_FIXED | MAP_SHARED),
+ u3P.eph_i, 0) )
+ {
+ fprintf(stderr, "loom: initial ephemeral mmap failed (%u pages): %s\r\n",
+ u3P.pag_w, strerror(errno));
+ u3_assert(0);
+ }
+}
+
+/* _ce_loom_mapf(): map [pgs_w] of [fid_i] into the bottom of memory
+** (and ephemeralize [old_w - pgs_w] after if needed).
+*/
+static void
+_ce_loom_mapf(c3_i fid_i, c3_w pgs_w, c3_w old_w)
+{
+ c3_w dif_w = 0;
+
+ if ( pgs_w ) {
+ if ( MAP_FAILED == mmap(_ce_ptr(0),
+ _ce_len(pgs_w),
+ PROT_READ,
+ (MAP_FIXED | MAP_PRIVATE),
+ fid_i, 0) )
+ {
+ fprintf(stderr, "loom: file-backed mmap failed (%u pages): %s\r\n",
+ pgs_w, strerror(errno));
+ u3_assert(0);
+ }
+ }
+
+ if ( old_w > pgs_w ) {
+ dif_w = old_w - pgs_w;
+
+ if ( u3C.wag_w & u3o_swap ) {
+ if ( MAP_FAILED == mmap(_ce_ptr(pgs_w),
+ _ce_len(dif_w),
+ (PROT_READ | PROT_WRITE),
+ (MAP_FIXED | MAP_SHARED),
+ u3P.eph_i, _ce_len(pgs_w)) )
+ {
+ fprintf(stderr, "loom: ephemeral mmap failed (%u pages, %u old): %s\r\n",
+ pgs_w, old_w, strerror(errno));
+ u3_assert(0);
+ }
+ }
+ else {
+ if ( MAP_FAILED == mmap(_ce_ptr(pgs_w),
+ _ce_len(dif_w),
+ (PROT_READ | PROT_WRITE),
+ (MAP_ANON | MAP_FIXED | MAP_PRIVATE),
+ -1, 0) )
+ {
+ fprintf(stderr, "loom: anonymous mmap failed (%u pages, %u old): %s\r\n",
+ pgs_w, old_w, strerror(errno));
+ u3_assert(0);
+ }
+ }
+
+#ifdef U3_GUARD_PAGE
+ // protect guard page if clobbered
+ //
+ // NB: < pgs_w is precluded by assertion in u3e_save()
+ //
+ if ( u3P.gar_w < old_w ) {
+ fprintf(stderr, "loom: guard on remap\r\n");
+ u3_assert( !_ce_ward_protect() );
+ }
+#endif
+ }
+
+ _ce_loom_track(pgs_w, dif_w);
+}
+
+/* _ce_loom_blit(): apply pages, in order, from the bottom of memory.
+*/
+static void
+_ce_loom_blit(c3_i fid_i, c3_w pgs_w)
+{
+ c3_w i_w;
+ void* ptr_v;
+ c3_zs ret_zs;
+
+ for ( i_w = 0; i_w < pgs_w; i_w++ ) {
+ ptr_v = _ce_ptr(i_w);
+
+ if ( _ce_page != (ret_zs = pread(fid_i, ptr_v, _ce_page, _ce_len(i_w))) ) {
+ if ( 0 < ret_zs ) {
+ fprintf(stderr, "loom: blit partial read: %"PRIc3_zs"\r\n",
+ ret_zs);
+ }
+ else {
+ fprintf(stderr, "loom: blit read %s\r\n", strerror(errno));
+ }
+ u3_assert(0);
+ }
+ }
+
+ _ce_loom_protect(pgs_w, 0);
+}
+
+#ifdef U3_SNAPSHOT_VALIDATION
+/* _ce_page_fine(): compare page in memory and on disk.
+*/
+static c3_o
+_ce_page_fine(u3e_image* img_u, c3_w pag_w, c3_z off_z)
+{
+ ssize_t ret_i;
+ c3_y buf_y[_ce_page];
+
+ if ( _ce_page !=
+ (ret_i = pread(img_u->fid_i, buf_y, _ce_page, off_z)) )
+ {
+ if ( 0 < ret_i ) {
+ fprintf(stderr, "loom: image fine partial read: %zu\r\n", (size_t)ret_i);
+ }
+ else {
+ fprintf(stderr, "loom: image fine read: %s\r\n", strerror(errno));
+ }
+ u3_assert(0);
+ }
+
+ {
+ c3_w mas_w = _ce_muk_page(_ce_ptr(pag_w));
+ c3_w fas_w = _ce_muk_page(buf_y);
+
+ if ( mas_w != fas_w ) {
+ fprintf(stderr, "loom: image checksum mismatch: "
+ "page %d, mem_w %x, fil_w %x\r\n",
+ pag_w, mas_w, fas_w);
+ return c3n;
+ }
+ }
+
+ return c3y;
+}
+
+/* _ce_loom_fine(): compare clean pages in memory and on disk.
+*/
+static c3_o
+_ce_loom_fine(void)
+{
+ c3_w off_w = u3R->rut_p >> u3a_page;
+ c3_w blk_w, bit_w, pag_w, i_w;
+ c3_o fin_o = c3y;
+
+ for ( i_w = 0; i_w < u3P.img_u.pgs_w; i_w++ ) {
+ pag_w = i_w;
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+
+ if ( !(u3P.dit_w[blk_w] & ((c3_w)1 << bit_w))
+ && ( (pag_w < off_w)
+ || (u3R->hep.len_w <= (pag_w - off_w))
+ || (u3a_free_pg != (u3to(u3_post, u3R->hep.pag_p))[pag_w - off_w]) ) )
+ {
+ fin_o = c3a(fin_o, _ce_page_fine(&u3P.img_u, pag_w, _ce_len(pag_w)));
+ }
+ }
+
+ return fin_o;
+}
+#endif
+
+/* _ce_image_copy(): copy all of [fom_u] to [tou_u]
+*/
+static c3_o
+_ce_image_copy(u3e_image* fom_u, u3e_image* tou_u)
+{
+ ssize_t ret_i;
+ c3_w i_w;
+
+ // resize images
+ //
+ _ce_image_resize(tou_u, fom_u->pgs_w);
+
+ // seek to begining of patch and images
+ //
+ if ( (-1 == lseek(fom_u->fid_i, 0, SEEK_SET))
+ || (-1 == lseek(tou_u->fid_i, 0, SEEK_SET)) )
+ {
+ fprintf(stderr, "loom: image copy seek: %s\r\n", strerror(errno));
+ return c3n;
+ }
+
+ // copy pages into destination image
+ //
+ for ( i_w = 0; i_w < fom_u->pgs_w; i_w++ ) {
+ c3_y buf_y[_ce_page];
+ c3_w off_w = i_w;
+
+ if ( _ce_page != (ret_i = read(fom_u->fid_i, buf_y, _ce_page)) ) {
+ if ( 0 < ret_i ) {
+ fprintf(stderr, "loom: image copy partial read: %zu\r\n",
+ (size_t)ret_i);
+ }
+ else {
+ fprintf(stderr, "loom: image copy read: %s\r\n",
+ strerror(errno));
+ }
+ return c3n;
+ }
+ else {
+ if ( -1 == lseek(tou_u->fid_i, _ce_len(off_w), SEEK_SET) ) {
+ fprintf(stderr, "loom: image copy seek: %s\r\n", strerror(errno));
+ return c3n;
+ }
+ if ( _ce_page != (ret_i = write(tou_u->fid_i, buf_y, _ce_page)) ) {
+ if ( 0 < ret_i ) {
+ fprintf(stderr, "loom: image copy partial write: %zu\r\n",
+ (size_t)ret_i);
+ }
+ else {
+ fprintf(stderr, "loom: image copy write: %s\r\n", strerror(errno));
+ }
+ fprintf(stderr, "info: you probably have insufficient disk space");
+ return c3n;
+ }
+ }
+ }
+
+ return c3y;
+}
+
+/* u3e_backup(): copy snapshot from [pux_c] to [pax_c],
+ * overwriting optionally. note that image files must
+ * be named "image".
+*/
+c3_o
+u3e_backup(c3_c* pux_c, c3_c* pax_c, c3_o ovw_o)
+{
+ // source image file from [pux_c]
+ u3e_image nux_u = { .nam_c = "image", .pgs_w = 0 };
+
+ // destination image file to [pax_c]
+ u3e_image nax_u = { .nam_c = "image", .pgs_w = 0 };
+
+ c3_i mod_i = O_RDWR | O_CREAT;
+
+ if ( !pux_c || !pax_c ) {
+ fprintf(stderr, "loom: image backup: bad path\r\n");
+ return c3n;
+ }
+
+ if ( (c3n == ovw_o) && c3_mkdir(pax_c, 0700) ) {
+ if ( EEXIST != errno ) {
+ fprintf(stderr, "loom: image backup: %s\r\n", strerror(errno));
+ }
+ return c3n;
+ }
+
+ // open source image files if they exist
+ //
+ c3_c nux_c[8193];
+ snprintf(nux_c, 8192, "%s/%s.bin", pux_c, nux_u.nam_c);
+ if ( (0 != access(nux_c, F_OK))
+ || (_ce_img_good != _ce_image_open(&nux_u, pux_c)) )
+ {
+ fprintf(stderr, "loom: couldn't open image at %s\r\n", pux_c);
+ return c3n;
+ }
+
+ // open destination image files
+ c3_c nax_c[8193];
+ snprintf(nax_c, 8192, "%s/%s.bin", pax_c, nax_u.nam_c);
+ if ( -1 == (nax_u.fid_i = c3_open(nax_c, mod_i, 0666)) ) {
+ fprintf(stderr, "loom: c3_open %s: %s\r\n", nax_c, strerror(errno));
+ return c3n;
+ }
+
+ if ( (c3n == _ce_image_copy(&nux_u, &nax_u))
+ || (c3n == _ce_image_sync(&nax_u)) )
+ {
+ c3_unlink(nax_c);
+ fprintf(stderr, "loom: image backup failed\r\n");
+ return c3n;
+ }
+
+ close(nax_u.fid_i);
+ fprintf(stderr, "loom: image backup complete\r\n");
+ return c3y;
+}
+
+/*
+ u3e_save(): save current changes.
+
+ If we are in dry-run mode, do nothing.
+
+ First, call `_ce_patch_compose` to write all dirty pages to disk and
+ clear protection and dirty bits. If there were no dirty pages to write,
+ then we're done.
+
+ - Sync the patch files to disk.
+ - Verify the patch (because why not?)
+ - Write the patch data into the image file (This is idempotent.).
+ - Sync the image file.
+ - Delete the patchfile and free it.
+
+ Once we've written the dirty pages to disk (and have reset their dirty bits
+ and protection flags), we *could* handle the rest of the checkpointing
+ process in a separate thread, but we'd need to wait until that finishes
+ before we try to make another snapshot.
+*/
+void
+u3e_save(u3_post low_p, u3_post hig_p)
+{
+ u3_ce_patch* pat_u;
+ c3_w old_w = u3P.img_u.pgs_w;
+
+ if ( u3C.wag_w & u3o_dryrun ) {
+ return;
+ }
+
+ // XX discard hig_p and friends
+ {
+ c3_w nop_w = (low_p >> u3a_page);
+ c3_w nor_w = (low_p + (_ce_len_words(1) - 1)) >> u3a_page;
+ c3_w sop_w = hig_p >> u3a_page;
+
+ u3_assert( (u3P.gar_w > nop_w) && (u3P.gar_w < sop_w) );
+
+ if ( !(pat_u = _ce_patch_compose(nor_w)) ) {
+ return;
+ }
+ }
+
+ if ( u3C.wag_w & u3o_verbose ) {
+ fprintf(stderr, "sync: skipped %u free", pat_u->sip_w);
+ u3a_print_memory(stderr, " pages", pat_u->sip_w << u3a_page);
+ }
+
+ // attempt to avoid propagating anything insane to disk
+ //
+ u3a_loom_sane();
+
+ if ( u3C.wag_w & u3o_verbose ) {
+ u3a_print_memory(stderr, "sync: save", pat_u->con_u->pgs_w << u3a_page);
+ }
+
+ _ce_patch_sync(pat_u);
+
+ if ( c3n == _ce_patch_verify(pat_u) ) {
+ u3_assert(!"loom: save failed");
+ }
+
+#ifdef U3_SNAPSHOT_VALIDATION
+ // check that clean pages are correct
+ //
+ u3_assert( c3y == _ce_loom_fine() );
+#endif
+
+ _ce_patch_apply(pat_u);
+
+ u3_assert( c3y == _ce_image_sync(&u3P.img_u) );
+
+ _ce_patch_free(pat_u);
+ _ce_patch_delete();
+
+#ifdef U3_SNAPSHOT_VALIDATION
+ {
+ c3_w pgs_w;
+ u3_assert( _ce_img_good == _ce_image_stat(&u3P.img_u, &pgs_w) );
+ u3_assert( pgs_w == u3P.img_u.pgs_w );
+ }
+
+ // check that all pages in the image are clean and *fine*,
+ // all others are dirty
+ //
+ // since total finery requires total cleanliness,
+ // pages of the image are protected twice.
+ //
+ _ce_loom_protect(u3P.img_u.pgs_w, old_w);
+
+ u3_assert( c3y == _ce_loom_track_sane() );
+ u3_assert( c3y == _ce_loom_fine() );
+#endif
+
+ if ( u3C.wag_w & u3o_no_demand ) {
+#ifndef U3_SNAPSHOT_VALIDATION
+ _ce_loom_protect(u3P.img_u.pgs_w, old_w);
+#endif
+ }
+ else {
+ _ce_loom_mapf(u3P.img_u.fid_i, u3P.img_u.pgs_w, old_w);
+ }
+
+ u3e_toss(low_p, hig_p);
+}
+
+/* _ce_toss_pages(): discard ephemeral pages.
+*/
+static void
+_ce_toss_pages(c3_w nor_w, c3_w sou_w)
+{
+ c3_w pgs_w = u3P.pag_w - (nor_w + sou_w);
+ void* ptr_v = _ce_ptr(nor_w);
+
+ #ifndef U3_OS_windows
+ if ( -1 == madvise(ptr_v, _ce_len(pgs_w), MADV_DONTNEED) ) {
+ fprintf(stderr, "loom: madv_dontneed failed (%u pages at %u): %s\r\n",
+ pgs_w, nor_w, strerror(errno));
+ }
+ #endif
+}
+
+/* u3e_toss(): discard ephemeral pages.
+*/
+void
+u3e_toss(u3_post low_p, u3_post hig_p)
+{
+ c3_w nor_w = (low_p + (_ce_len_words(1) - 1)) >> u3a_page;
+ c3_w sou_w = u3P.pag_w - (hig_p >> u3a_page);
+
+ _ce_toss_pages(nor_w, sou_w);
+}
+
+/* u3e_live(): start the checkpointing system.
+*/
+c3_o
+u3e_live(c3_o nuu_o, c3_c* dir_c)
+{
+ // require that our page size is a multiple of the system page size.
+ //
+ {
+ size_t sys_i = sysconf(_SC_PAGESIZE);
+
+ if ( _ce_page % sys_i ) {
+ fprintf(stderr, "loom: incompatible system page size (%zuKB)\r\n",
+ sys_i >> 10);
+ exit(1);
+ }
+ }
+
+ u3P.dir_c = dir_c;
+ u3P.eph_i = 0;
+ u3P.img_u.nam_c = "image";
+ u3P.pag_w = u3C.wor_i >> u3a_page;
+
+ // XX review dryrun requirements, enable or remove
+ //
+#if 0
+ if ( u3C.wag_w & u3o_dryrun ) {
+ return c3y;
+ } else
+#endif
+ {
+ // Open the ephemeral space file.
+ //
+ if ( u3C.wag_w & u3o_swap ) {
+ if ( c3n == _ce_ephemeral_open(&u3P.eph_i) ) {
+ fprintf(stderr, "boot: failed to load ephemeral file\r\n");
+ exit(1);
+ }
+ }
+
+ // Open image files.
+ //
+ c3_c chk_c[8193];
+ snprintf(chk_c, 8193, "%s/.urb/chk", u3P.dir_c);
+
+ _ce_img_stat sat_e = _ce_image_open(&u3P.img_u, chk_c);
+
+ if ( _ce_img_fail == sat_e ) {
+ fprintf(stderr, "boot: image failed\r\n");
+ exit(1);
+ }
+ else {
+ u3_ce_patch* pat_u;
+
+ /* Load any patch files; apply them to images.
+ */
+ if ( 0 != (pat_u = _ce_patch_open()) ) {
+ _ce_patch_apply(pat_u);
+ u3_assert( c3y == _ce_image_sync(&u3P.img_u) );
+ _ce_patch_free(pat_u);
+ _ce_patch_delete();
+ }
+ else if ( _ce_img_size == sat_e ) {
+ fprintf(stderr, "boot: image failed (size)\r\n");
+ exit(1);
+ }
+
+ // detect snapshots from a larger loom
+ //
+ if ( (u3P.img_u.pgs_w + 1) >= u3P.pag_w ) { // XX?
+ fprintf(stderr, "boot: snapshot too big for loom\r\n");
+ exit(1);
+ }
+
+ // mark all pages dirty (pages in the snapshot will be marked clean)
+ //
+ u3e_foul();
+
+ /* Write image files to memory; reinstate protection.
+ */
+ {
+ if ( u3C.wag_w & u3o_swap ) {
+ _ce_loom_mapf_ephemeral();
+ }
+
+ if ( u3C.wag_w & u3o_no_demand ) {
+ _ce_loom_blit(u3P.img_u.fid_i, u3P.img_u.pgs_w);
+ }
+ else {
+ _ce_loom_mapf(u3P.img_u.fid_i, u3P.img_u.pgs_w, 0);
+ }
+
+ u3l_log("boot: protected loom");
+ }
+
+ /* If the images were empty, we are logically booting.
+ */
+ if ( !u3P.img_u.pgs_w ) {
+ u3l_log("live: logical boot");
+ nuu_o = c3y;
+ }
+ else if ( u3C.wag_w & u3o_no_demand ) {
+ u3a_print_memory(stderr, "live: loaded", _ce_len_words(u3P.img_u.pgs_w));
+ }
+ else {
+ u3a_print_memory(stderr, "live: mapped", _ce_len_words(u3P.img_u.pgs_w));
+ }
+
+#ifdef U3_GUARD_PAGE
+ u3_assert( !_ce_ward_post(u3P.img_u.pgs_w, u3P.pag_w) );
+#endif
+ }
+ }
+
+ return nuu_o;
+}
+
+/* u3e_stop(): gracefully stop the persistence system.
+*/
+void
+u3e_stop(void)
+{
+ if ( u3P.eph_i ) {
+ _ce_toss_pages(u3P.img_u.pgs_w, u3P.pag_w);
+ close(u3P.eph_i);
+ unlink(u3C.eph_c);
+ }
+
+ close(u3P.img_u.fid_i);
+}
+
+/* u3e_yolo(): disable dirty page tracking, read/write whole loom.
+*/
+c3_o
+u3e_yolo(void)
+{
+ // NB: u3e_save() will reinstate protection flags
+ //
+ if ( 0 != mprotect(_ce_ptr(0),
+ _ce_len(u3P.pag_w),
+ (PROT_READ | PROT_WRITE)) )
+ {
+ // XX confirm recoverable errors
+ //
+ fprintf(stderr, "loom: yolo: %s\r\n", strerror(errno));
+ return c3n;
+ }
+
+ u3_assert( !_ce_ward_protect() );
+
+ return c3y;
+}
+
+/* u3e_foul(): dirty all the pages of the loom.
+*/
+void
+u3e_foul(void)
+{
+ memset((void*)u3P.dit_w, 0xff, sizeof(u3P.dit_w));
+}
+
+/* u3e_init(): initialize guard page tracking, dirty loom
+*/
+void
+u3e_init(void)
+{
+ u3P.pag_w = u3C.wor_i >> u3a_page;
+
+ u3P.img_u.fid_i = -1;
+
+ u3e_foul();
+
+#ifdef U3_GUARD_PAGE
+ u3_assert( !_ce_ward_post(0, u3P.pag_w) );
+#endif
+}
+
+/* u3e_ward(): reposition guard page if needed.
+*/
+void
+u3e_ward(u3_post low_p, u3_post hig_p)
+{
+#ifdef U3_GUARD_PAGE
+ c3_w nop_w = low_p >> u3a_page;
+ c3_w sop_w = hig_p >> u3a_page;
+ c3_w pag_w = u3P.gar_w;
+
+ if ( !((pag_w > nop_w) && (pag_w < sop_w)) ) {
+ u3_assert( !_ce_ward_post(nop_w, sop_w) );
+ u3_assert( !_ce_flaw_mprotect(pag_w) );
+ u3_assert( u3P.dit_w[pag_w >> 5] & ((c3_w)1 << (pag_w & 31)) );
+ }
+#endif
+}
diff --git a/vere/pkg/noun/events.h b/vere/pkg/noun/events.h
new file mode 100644
index 0000000..d9cdb50
--- /dev/null
+++ b/vere/pkg/noun/events.h
@@ -0,0 +1,131 @@
+/// @file
+
+#ifndef U3_EVENTS_H
+#define U3_EVENTS_H
+
+#include "c3/c3.h"
+#include "allocate.h"
+#include "version.h"
+
+ /** Data structures.
+ **/
+ /* u3e_line: control line.
+ */
+ typedef struct _u3e_line {
+ c3_w pag_w;
+ c3_w has_w;
+ } u3e_line;
+
+ /* u3e_control: memory change, control file.
+ */
+ typedef struct _u3e_control {
+ u3e_version ver_w; // version number
+ c3_w has_w; // control checksum
+ c3_w tot_w; // new page count
+ c3_w pgs_w; // number of changed pages
+ u3e_line mem_u[]; // per page
+ } u3e_control;
+
+ /* u3_cs_patch: memory change, top level.
+ */
+ typedef struct _u3_cs_patch {
+ c3_i ctl_i;
+ c3_i mem_i;
+ c3_w sip_w;
+ u3e_control* con_u;
+ } u3_ce_patch;
+
+ /* u3e_image: memory segment, open file.
+ */
+ typedef struct _u3e_image {
+ c3_c* nam_c; // segment name
+ c3_i fid_i; // open file, or 0
+ c3_w pgs_w; // length in pages
+ } u3e_image;
+
+ /* u3e_pool: entire memory system.
+ */
+ typedef struct _u3e_pool {
+ c3_c* dir_c; // path to
+ c3_i eph_i; // ephemeral file descriptor
+ c3_w dit_w[u3a_pages >> 5]; // touched since last save
+ c3_w pag_w; // number of pages (<= u3a_pages)
+ c3_w gar_w; // guard page
+ u3e_image img_u; // image
+ } u3e_pool;
+
+ /* u3e_flaw: loom fault result.
+ */
+ typedef enum {
+ u3e_flaw_sham = 0, // bogus state
+ u3e_flaw_base = 1, // vm fail (mprotect)
+ u3e_flaw_meme = 2, // bail:meme
+ u3e_flaw_good = 3 // handled
+ } u3e_flaw;
+
+ /** Globals.
+ **/
+ /// Snapshotting system.
+ extern u3e_pool u3e_Pool;
+# define u3P u3e_Pool
+
+ /** Constants.
+ **/
+
+ /** Functions.
+ **/
+ /* u3e_backup(): copy the snapshot from [pux_c] to [pax_c],
+ * overwriting optional.
+ */
+ c3_o
+ u3e_backup(c3_c* pux_c, c3_c* pax_c, c3_o ovw_o);
+
+ /* u3e_fault(): handle a memory fault.
+ */
+ u3e_flaw
+ u3e_fault(u3_post low_p, u3_post hig_p, u3_post off_p);
+
+ /* u3e_save(): update the checkpoint.
+ */
+ void
+ u3e_save(u3_post low_p, u3_post hig_p);
+
+ /* u3e_toss(): discard ephemeral pages.
+ */
+ void
+ u3e_toss(u3_post low_p, u3_post hig_p);
+
+ /* u3e_live(): start the persistence system. Return c3y if no image.
+ */
+ c3_o
+ u3e_live(c3_o nuu_o, c3_c* dir_c);
+
+ /* u3e_stop(): gracefully stop the persistence system.
+ */
+ void
+ u3e_stop(void);
+
+ /* u3e_yolo(): disable dirty page tracking, read/write whole loom.
+ */
+ c3_o
+ u3e_yolo(void);
+
+ /* u3e_foul(): dirty all the pages of the loom.
+ */
+ void
+ u3e_foul(void);
+
+ /* u3e_init(): initialize guard page tracking.
+ */
+ void
+ u3e_init(void);
+
+ /* u3e_ward(): reposition guard page if needed.
+ */
+ void
+ u3e_ward(u3_post low_p, u3_post hig_p);
+
+ c3_i
+ u3e_image_open_any(c3_c* nam_c, c3_c* dir_c, c3_z* len_z);
+
+#endif /* ifndef U3_EVENTS_H */
diff --git a/vere/pkg/noun/hashtable.c b/vere/pkg/noun/hashtable.c
new file mode 100644
index 0000000..6b1fb39
--- /dev/null
+++ b/vere/pkg/noun/hashtable.c
@@ -0,0 +1,1408 @@
+/// @file
+
+#include "hashtable.h"
+
+#include "allocate.h"
+#include "imprison.h"
+#include "retrieve.h"
+#include "xtract.h"
+
+/* CUT_END(): extract [b_w] low bits from [a_w]
+*/
+#define CUT_END(a_w, b_w) ((a_w) & (((c3_w)1 << (b_w)) - 1))
+
+/* BIT_SET(): [1] if bit [b_w] is set in [a_w]
+*/
+#define BIT_SET(a_w, b_w) ((a_w) & ((c3_w)1 << (b_w)))
+
+static u3_weak
+_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w);
+
+static u3_weak
+_ch_trim_root(u3h_root* har_u);
+
+c3_w
+_ch_skip_slot(c3_w mug_w, c3_w lef_w);
+
+/* u3h_new_cache(): create hashtable with bounded size.
+*/
+u3p(u3h_root)
+u3h_new_cache(c3_w max_w)
+{
+ u3h_root* har_u = u3a_walloc(c3_wiseof(u3h_root));
+ u3p(u3h_root) har_p = u3of(u3h_root, har_u);
+ c3_w i_w;
+
+ har_u->max_w = max_w;
+ har_u->use_w = 0;
+ har_u->arm_u.mug_w = 0;
+ har_u->arm_u.inx_w = 0;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ har_u->sot_w[i_w] = 0;
+ }
+ return har_p;
+}
+
+/* u3h_new(): create hashtable.
+*/
+u3p(u3h_root)
+u3h_new(void)
+{
+ return u3h_new_cache(0);
+}
+
+/* _ch_popcount(): number of bits set in word. A standard intrinsic.
+*/
+static c3_w
+_ch_popcount(c3_w num_w)
+{
+ return c3_pc_w(num_w);
+}
+
+/* _ch_buck_new(): create new bucket.
+*/
+static u3h_buck*
+_ch_buck_new(c3_w len_w)
+{
+ u3h_buck* hab_u = u3a_walloc(c3_wiseof(u3h_buck) +
+ (len_w * c3_wiseof(u3h_slot)));
+ hab_u->len_w = len_w;
+ return hab_u;
+}
+
+/* _ch_node_new(): create new node.
+*/
+static u3h_node*
+_ch_node_new(c3_w len_w)
+{
+ u3h_node* han_u = u3a_walloc(c3_wiseof(u3h_node) +
+ (len_w * c3_wiseof(u3h_slot)));
+ han_u->map_w = 0;
+ return han_u;
+}
+
+static void _ch_slot_put(u3h_slot*, u3_noun, c3_w, c3_w, c3_w*);
+
+/* _ch_node_add(): add to node.
+*/
+static u3h_node*
+_ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w)
+{
+ c3_w bit_w, inx_w, map_w, i_w;
+
+ lef_w -= 5;
+ bit_w = (rem_w >> lef_w);
+ rem_w = CUT_END(rem_w, lef_w);
+ map_w = han_u->map_w;
+ inx_w = _ch_popcount(CUT_END(map_w, bit_w));
+
+ if ( BIT_SET(map_w, bit_w) ) {
+ _ch_slot_put(&(han_u->sot_w[inx_w]), kev, lef_w, rem_w, use_w);
+ return han_u;
+ }
+ else {
+ // nothing was at this slot.
+ // Optimize: use u3a_wealloc.
+ //
+ c3_w len_w = _ch_popcount(map_w);
+ u3h_node* nah_u = _ch_node_new(1 + len_w);
+ nah_u->map_w = han_u->map_w | ((c3_w)1 << bit_w);
+
+ for ( i_w = 0; i_w < inx_w; i_w++ ) {
+ nah_u->sot_w[i_w] = han_u->sot_w[i_w];
+ }
+ nah_u->sot_w[inx_w] = u3h_noun_be_warm(u3h_noun_to_slot(kev));
+ for ( i_w = inx_w; i_w < len_w; i_w++ ) {
+ nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w];
+ }
+
+ u3a_wfree(han_u);
+ *use_w += 1;
+ return nah_u;
+ }
+}
+
+/* ch_buck_add(): add to bucket.
+*/
+static u3h_buck*
+_ch_buck_add(u3h_buck* hab_u, u3_noun kev, c3_w *use_w)
+{
+ c3_w i_w;
+
+ // if our key is equal to any of the existing keys in the bucket,
+ // then replace that key-value pair with kev.
+ //
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]);
+ if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) {
+ hab_u->sot_w[i_w] = u3h_noun_to_slot(kev);
+ u3z(kov);
+ return hab_u;
+ }
+ }
+
+ // create mutant bucket with added key-value pair.
+ // Optimize: use u3a_wealloc().
+ {
+ u3h_buck* bah_u = _ch_buck_new(1 + hab_u->len_w);
+ bah_u->sot_w[0] = u3h_noun_be_warm(u3h_noun_to_slot(kev));
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ bah_u->sot_w[i_w + 1] = hab_u->sot_w[i_w];
+ }
+
+ u3a_wfree(hab_u);
+ *use_w += 1;
+ return bah_u;
+ }
+}
+
+/* _ch_some_add(): add to node or bucket.
+*/
+static void*
+_ch_some_add(void* han_v, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w)
+{
+ if ( 0 == lef_w ) {
+ return _ch_buck_add((u3h_buck*)han_v, kev, use_w);
+ }
+ else return _ch_node_add((u3h_node*)han_v, lef_w, rem_w, kev, use_w);
+}
+
+/* _ch_two(): create a new node with two leaves underneath
+*/
+u3h_slot
+_ch_two(u3h_slot had_w, u3h_slot add_w, c3_w lef_w, c3_w ham_w, c3_w mad_w)
+{
+ void* ret;
+
+ if ( 0 == lef_w ) {
+ u3h_buck* hab_u = _ch_buck_new(2);
+ ret = hab_u;
+ hab_u->sot_w[0] = had_w;
+ hab_u->sot_w[1] = add_w;
+ }
+ else {
+ c3_w hop_w, tad_w;
+ lef_w -= 5;
+ hop_w = ham_w >> lef_w;
+ tad_w = mad_w >> lef_w;
+ if ( hop_w == tad_w ) {
+ // fragments collide: store in a child node.
+ u3h_node* han_u = _ch_node_new(1);
+ ret = han_u;
+ han_u->map_w = (c3_w)1 << hop_w;
+ ham_w = CUT_END(ham_w, lef_w);
+ mad_w = CUT_END(mad_w, lef_w);
+ han_u->sot_w[0] = _ch_two(had_w, add_w, lef_w, ham_w, mad_w);
+ }
+ else {
+ u3h_node* han_u = _ch_node_new(2);
+ ret = han_u;
+ han_u->map_w = ((c3_w)1 << hop_w) | ((c3_w)1 << tad_w);
+ // smaller mug fragments go in earlier slots
+ if ( hop_w < tad_w ) {
+ han_u->sot_w[0] = had_w;
+ han_u->sot_w[1] = add_w;
+ }
+ else {
+ han_u->sot_w[0] = add_w;
+ han_u->sot_w[1] = had_w;
+ }
+ }
+ }
+
+ return u3h_node_to_slot(ret);
+}
+
+/* _ch_slot_put(): store a key-value pair in a non-null slot
+*/
+static void
+_ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w)
+{
+ if ( c3n == u3h_slot_is_noun(*sot_w) ) {
+ void* hav_v = _ch_some_add(u3h_slot_to_node(*sot_w),
+ lef_w,
+ rem_w,
+ kev,
+ use_w);
+
+ u3_assert( c3y == u3h_slot_is_node(*sot_w) );
+ *sot_w = u3h_node_to_slot(hav_v);
+ }
+ else {
+ u3_noun kov = u3h_slot_to_noun(*sot_w);
+ u3h_slot add_w = u3h_noun_be_warm(u3h_noun_to_slot(kev));
+ if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) {
+ // replace old value
+ u3z(kov);
+ *sot_w = add_w;
+ }
+ else {
+ c3_w ham_w = CUT_END(u3r_mug(u3h(kov)), lef_w);
+ *sot_w = _ch_two(*sot_w, add_w, lef_w, ham_w, rem_w);
+ *use_w += 1;
+ }
+ }
+}
+
+/* u3h_put_get(): insert in caching hashtable, returning deleted key-value pair
+**
+** `key` is RETAINED; `val` is transferred.
+*/
+u3_weak
+u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ u3_noun kev = u3nc(u3k(key), val);
+ c3_w mug_w = u3r_mug(key);
+ c3_w inx_w = (mug_w >> 25); // 6 bits
+ c3_w rem_w = CUT_END(mug_w, 25);
+ u3h_slot* sot_w = &(har_u->sot_w[inx_w]);
+
+ if ( c3y == u3h_slot_is_null(*sot_w) ) {
+ *sot_w = u3h_noun_be_warm(u3h_noun_to_slot(kev));
+ har_u->use_w += 1;
+ }
+ else {
+ _ch_slot_put(sot_w, kev, 25, rem_w, &(har_u->use_w));
+ }
+
+ {
+ u3_weak ret = u3_none;
+
+ if ( har_u->max_w && (har_u->use_w > har_u->max_w) ) {
+ do {
+ ret = _ch_trim_root(har_u);
+ }
+ while ( u3_none == ret );
+ har_u->use_w -= 1;
+ }
+
+ return ret;
+ }
+}
+
+/* u3h_put(): insert in hashtable.
+**
+** `key` is RETAINED; `val` is transferred.
+*/
+void
+u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val)
+{
+ u3_weak del = u3h_put_get(har_p, key, val);
+ if ( u3_none != del ) {
+ u3z(del);
+ }
+}
+
+/* _ch_buck_del(): delete from bucket
+*/
+static c3_o
+_ch_buck_del(u3h_slot* sot_w, u3_noun key)
+{
+ u3h_buck* hab_u = u3h_slot_to_node(*sot_w);
+ c3_w fin_w = hab_u->len_w;
+ c3_w i_w;
+ //
+ // find index of key to be deleted
+ //
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]);
+ if ( c3y == u3r_sing(key, u3h(kov)) ) {
+ fin_w = i_w;
+ u3z(kov);
+ break;
+ }
+ }
+
+ // no key found, no-op
+ if ( fin_w == hab_u->len_w ) {
+ return c3n;
+ }
+
+ {
+ hab_u->len_w--;
+ // u3_assert(c3y == u3h_slot_is_noun(hab_u->sot_w[fin_w]));
+ for ( i_w = fin_w; i_w < hab_u->len_w; i_w++ ) {
+ hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1];
+ }
+
+ return c3y;
+ }
+}
+
+static c3_o _ch_some_del(u3h_slot*, u3_noun, c3_w, c3_w);
+
+/* _ch_slot_del(): delete from slot
+*/
+static c3_o
+_ch_slot_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
+{
+ if ( c3y == u3h_slot_is_noun(*sot_w) ) {
+ u3_noun kev = u3h_slot_to_noun(*sot_w);
+ *sot_w = 0;
+ u3z(kev);
+ return c3y;
+ }
+ else {
+ return _ch_some_del(sot_w, key, lef_w, rem_w);
+ }
+}
+
+/* _ch_slot_del(): delete from node
+*/
+static c3_o
+_ch_node_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
+{
+ u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w);
+ u3h_slot* tos_w;
+
+ c3_w bit_w, inx_w, map_w, i_w;
+
+ lef_w -= 5;
+ bit_w = (rem_w >> lef_w);
+ rem_w = CUT_END(rem_w, lef_w);
+ map_w = han_u->map_w;
+ inx_w = _ch_popcount(CUT_END(map_w, bit_w));
+
+ tos_w = &(han_u->sot_w[inx_w]);
+
+ // nothing at slot, no-op
+ if ( !BIT_SET(map_w, bit_w) ) {
+ return c3n;
+ }
+
+ if ( c3n == _ch_slot_del(tos_w, key, lef_w, rem_w) ) {
+ // nothing deleted
+ return c3n;
+ }
+ else if ( 0 != *tos_w ) {
+ // something deleted, but slot still has value
+ return c3y;
+ }
+ else {
+ // shrink!
+ c3_w i_w, ken_w, len_w = _ch_popcount(map_w);
+ u3h_slot kes_w;
+
+ if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0),
+ (kes_w = han_u->sot_w[ken_w]),
+ (c3y == u3h_slot_is_noun(kes_w))) )
+ {
+ // only one side left, and the other is a noun. debucketize.
+ *sot_w = kes_w;
+ u3a_wfree(han_u);
+ }
+ else {
+ // shrink node in place; don't reallocate, we could be low on memory
+ //
+ han_u->map_w &= ~(1 << bit_w);
+ --len_w;
+
+ for ( i_w = inx_w; i_w < len_w; i_w++ ) {
+ han_u->sot_w[i_w] = han_u->sot_w[i_w + 1];
+ }
+ }
+ return c3y;
+ }
+}
+
+/* _ch_some_del(): delete from node or buck
+*/
+static c3_o
+_ch_some_del(u3h_slot* sot_w, u3_noun key, c3_w lef_w, c3_w rem_w)
+{
+ if ( 0 == lef_w ) {
+ return _ch_buck_del(sot_w, key);
+ }
+
+ return _ch_node_del(sot_w, key, lef_w, rem_w);
+}
+
+/* u3h_del(); delete from hashtable.
+*/
+void
+u3h_del(u3p(u3h_root) har_p, u3_noun key)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w mug_w = u3r_mug(key);
+ c3_w inx_w = (mug_w >> 25);
+ c3_w rem_w = CUT_END(mug_w, 25);
+ u3h_slot* sot_w = &(har_u->sot_w[inx_w]);
+
+ if ( (c3n == u3h_slot_is_null(*sot_w))
+ && (c3y == _ch_slot_del(sot_w, key, 25, rem_w)) )
+ {
+ har_u->use_w--;
+ }
+}
+
+/* _ch_uni_with(): key/value callback, put into [*wit]
+*/
+static void
+_ch_uni_with(u3_noun kev, void* wit)
+{
+ u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit;
+ u3_noun key, val;
+ u3x_cell(kev, &key, &val);
+
+ u3h_put(har_p, key, u3k(val));
+}
+
+/* u3h_uni(): unify hashtables, copying [rah_p] into [har_p]
+*/
+void
+u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p)
+{
+ u3h_walk_with(rah_p, _ch_uni_with, &har_p);
+}
+
+/* _ch_trim_node(): trim one entry from a node slot or its children
+*/
+static u3_weak
+_ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w)
+{
+ c3_w bit_w, map_w, inx_w;
+ u3h_slot* tos_w;
+ u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w);
+
+ lef_w -= 5;
+ bit_w = (rem_w >> lef_w);
+ map_w = han_u->map_w;
+
+ if ( !BIT_SET(map_w, bit_w) ) {
+ har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w);
+ return c3n;
+ }
+
+ rem_w = CUT_END(rem_w, lef_w);
+ inx_w = _ch_popcount(CUT_END(map_w, bit_w));
+ tos_w = &(han_u->sot_w[inx_w]);
+
+ u3_weak ret = _ch_trim_slot(har_u, tos_w, lef_w, rem_w);
+ if ( (u3_none != ret) && (0 == *tos_w) ) {
+ // shrink!
+ c3_w i_w, ken_w, len_w = _ch_popcount(map_w);
+ u3h_slot kes_w;
+
+ if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0),
+ (kes_w = han_u->sot_w[ken_w]),
+ (c3y == u3h_slot_is_noun(kes_w))) ) {
+ // only one side left, and the other is a noun. debucketize.
+ *sot_w = kes_w;
+ u3a_wfree(han_u);
+ }
+ else {
+ // shrink node in place; don't reallocate, we could be low on memory
+ //
+ han_u->map_w &= ~(1 << bit_w);
+ --len_w;
+
+ for ( i_w = inx_w; i_w < len_w; i_w++ ) {
+ han_u->sot_w[i_w] = han_u->sot_w[i_w + 1];
+ }
+ }
+ }
+ return ret;
+}
+
+/* _ch_trim_kev(): trim a single entry slot
+*/
+static u3_weak
+_ch_trim_kev(u3h_slot *sot_w)
+{
+ if ( _(u3h_slot_is_warm(*sot_w)) ) {
+ *sot_w = u3h_noun_be_cold(*sot_w);
+ return u3_none;
+ }
+ else {
+ u3_noun kev = u3h_slot_to_noun(*sot_w);
+ *sot_w = 0;
+ return kev;
+ }
+}
+
+/* _ch_trim_node(): trim one entry from a bucket slot
+*/
+static u3_weak
+_ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w)
+{
+ c3_w i_w, len_w;
+ u3h_buck* hab_u = u3h_slot_to_node(*sot_w);
+
+ for ( len_w = hab_u->len_w;
+ har_u->arm_u.inx_w < len_w;
+ har_u->arm_u.inx_w += 1 )
+ {
+ u3_weak ret = _ch_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w]));
+ if ( u3_none != ret ) {
+ if ( 2 == len_w ) {
+ // 2 things in bucket: debucketize to key-value pair, the next
+ // run will point at this pair (same mug_w, no longer in bucket)
+ *sot_w = hab_u->sot_w[ (0 == har_u->arm_u.inx_w) ? 1 : 0 ];
+ u3a_wfree(hab_u);
+ har_u->arm_u.inx_w = 0;
+ }
+ else {
+ // shrink bucket in place; don't reallocate, we could be low on memory
+ hab_u->len_w = --len_w;
+
+ for ( i_w = har_u->arm_u.inx_w; i_w < len_w; ++i_w ) {
+ hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1];
+ }
+ // leave the arm pointing at the next index in the bucket
+ ++(har_u->arm_u.inx_w);
+ }
+ return ret;
+ }
+ }
+
+ har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31
+ har_u->arm_u.inx_w = 0;
+ return u3_none;
+}
+
+/* _ch_trim_some(): trim one entry from a bucket or node slot
+*/
+static u3_weak
+_ch_trim_some(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w)
+{
+ if ( 0 == lef_w ) {
+ return _ch_trim_buck(har_u, sot_w);
+ }
+ else {
+ return _ch_trim_node(har_u, sot_w, lef_w, rem_w);
+ }
+}
+
+/* _ch_skip_slot(): increment arm over hash prefix.
+*/
+c3_w
+_ch_skip_slot(c3_w mug_w, c3_w lef_w)
+{
+ c3_w hig_w = mug_w >> lef_w;
+ c3_w new_w = CUT_END(hig_w + 1, (31 - lef_w)); // modulo 2^(31 - lef_w)
+ return new_w << lef_w;
+}
+
+/* _ch_trim_slot(): trim one entry from a non-bucket slot
+*/
+static u3_weak
+_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w)
+{
+ if ( c3y == u3h_slot_is_noun(*sot_w) ) {
+ har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w);
+ return _ch_trim_kev(sot_w);
+ }
+ else {
+ return _ch_trim_some(har_u, sot_w, lef_w, rem_w);
+ }
+}
+
+/* _ch_trim_root(): trim one entry from a hashtable
+*/
+static u3_weak
+_ch_trim_root(u3h_root* har_u)
+{
+ c3_w mug_w = har_u->arm_u.mug_w;
+ c3_w inx_w = mug_w >> 25; // 6 bits
+ u3h_slot* sot_w = &(har_u->sot_w[inx_w]);
+
+ if ( c3y == u3h_slot_is_null(*sot_w) ) {
+ har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, 25);
+ return u3_none;
+ }
+
+ return _ch_trim_slot(har_u, sot_w, 25, CUT_END(mug_w, 25));
+}
+
+/* u3h_trim_to(): trim to n key-value pairs
+*/
+void
+u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w)
+{
+ u3h_trim_with(har_p, n_w, u3a_lose);
+}
+
+/* u3h_trim_to(): trim to n key-value pairs
+*/
+void
+u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun))
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+
+ while ( har_u->use_w > n_w ) {
+ u3_weak del = _ch_trim_root(har_u);
+ if ( u3_none != del ) {
+ har_u->use_w -= 1;
+ del_cb(del);
+ }
+ }
+}
+
+/* _ch_buck_hum(): read in bucket.
+*/
+static c3_o
+_ch_buck_hum(u3h_buck* hab_u, c3_w mug_w)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ if ( mug_w == u3r_mug(u3h(u3h_slot_to_noun(hab_u->sot_w[i_w]))) ) {
+ return c3y;
+ }
+ }
+ return c3n;
+}
+
+/* _ch_node_hum(): read in node.
+*/
+static c3_o
+_ch_node_hum(u3h_node* han_u, c3_w lef_w, c3_w rem_w, c3_w mug_w)
+{
+ c3_w bit_w, map_w;
+
+ lef_w -= 5;
+ bit_w = (rem_w >> lef_w);
+ rem_w = CUT_END(rem_w, lef_w);
+ map_w = han_u->map_w;
+
+ if ( !BIT_SET(map_w, bit_w) ) {
+ return c3n;
+ }
+ else {
+ c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w));
+ c3_w sot_w = han_u->sot_w[inx_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ if ( mug_w == u3r_mug(u3h(kev)) ) {
+ return c3y;
+ }
+ else {
+ return c3n;
+ }
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ return _ch_buck_hum(hav_v, mug_w);
+ }
+ else return _ch_node_hum(hav_v, lef_w, rem_w, mug_w);
+ }
+ }
+}
+
+/* u3h_hum(): check presence in hashtable.
+**
+** `key` is RETAINED.
+*/
+c3_o
+u3h_hum(u3p(u3h_root) har_p, c3_w mug_w)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w inx_w = (mug_w >> 25);
+ c3_w rem_w = CUT_END(mug_w, 25);
+ c3_w sot_w = har_u->sot_w[inx_w];
+
+ if ( _(u3h_slot_is_null(sot_w)) ) {
+ return c3n;
+ }
+ else if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ if ( mug_w == u3r_mug(u3h(kev)) ) {
+ return c3y;
+ }
+ else {
+ return c3n;
+ }
+ }
+ else {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ return _ch_node_hum(han_u, 25, rem_w, mug_w);
+ }
+}
+
+/* _ch_buck_git(): read in bucket.
+*/
+static u3_weak
+_ch_buck_git(u3h_buck* hab_u, u3_noun key)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3_noun kev = u3h_slot_to_noun(hab_u->sot_w[i_w]);
+ if ( _(u3r_sing(key, u3h(kev))) ) {
+ return u3t(kev);
+ }
+ }
+ return u3_none;
+}
+
+/* _ch_node_git(): read in node.
+*/
+static u3_weak
+_ch_node_git(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key)
+{
+ c3_w bit_w, map_w;
+
+ lef_w -= 5;
+ bit_w = (rem_w >> lef_w);
+ rem_w = CUT_END(rem_w, lef_w);
+ map_w = han_u->map_w;
+
+ if ( !BIT_SET(map_w, bit_w) ) {
+ return u3_none;
+ }
+ else {
+ c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w));
+ c3_w sot_w = han_u->sot_w[inx_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ if ( _(u3r_sing(key, u3h(kev))) ) {
+ return u3t(kev);
+ }
+ else {
+ return u3_none;
+ }
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ return _ch_buck_git(hav_v, key);
+ }
+ else return _ch_node_git(hav_v, lef_w, rem_w, key);
+ }
+ }
+}
+
+/* u3h_git(): read from hashtable.
+**
+** `key` is RETAINED; result is RETAINED.
+*/
+u3_weak
+u3h_git(u3p(u3h_root) har_p, u3_noun key)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w mug_w = u3r_mug(key);
+ c3_w inx_w = (mug_w >> 25);
+ c3_w rem_w = CUT_END(mug_w, 25);
+ c3_w sot_w = har_u->sot_w[inx_w];
+
+ if ( _(u3h_slot_is_null(sot_w)) ) {
+ return u3_none;
+ }
+ else if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ if ( _(u3r_sing(key, u3h(kev))) ) {
+ har_u->sot_w[inx_w] = u3h_noun_be_warm(sot_w);
+ return u3t(kev);
+ }
+ else {
+ return u3_none;
+ }
+ }
+ else {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ return _ch_node_git(han_u, 25, rem_w, key);
+ }
+}
+
+/* u3h_get(): read from hashtable, incrementing refcount.
+**
+** `key` is RETAINED; result is PRODUCED.
+*/
+u3_weak
+u3h_get(u3p(u3h_root) har_p, u3_noun key)
+{
+ u3_noun pro = u3h_git(har_p, key);
+
+ if ( u3_none != pro ) {
+ u3k(pro);
+ }
+ return pro;
+}
+
+/* _ch_free_buck(): free bucket
+*/
+static void
+_ch_free_buck(u3h_buck* hab_u)
+{
+ //fprintf(stderr, "free buck\r\n");
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3z(u3h_slot_to_noun(hab_u->sot_w[i_w]));
+ }
+ u3a_wfree(hab_u);
+}
+
+/* _ch_free_node(): free node.
+*/
+static void
+_ch_free_node(u3h_node* han_u, c3_w lef_w, c3_o pin_o)
+{
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+ if ( _(u3h_slot_is_null(sot_w))) {
+ } else if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3z(u3h_slot_to_noun(sot_w));
+ } else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ _ch_free_buck(hav_v);
+ } else {
+ _ch_free_node(hav_v, lef_w, pin_o);
+ }
+ }
+ }
+ u3a_wfree(han_u);
+}
+
+/* u3h_free(): free hashtable.
+*/
+void
+u3h_free(u3p(u3h_root) har_p)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3z(u3h_slot_to_noun(sot_w));
+ }
+ else if ( _(u3h_slot_is_node(sot_w)) ) {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ _ch_free_node(han_u, 25, i_w == 57);
+ }
+ }
+ u3a_wfree(har_u);
+}
+
+/* _ch_walk_buck(): walk bucket for gc.
+*/
+static void
+_ch_walk_buck(u3h_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ fun_f(u3h_slot_to_noun(hab_u->sot_w[i_w]), wit);
+ }
+}
+
+/* _ch_walk_node(): walk node for gc.
+*/
+static void
+_ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit)
+{
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ fun_f(kev, wit);
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ _ch_walk_buck(hav_v, fun_f, wit);
+ } else {
+ _ch_walk_node(hav_v, lef_w, fun_f, wit);
+ }
+ }
+ }
+}
+
+/* u3h_walk_with(): traverse hashtable with key, value fn and data
+ * argument; RETAINS.
+*/
+void
+u3h_walk_with(u3p(u3h_root) har_p,
+ void (*fun_f)(u3_noun, void*),
+ void* wit)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ fun_f(kev, wit);
+ }
+ else if ( _(u3h_slot_is_node(sot_w)) ) {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ _ch_walk_node(han_u, 25, fun_f, wit);
+ }
+ }
+}
+
+/* _ch_walk_plain(): use plain u3_noun fun_f for each node
+ */
+static void
+_ch_walk_plain(u3_noun kev, void* wit)
+{
+ void (*fun_f)(u3_noun) = (void (*)(u3_noun))wit;
+ fun_f(kev);
+}
+
+/* u3h_walk(): u3h_walk_with, but with no data argument
+*/
+void
+u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun))
+{
+ u3h_walk_with(har_p, _ch_walk_plain, (void *)fun_f);
+}
+
+/* _ch_take_noun(): take key and call [fun_f] on val.
+*/
+static u3h_slot
+_ch_take_noun(u3h_slot sot_w, u3_funk fun_f)
+{
+ u3_noun kov = u3h_slot_to_noun(sot_w);
+ u3_noun kev = u3nc(u3a_take(u3h(kov)),
+ fun_f(u3t(kov)));
+
+ return u3h_noun_to_slot(kev);
+}
+
+/* _ch_take_buck(): take bucket and contents
+*/
+static u3h_slot
+_ch_take_buck(u3h_slot sot_w, u3_funk fun_f)
+{
+ u3h_buck* hab_u = u3h_slot_to_node(sot_w);
+ u3h_buck* bah_u = _ch_buck_new(hab_u->len_w);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ bah_u->sot_w[i_w] = _ch_take_noun(hab_u->sot_w[i_w], fun_f);
+ }
+
+ return u3h_node_to_slot(bah_u);
+}
+
+/* _ch_take_node(): take node and contents
+*/
+static u3h_slot
+_ch_take_node(u3h_slot sot_w, c3_w lef_w, u3_funk fun_f)
+{
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ u3h_node* nah_u = _ch_node_new(len_w);
+ c3_w i_w;
+
+ nah_u->map_w = han_u->map_w;
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w tos_w = han_u->sot_w[i_w];
+ nah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(tos_w) )
+ ? _ch_take_noun(tos_w, fun_f)
+ : ( 0 == lef_w )
+ ? _ch_take_buck(tos_w, fun_f)
+ : _ch_take_node(tos_w, lef_w, fun_f);
+ }
+
+ return u3h_node_to_slot(nah_u);
+}
+
+/* u3h_take_with(): gain hashtable, copying junior keys
+** and calling [fun_f] on values
+*/
+u3p(u3h_root)
+u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ u3p(u3h_root) rah_p = u3h_new_cache(har_u->max_w);
+ u3h_root* rah_u = u3to(u3h_root, rah_p);
+ c3_w sot_w, i_w;
+
+ rah_u->use_w = har_u->use_w;
+ rah_u->arm_u = har_u->arm_u;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ sot_w = har_u->sot_w[i_w];
+ if ( c3n == u3h_slot_is_null(sot_w) ) {
+ rah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(sot_w) )
+ ? _ch_take_noun(sot_w, fun_f)
+ : _ch_take_node(sot_w, 25, fun_f);
+ }
+ }
+
+ return rah_p;
+}
+
+/* u3h_take(): gain hashtable, copying junior nouns
+*/
+u3p(u3h_root)
+u3h_take(u3p(u3h_root) har_p)
+{
+ return u3h_take_with(har_p, u3a_take);
+}
+
+/* _ch_mark_buck(): mark bucket for gc.
+*/
+c3_w
+_ch_mark_buck(u3h_buck* hab_u)
+{
+ c3_w tot_w = 0;
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ tot_w += u3a_mark_noun(u3h_slot_to_noun(hab_u->sot_w[i_w]));
+ }
+ tot_w += u3a_mark_ptr(hab_u);
+
+ return tot_w;
+}
+
+/* _ch_mark_node(): mark node for gc.
+*/
+c3_w
+_ch_mark_node(u3h_node* han_u, c3_w lef_w)
+{
+ c3_w tot_w = 0;
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_mark_noun(kev);
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ tot_w += _ch_mark_buck(hav_v);
+ } else {
+ tot_w += _ch_mark_node(hav_v, lef_w);
+ }
+ }
+ }
+
+ tot_w += u3a_mark_ptr(han_u);
+
+ return tot_w;
+}
+
+/* u3h_mark(): mark hashtable for gc.
+*/
+c3_w
+u3h_mark(u3p(u3h_root) har_p)
+{
+ c3_w tot_w = 0;
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_mark_noun(kev);
+ }
+ else if ( _(u3h_slot_is_node(sot_w)) ) {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ tot_w += _ch_mark_node(han_u, 25);
+ }
+ }
+
+ tot_w += u3a_mark_ptr(har_u);
+
+ return tot_w;
+}
+
+static void
+_ch_relocate_noun(u3h_slot *sot_w)
+{
+ u3_noun kev = u3h_slot_to_noun(*sot_w);
+ u3a_relocate_noun(&kev);
+ *sot_w = u3h_noun_to_slot(kev);
+}
+
+static void
+_ch_relocate_buck(u3h_slot *sot_w)
+{
+ u3h_buck *hab_u = u3h_slot_to_node(*sot_w);
+ u3_post new_p, sot_p = u3a_outa(hab_u);
+ c3_t fir_t;
+
+ new_p = u3a_mark_relocate_post(sot_p, &fir_t);
+ *sot_w = u3h_node_to_slot(u3a_into(new_p));
+
+ if ( !fir_t ) return;
+
+ for ( c3_w i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ _ch_relocate_noun(&(hab_u->sot_w[i_w]));
+ }
+}
+
+static void
+_ch_relocate_slot(u3h_slot *sot_w, c3_w lef_w);
+
+static void
+_ch_relocate_node(u3h_slot *sot_w, c3_w lef_w)
+{
+ u3h_node* han_u = u3h_slot_to_node(*sot_w);
+ u3_post new_p, sot_p = u3a_outa(han_u);
+ c3_w len_w;
+ c3_t fir_t;
+
+ new_p = u3a_mark_relocate_post(sot_p, &fir_t);
+ *sot_w = u3h_node_to_slot(u3a_into(new_p));
+
+ if ( !fir_t ) return;
+
+ len_w = _ch_popcount(han_u->map_w);
+ lef_w -= 5;
+
+ for ( c3_w i_w = 0; i_w < len_w; i_w++ ) {
+ _ch_relocate_slot(&(han_u->sot_w[i_w]), lef_w);
+ }
+}
+
+static void
+_ch_relocate_slot(u3h_slot *sot_w, c3_w lef_w)
+{
+ if ( c3y == u3h_slot_is_noun(*sot_w) ) {
+ _ch_relocate_noun(sot_w);
+ }
+ else if ( !lef_w ) {
+ _ch_relocate_buck(sot_w);
+ }
+ else {
+ _ch_relocate_node(sot_w, lef_w);
+ }
+}
+
+/* u3h_relocate(): relocate hashtable for compaction.
+*/
+void
+u3h_relocate(u3p(u3h_root) *har_p)
+{
+ u3_post new_p, old_p = *har_p;
+ u3h_root* har_u = u3to(u3h_root, old_p);
+ c3_w sot_w, i_w;
+ c3_t fir_t;
+
+ new_p = u3a_mark_relocate_post(old_p, &fir_t);
+ *har_p = new_p;
+
+ if ( !fir_t ) return;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ sot_w = har_u->sot_w[i_w];
+
+ if ( c3n == u3h_slot_is_null(sot_w) ) {
+ _ch_relocate_slot(&(har_u->sot_w[i_w]), 25);
+ }
+ }
+}
+
+/* _ch_count_buck(): count bucket for gc.
+*/
+c3_w
+_ch_count_buck(u3h_buck* hab_u)
+{
+ c3_w tot_w = 0;
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ tot_w += u3a_count_noun(u3h_slot_to_noun(hab_u->sot_w[i_w]));
+ }
+ tot_w += u3a_count_ptr(hab_u);
+
+ return tot_w;
+}
+
+/* _ch_count_node(): count node for gc.
+*/
+c3_w
+_ch_count_node(u3h_node* han_u, c3_w lef_w)
+{
+ c3_w tot_w = 0;
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_count_noun(kev);
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ tot_w += _ch_count_buck(hav_v);
+ } else {
+ tot_w += _ch_count_node(hav_v, lef_w);
+ }
+ }
+ }
+
+ tot_w += u3a_count_ptr(han_u);
+
+ return tot_w;
+}
+
+/* u3h_count(): count hashtable for gc.
+*/
+c3_w
+u3h_count(u3p(u3h_root) har_p)
+{
+ c3_w tot_w = 0;
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_count_noun(kev);
+ }
+ else if ( _(u3h_slot_is_node(sot_w)) ) {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ tot_w += _ch_count_node(han_u, 25);
+ }
+ }
+
+ tot_w += u3a_count_ptr(har_u);
+
+ return tot_w;
+}
+
+/* _ch_discount_buck(): discount bucket for gc.
+*/
+c3_w
+_ch_discount_buck(u3h_buck* hab_u)
+{
+ c3_w tot_w = 0;
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ tot_w += u3a_discount_noun(u3h_slot_to_noun(hab_u->sot_w[i_w]));
+ }
+ tot_w += u3a_discount_ptr(hab_u);
+
+ return tot_w;
+}
+
+/* _ch_discount_node(): discount node for gc.
+*/
+c3_w
+_ch_discount_node(u3h_node* han_u, c3_w lef_w)
+{
+ c3_w tot_w = 0;
+ c3_w len_w = _ch_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_discount_noun(kev);
+ }
+ else {
+ void* hav_v = u3h_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ tot_w += _ch_discount_buck(hav_v);
+ } else {
+ tot_w += _ch_discount_node(hav_v, lef_w);
+ }
+ }
+ }
+
+ tot_w += u3a_discount_ptr(han_u);
+
+ return tot_w;
+}
+
+/* u3h_discount(): discount hashtable for gc.
+*/
+c3_w
+u3h_discount(u3p(u3h_root) har_p)
+{
+ c3_w tot_w = 0;
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_slot_to_noun(sot_w);
+
+ tot_w += u3a_discount_noun(kev);
+ }
+ else if ( _(u3h_slot_is_node(sot_w)) ) {
+ u3h_node* han_u = u3h_slot_to_node(sot_w);
+
+ tot_w += _ch_discount_node(han_u, 25);
+ }
+ }
+
+ tot_w += u3a_discount_ptr(har_u);
+
+ return tot_w;
+}
+
+/* u3h_wyt(): number of entries
+*/
+c3_w
+u3h_wyt(u3p(u3h_root) har_p)
+{
+ u3h_root* har_u = u3to(u3h_root, har_p);
+ return har_u->use_w;
+}
diff --git a/vere/pkg/noun/hashtable.h b/vere/pkg/noun/hashtable.h
new file mode 100644
index 0000000..f263dd8
--- /dev/null
+++ b/vere/pkg/noun/hashtable.h
@@ -0,0 +1,206 @@
+#ifndef U3_HASHTABLE_H
+#define U3_HASHTABLE_H
+
+#include "c3/c3.h"
+#include "types.h"
+
+ /** Data structures.
+ **/
+ /** Straightforward implementation of the classic Bagwell
+ *** HAMT (hash array mapped trie), using a mug hash.
+ ***
+ *** Because a mug is 31 bits, the root table has 64 slots.
+ *** The 31 bits of a mug are divided into the first lookup,
+ *** which is 6 bits (corresponding to the 64 entries in the
+ *** root table), followed by 5 more branchings of 5 bits each,
+ *** corresponding to the 32-slot nodes for everything under
+ *** the root node.
+ ***
+ *** We store an extra "freshly warm" bit and use it for a simple
+ *** clock-algorithm reclamation policy.
+ **/
+ /* u3h_slot: map slot.
+ **
+ ** Either a key-value cell or a loom offset, decoded as a pointer
+ ** to a u3h_node, or a u3h_buck at the bottom. Matches the u3_noun
+ ** format - coordinate with allocate.h. The top two bits are:
+ **
+ ** 00 - empty (in the root table only)
+ ** 01 - table (node or buck)
+ ** 02 - entry, stale
+ ** 03 - entry, fresh
+ */
+ typedef c3_w u3h_slot;
+
+ /* u3h_node: map node.
+ */
+ typedef struct {
+ c3_w map_w; // bitmap for [sot_w]
+ u3h_slot sot_w[]; // filled slots
+ } u3h_node;
+
+ /* u3h_root: hash root table
+ */
+ typedef struct {
+ c3_w max_w; // number of cache lines (0 for no trimming)
+ c3_w use_w; // number of lines currently filled
+ struct {
+ c3_w mug_w; // current hash
+ c3_w inx_w; // index into current hash bucket
+ c3_o buc_o; // XX remove
+ } arm_u; // clock arm
+ u3h_slot sot_w[64]; // slots
+ } u3h_root;
+
+ /* u3h_buck: bottom bucket.
+ */
+ typedef struct {
+ c3_w len_w; // length of [sot_w]
+ u3h_slot sot_w[]; // filled slots
+ } u3h_buck;
+
+ /** HAMT macros.
+ ***
+ *** Coordinate with u3_noun definition!
+ **/
+ /* u3h_slot_is_null(): yes iff slot is empty
+ ** u3h_slot_is_noun(): yes iff slot contains a key/value cell
+ ** u3h_slot_is_node(): yes iff slot contains a subtable/bucket
+ ** u3h_slot_is_warm(): yes iff fresh bit is set
+ ** u3h_slot_to_node(): slot to node pointer
+ ** u3h_node_to_slot(): node pointer to slot
+ ** u3h_slot_to_noun(): slot to cell
+ ** u3h_noun_to_slot(): cell to slot
+ ** u3h_noun_be_warm(): warm mutant
+ ** u3h_noun_be_cold(): cold mutant
+ */
+# define u3h_slot_is_null(sot) ((0 == ((sot) >> 30)) ? c3y : c3n)
+# define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n)
+# define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n)
+# define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n)
+# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits))
+# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000)
+# define u3h_noun_be_warm(sot) ((sot) | 0x40000000)
+# define u3h_noun_be_cold(sot) ((sot) & ~0x40000000)
+# define u3h_slot_to_noun(sot) (0x40000000 | (sot))
+# define u3h_noun_to_slot(som) (u3h_noun_be_warm(som))
+
+ /** Functions.
+ ***
+ *** Needs: delete and merge functions; clock reclamation function.
+ **/
+ /* u3h_new_cache(): create hashtable with bounded size.
+ */
+ u3p(u3h_root)
+ u3h_new_cache(c3_w clk_w);
+
+ /* u3h_new(): create hashtable.
+ */
+ u3p(u3h_root)
+ u3h_new(void);
+
+ /* u3h_put(): insert in hashtable.
+ **
+ ** `key` is RETAINED; `val` is transferred.
+ */
+ void
+ u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val);
+
+ /* u3h_put_get(): insert in caching hashtable, returning deleted entry
+ **
+ ** `key` is RETAINED; `val` is transferred.
+ */
+ u3_weak
+ u3h_put_get(u3p(u3h_root) har_p, u3_noun key, u3_noun val);
+
+ /* u3h_uni(): unify hashtables, copying [rah_p] into [har_p]
+ */
+ void
+ u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p);
+
+ /* u3h_get(): read from hashtable.
+ **
+ ** `key` is RETAINED; result is PRODUCED.
+ */
+ u3_weak
+ u3h_get(u3p(u3h_root) har_p, u3_noun key);
+
+ /* u3h_git(): read from hashtable, retaining result.
+ **
+ ** `key` is RETAINED; result is RETAINED.
+ */
+ u3_weak
+ u3h_git(u3p(u3h_root) har_p, u3_noun key);
+
+ /* u3h_del(); delete from hashtable.
+ **
+ ** `key` is RETAINED
+ */
+ void
+ u3h_del(u3p(u3h_root) har_p, u3_noun key);
+
+ /* u3h_trim_to(): trim to n key-value pairs
+ */
+ void
+ u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w);
+
+ /* u3h_trim_with(): trim to n key-value pairs, with deletion callback
+ */
+ void
+ u3h_trim_with(u3p(u3h_root) har_p, c3_w n_w, void (*del_cb)(u3_noun));
+
+ /* u3h_free(): free hashtable.
+ */
+ void
+ u3h_free(u3p(u3h_root) har_p);
+
+ /* u3h_mark(): mark hashtable for gc.
+ */
+ c3_w
+ u3h_mark(u3p(u3h_root) har_p);
+
+ /* u3h_relocate(): relocate hashtable for compaction.
+ */
+ void
+ u3h_relocate(u3p(u3h_root) *har_p);
+
+ /* u3h_count(): count hashtable for gc.
+ */
+ c3_w
+ u3h_count(u3p(u3h_root) har_p);
+
+ /* u3h_discount(): discount hashtable for gc.
+ */
+ c3_w
+ u3h_discount(u3p(u3h_root) har_p);
+
+ /* u3h_walk_with(): traverse hashtable with key, value fn and data
+ * argument; RETAINS.
+ */
+ void
+ u3h_walk_with(u3p(u3h_root) har_p,
+ void (*fun_f)(u3_noun, void*),
+ void* wit);
+
+ /* u3h_walk(): u3h_walk_with, but with no data argument
+ */
+ void
+ u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun));
+
+ /* u3h_take_with(): gain hashtable, copying junior keys
+ ** and calling [fun_f] on values
+ */
+ u3p(u3h_root)
+ u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f);
+
+ /* u3h_take(): gain hashtable, copying junior nouns
+ */
+ u3p(u3h_root)
+ u3h_take(u3p(u3h_root) har_p);
+
+ /* u3h_wyt(): number of entries
+ */
+ c3_w
+ u3h_wyt(u3p(u3h_root) har_p);
+
+#endif /* ifndef U3_HASHTABLE_H */
diff --git a/vere/pkg/noun/hashtable_tests.c b/vere/pkg/noun/hashtable_tests.c
new file mode 100644
index 0000000..9a5a3f8
--- /dev/null
+++ b/vere/pkg/noun/hashtable_tests.c
@@ -0,0 +1,301 @@
+/// @file
+
+#include "noun.h"
+#define TEST_SIZE 100000
+
+// defined in noun/hashtable.c
+c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w);
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_init(1 << 27);
+ u3m_pave(c3y);
+}
+
+/* _test_put_del():
+*/
+static c3_i
+_test_put_del()
+{
+ u3p(u3h_root) har_p = u3h_new();
+ c3_i ret_i = 1;
+
+ c3_w i_w;
+ for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) {
+ u3_noun key = u3i_word(i_w);
+ u3_noun val = u3nc(u3_nul, u3k(key));
+ u3h_put(har_p, key, val);
+ u3z(key);
+ }
+ // fprintf(stderr, "inserted\r\n");
+
+ for ( i_w = 0; i_w < TEST_SIZE; i_w++ ) {
+ u3_noun key = u3i_word(i_w);
+ u3_weak val = u3h_get(har_p, key);
+ if ( val == u3_none ) {
+ fprintf(stderr, "failed insert\r\n");
+ ret_i = 0;
+ }
+ u3z(key);
+ u3z(val);
+ }
+ // fprintf(stderr, "presence\r\n");
+ c3_w del_w[4] = {30, 82, 4921, 535};
+
+ for ( i_w = 0; i_w < 4; i_w++ ) {
+ u3_noun key = u3i_word(del_w[i_w]);
+ u3h_del(har_p, key);
+ u3z(key);
+ }
+ // fprintf(stderr, "deleted\r\n");
+
+ for ( i_w = 0; i_w < 4; i_w++ ) {
+ u3_noun key = u3i_word(del_w[i_w]);
+ u3_weak val = u3h_get(har_p, key);
+ if ( u3_none != val ) {
+ fprintf(stderr, "failed delete\r\n");
+ ret_i = 0;
+ break;
+ }
+ }
+ // fprintf(stderr, "presence two\r\n");
+ u3h_free(har_p);
+ // fprintf(stderr, "freed\r\n");
+
+ return ret_i;
+}
+
+/* _test_bit_manipulation():
+*/
+static c3_i
+_test_bit_manipulation()
+{
+ c3_i ret_i = 1;
+
+ if ( sizeof(u3_noun) != sizeof(u3h_slot) ) {
+ fprintf(stderr, "bit manipulation: wrong size\r\n");
+ ret_i = 0;
+ }
+
+ u3h_slot a = 0;
+
+ if (u3h_slot_is_null(a) != c3y) {
+ fprintf(stderr, "bit manipulation: nullity\r\n");
+ ret_i = 0;
+ }
+
+ a = u3h_noun_be_warm(a);
+ if (u3h_slot_is_warm(a) != c3y) {
+ fprintf(stderr, "bit manipulation: warmth\r\n");
+ ret_i = 0;
+ }
+
+ if (u3h_slot_is_null(a) != c3n) {
+ fprintf(stderr, "bit manipulation: nullity 2\r\n");
+ ret_i = 0;
+ }
+
+ a = u3h_noun_be_cold(a);
+ if (u3h_slot_is_warm(a) != c3n) {
+ fprintf(stderr, "bit manipulation: coldness\r\n");
+ ret_i = 0;
+ }
+
+ return ret_i;
+}
+
+/* _test_no_cache(): test a hashtable without caching.
+*/
+static c3_i
+_test_no_cache(void)
+{
+ c3_i ret_i = 1;
+ c3_w max_w = 1000;
+ c3_w i_w;
+
+ u3p(u3h_root) har_p = u3h_new();
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ u3h_put(har_p, i_w, i_w + max_w);
+ }
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ if ( (i_w + max_w) != u3h_get(har_p, i_w) ) {
+ fprintf(stderr, "bit test_no_cache: get failed\r\n");
+ ret_i = 0;
+ }
+ }
+
+ u3h_free(har_p);
+ return ret_i;
+}
+
+/* _test_skip_slot():
+*/
+static c3_i
+_test_skip_slot(void)
+{
+ c3_i ret_i = 1;
+
+ // root table
+ {
+ c3_w mug_w = 0x17 << 25;
+ c3_w res_w = _ch_skip_slot(mug_w, 25);
+
+ if ( (0x18 << 25) != res_w ) {
+ fprintf(stderr, "bit skip_slot (a): failed\r\n");
+ ret_i = 0;
+ }
+ }
+
+ {
+ c3_w mug_w = 63 << 25; // 6 bits, all ones
+ c3_w res_w = _ch_skip_slot(mug_w, 25);
+
+ if ( 0 != res_w ) {
+ fprintf(stderr, "bit skip_slot (b): failed\r\n");
+ ret_i = 0;
+ }
+ }
+
+ // child nodes
+ {
+ c3_w mug_w = 17 << 20;
+ c3_w res_w = _ch_skip_slot(mug_w, 20);
+
+ if ( (18 << 20) != res_w ) {
+ fprintf(stderr, "bit skip_slot (c): failed\r\n");
+ ret_i = 0;
+ }
+ }
+
+ {
+ c3_w mug_w = 31 << 20; // 5 bits, all ones
+ c3_w res_w = _ch_skip_slot(mug_w, 20);
+ u3_assert((1 << 25) == res_w);
+
+ if ( (1 << 25) != res_w ) {
+ fprintf(stderr, "bit skip_slot (d): failed\r\n");
+ ret_i = 0;
+ }
+ }
+
+ return ret_i;
+}
+
+/* _test_cache_trimming(): ensure a caching hashtable removes stale items.
+*/
+static c3_i
+_test_cache_trimming(void)
+{
+ c3_i ret_i = 1;
+ c3_w max_w = 2000000; // big number
+ //c3_w max_w = 348000; // caused a leak before
+ c3_w i_w, fil_w = max_w / 10;
+
+ u3p(u3h_root) har_p = u3h_new_cache(fil_w);
+ u3h_root* har_u = u3to(u3h_root, har_p);
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ u3_noun cel = u3nc(i_w, i_w);
+ u3h_put(har_p, cel, cel);
+ }
+
+ {
+ // last thing we put in is still there
+ c3_w las_w = max_w - 1;
+ u3_noun key = u3nc(las_w, las_w);
+ u3_noun val = u3h_get(har_p, key);
+ u3z(key);
+
+ if ( las_w != u3t(val) ) {
+ fprintf(stderr, "cache_trimming (a): fail\r\n");
+ ret_i = 0;
+ }
+
+ if ( fil_w != har_u->use_w ) {
+ fprintf(stderr, "cache_trimming (b): fail %d != %d\r\n",
+ fil_w, har_u->use_w );
+ ret_i = 0;
+ }
+
+ u3z(val);
+ }
+
+ u3h_free(har_p);
+ return ret_i;
+}
+
+/* _test_cache_replace_value():
+*/
+static c3_i
+_test_cache_replace_value(void)
+{
+ c3_i ret_i = 1;
+ c3_w max_w = 100;
+ c3_w i_w;
+
+ u3p(u3h_root) har_p = u3h_new_cache(max_w);
+ u3h_root* har_u = u3to(u3h_root, har_p);
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ u3h_put(har_p, i_w, i_w + max_w);
+ }
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ u3h_put(har_p, i_w, i_w + max_w + 1);
+ }
+
+ if ( (2 * max_w) != u3h_get(har_p, max_w - 1) ) {
+ fprintf(stderr, "cache_replace (a): fail\r\n");
+ ret_i = 0;
+ }
+ if ( max_w != har_u->use_w ) {
+ fprintf(stderr, "cache_replace (b): fail\r\n");
+ fprintf(stderr, "cache_replace (b): fail %d %d\r\n",
+ max_w, har_u->use_w );
+ ret_i = 0;
+ }
+
+ u3h_free(har_p);
+ return ret_i;
+}
+
+static c3_i
+_test_hashtable(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _test_bit_manipulation();
+ ret_i &= _test_no_cache();
+ ret_i &= _test_skip_slot();
+ ret_i &= _test_cache_trimming();
+ ret_i &= _test_cache_replace_value();
+ ret_i &= _test_put_del();
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_hashtable() ) {
+ fprintf(stderr, "test_hashtable: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test_hashtable: ok\r\n");
+
+ return 0;
+}
diff --git a/vere/pkg/noun/imprison.c b/vere/pkg/noun/imprison.c
new file mode 100644
index 0000000..c182d95
--- /dev/null
+++ b/vere/pkg/noun/imprison.c
@@ -0,0 +1,772 @@
+/// @file
+
+#include "imprison.h"
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "manage.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "xtract.h"
+
+/* _ci_slab_size(): calculate slab bloq-size, checking for overflow.
+*/
+static c3_w
+_ci_slab_size(c3_g met_g, c3_d len_d)
+{
+ c3_d bit_d = len_d << met_g;
+ c3_d wor_d = (bit_d + 0x1f) >> 5;
+ c3_w wor_w = (c3_w)wor_d;
+
+ if ( (wor_w != wor_d)
+ || (len_d != (bit_d >> met_g)) )
+ {
+ return (c3_w)u3m_bail(c3__fail);
+ }
+
+ return wor_w;
+}
+
+/* _ci_slab_init(): initialize slab with heap allocation.
+** NB: callers must ensure [len_w] >0
+*/
+static void
+_ci_slab_init(u3i_slab* sab_u, c3_w len_w)
+{
+ c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom));
+ u3a_atom* vat_u = (void *)nov_w;
+
+ vat_u->use_w = 1;
+ vat_u->mug_w = 0;
+ vat_u->len_w = len_w;
+
+#ifdef U3_MEMORY_DEBUG
+ u3_assert( len_w );
+#endif
+
+ sab_u->_._vat_u = vat_u;
+ sab_u->buf_w = vat_u->buf_w;
+ sab_u->len_w = len_w;
+}
+
+/* _ci_slab_grow(): update slab with heap reallocation.
+*/
+static void
+_ci_slab_grow(u3i_slab* sab_u, c3_w len_w)
+{
+ c3_w* old_w = (void*)sab_u->_._vat_u;
+ // XX implement a more efficient u3a_wealloc()
+ //
+ c3_w* nov_w = u3a_wealloc(old_w, len_w + c3_wiseof(u3a_atom));
+ u3a_atom* vat_u = (void *)nov_w;
+
+ vat_u->len_w = len_w;
+
+ sab_u->_._vat_u = vat_u;
+ sab_u->buf_w = vat_u->buf_w;
+ sab_u->len_w = len_w;
+}
+
+/* _ci_atom_mint(): finalize a heap-allocated atom at specified length.
+*/
+static u3_atom
+_ci_atom_mint(u3a_atom* vat_u, c3_w len_w)
+{
+ c3_w* nov_w = (void*)vat_u;
+
+ if ( 0 == len_w ) {
+ u3a_wfree(nov_w);
+ return (u3_atom)0;
+ }
+ else if ( 1 == len_w ) {
+ c3_w dat_w = *vat_u->buf_w;
+
+ if ( c3y == u3a_is_cat(dat_w) ) {
+ u3a_wfree(nov_w);
+ return (u3_atom)dat_w;
+ }
+ }
+
+ // try to strip a block off the end
+ //
+ {
+ c3_w old_w = vat_u->len_w;
+
+ if ( old_w > len_w ) {
+ c3_y wiz_y = c3_wiseof(u3a_atom);
+ u3a_wtrim(nov_w, old_w + wiz_y, len_w + wiz_y);
+ }
+ }
+
+ vat_u->len_w = len_w;
+
+ return u3a_to_pug(u3a_outa(nov_w));
+}
+
+/* u3i_slab_init(): configure bloq-length slab, zero-initialize.
+*/
+void
+u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
+{
+ u3i_slab_bare(sab_u, met_g, len_d);
+
+ u3t_on(mal_o);
+ memset(sab_u->buf_y, 0, (size_t)sab_u->len_w * 4);
+ u3t_off(mal_o);
+}
+
+/* u3i_slab_bare(): configure bloq-length slab, uninitialized.
+*/
+void
+u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
+{
+ u3t_on(mal_o);
+ {
+ c3_w wor_w = _ci_slab_size(met_g, len_d);
+
+ // if we only need one word, use the static storage in [sab_u]
+ //
+ if ( (0 == wor_w) || (1 == wor_w) ) {
+ sab_u->_._vat_u = 0;
+ sab_u->buf_w = &sab_u->_._sat_w;
+ sab_u->len_w = 1;
+ }
+ // allocate an indirect atom
+ //
+ else {
+ _ci_slab_init(sab_u, wor_w);
+ }
+ }
+ u3t_off(mal_o);
+}
+
+/* u3i_slab_from(): configure bloq-length slab, initialize with [a].
+*/
+void
+u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d)
+{
+ u3i_slab_bare(sab_u, met_g, len_d);
+
+ // copies [a], zero-initializes any additional space
+ //
+ u3r_words(0, sab_u->len_w, sab_u->buf_w, a);
+
+ // if necessary, mask off extra most-significant bits
+ // from most-significant word
+ //
+ if ( (5 > met_g) && (u3r_met(5, a) >= sab_u->len_w) ) {
+ // NB: overflow already checked in _ci_slab_size()
+ //
+ c3_d bit_d = len_d << met_g;
+ c3_w wor_w = bit_d >> 5;
+ c3_w bit_w = bit_d & 0x1f;
+
+ if ( bit_w ) {
+ sab_u->buf_w[wor_w] &= ((c3_w)1 << bit_w) - 1;
+ }
+ }
+}
+
+/* u3i_slab_grow(): resize slab, zero-initializing new space.
+*/
+void
+u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
+{
+ c3_w old_w = sab_u->len_w;
+
+ u3t_on(mal_o);
+ {
+ c3_w wor_w = _ci_slab_size(met_g, len_d);
+
+ // XX actually shrink?
+ //
+ if ( wor_w <= old_w ) {
+ sab_u->len_w = wor_w;
+ }
+ else {
+ // upgrade from static storage
+ //
+ if ( 1 == old_w ) {
+ c3_w dat_w = *sab_u->buf_w;
+
+ _ci_slab_init(sab_u, wor_w);
+ sab_u->buf_w[0] = dat_w;
+ }
+ // reallocate
+ //
+ else {
+ _ci_slab_grow(sab_u, wor_w);
+ }
+
+ {
+ c3_y* buf_y = (void*)(sab_u->buf_w + old_w);
+ size_t dif_i = wor_w - old_w;
+ memset(buf_y, 0, dif_i * 4);
+ }
+ }
+ }
+ u3t_off(mal_o);
+}
+
+/* u3i_slab_free(): dispose memory backing slab.
+*/
+void
+u3i_slab_free(u3i_slab* sab_u)
+{
+ c3_w len_w = sab_u->len_w;
+ u3a_atom* vat_u = sab_u->_._vat_u;
+
+ u3t_on(mal_o);
+
+ if ( 1 == len_w ) {
+ u3_assert( !vat_u );
+ }
+ else {
+ c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
+ u3_assert( tav_w == (c3_w*)vat_u );
+ u3a_wfree(vat_u);
+ }
+
+ u3t_off(mal_o);
+}
+
+/* u3i_slab_mint(): produce atom from slab, trimming.
+*/
+u3_atom
+u3i_slab_mint(u3i_slab* sab_u)
+{
+ c3_w len_w = sab_u->len_w;
+ u3a_atom* vat_u = sab_u->_._vat_u;
+ u3_atom pro;
+
+ u3t_on(mal_o);
+
+ if ( 1 == len_w ) {
+ c3_w dat_w = *sab_u->buf_w;
+
+ u3_assert( !vat_u );
+
+ u3t_off(mal_o);
+ pro = u3i_word(dat_w);
+ u3t_on(mal_o);
+ }
+ else {
+ u3a_atom* vat_u = sab_u->_._vat_u;
+ c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
+ u3_assert( tav_w == (c3_w*)vat_u );
+
+ // trim trailing zeros
+ //
+ while ( len_w && !(sab_u->buf_w[len_w - 1]) ) {
+ len_w--;
+ }
+
+ pro = _ci_atom_mint(vat_u, len_w);
+ }
+
+ u3t_off(mal_o);
+
+ return pro;
+}
+
+/* u3i_slab_moot(): produce atom from slab, no trimming.
+*/
+u3_atom
+u3i_slab_moot(u3i_slab* sab_u)
+{
+ c3_w len_w = sab_u->len_w;
+ u3_atom pro;
+
+ u3t_on(mal_o);
+
+ if ( 1 == len_w) {
+ c3_w dat_w = *sab_u->buf_w;
+
+ u3_assert( !sab_u->_._vat_u );
+
+ u3t_off(mal_o);
+ pro = u3i_word(dat_w);
+ u3t_on(mal_o);
+ }
+ else {
+ u3a_atom* vat_u = sab_u->_._vat_u;
+ c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
+ u3_assert( tav_w == (c3_w*)vat_u );
+
+ pro = _ci_atom_mint(vat_u, len_w);
+ }
+
+ u3t_off(mal_o);
+
+ return pro;
+}
+
+/* u3i_word(): construct u3_atom from c3_w.
+*/
+u3_atom
+u3i_word(c3_w dat_w)
+{
+ u3_atom pro;
+
+ u3t_on(mal_o);
+
+ if ( c3y == u3a_is_cat(dat_w) ) {
+ pro = (u3_atom)dat_w;
+ }
+ else {
+ c3_w* nov_w = u3a_walloc(1 + c3_wiseof(u3a_atom));
+ u3a_atom* vat_u = (void *)nov_w;
+
+ vat_u->use_w = 1;
+ vat_u->mug_w = 0;
+ vat_u->len_w = 1;
+ vat_u->buf_w[0] = dat_w;
+
+ pro = u3a_to_pug(u3a_outa(nov_w));
+ }
+
+ u3t_off(mal_o);
+
+ return pro;
+}
+
+/* u3i_chub(): construct u3_atom from c3_d.
+*/
+u3_atom
+u3i_chub(c3_d dat_d)
+{
+ if ( c3y == u3a_is_cat(dat_d) ) {
+ return (u3_atom)dat_d;
+ }
+ else {
+ c3_w dat_w[2] = {
+ dat_d & 0xffffffffULL,
+ dat_d >> 32
+ };
+
+ return u3i_words(2, dat_w);
+ }
+}
+
+/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom.
+*/
+u3_atom
+u3i_bytes(c3_w a_w,
+ const c3_y* b_y)
+{
+ // strip trailing zeroes.
+ //
+ while ( a_w && !b_y[a_w - 1] ) {
+ a_w--;
+ }
+
+ if ( !a_w ) {
+ return (u3_atom)0;
+ }
+ else {
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 3, a_w);
+
+ u3t_on(mal_o);
+ {
+ // zero-initialize last word
+ //
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+ memcpy(sab_u.buf_y, b_y, a_w);
+ }
+ u3t_off(mal_o);
+
+ return u3i_slab_moot_bytes(&sab_u);
+ }
+}
+
+/* u3i_words(): Copy [a] words from [b] into an atom.
+*/
+u3_atom
+u3i_words(c3_w a_w,
+ const c3_w* b_w)
+{
+ // strip trailing zeroes.
+ //
+ while ( a_w && !b_w[a_w - 1] ) {
+ a_w--;
+ }
+
+ if ( !a_w ) {
+ return (u3_atom)0;
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 5, a_w);
+
+ u3t_on(mal_o);
+ memcpy(sab_u.buf_w, b_w, (size_t)4 * a_w);
+ u3t_off(mal_o);
+
+ return u3i_slab_moot(&sab_u);
+ }
+}
+
+/* u3i_chubs(): Copy [a] chubs from [b] into an atom.
+*/
+u3_atom
+u3i_chubs(c3_w a_w,
+ const c3_d* b_d)
+{
+ // strip trailing zeroes.
+ //
+ while ( a_w && !b_d[a_w - 1] ) {
+ a_w--;
+ }
+
+ if ( !a_w ) {
+ return (u3_atom)0;
+ }
+ else if ( 1 == a_w ) {
+ return u3i_chub(b_d[0]);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 6, a_w);
+
+ u3t_on(mal_o);
+ {
+ c3_w* buf_w = sab_u.buf_w;
+ c3_w i_w;
+ c3_d i_d;
+
+ for ( i_w = 0; i_w < a_w; i_w++ ) {
+ i_d = b_d[i_w];
+ *buf_w++ = i_d & 0xffffffffULL;
+ *buf_w++ = i_d >> 32;
+ }
+ }
+ u3t_off(mal_o);
+
+ return u3i_slab_mint(&sab_u);
+ }
+}
+
+/* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it.
+*/
+u3_atom
+u3i_mp(mpz_t a_mp)
+{
+ size_t siz_i = mpz_sizeinbase(a_mp, 2);
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, 0, siz_i);
+
+ mpz_export(sab_u.buf_w, 0, -1, sizeof(c3_w), 0, 0, a_mp);
+ mpz_clear(a_mp);
+
+ // per the mpz_export() docs:
+ //
+ // > If op is non-zero then the most significant word produced
+ // > will be non-zero.
+ //
+ return u3i_slab_moot(&sab_u);
+}
+
+/* u3i_vint(): increment [a].
+*/
+u3_atom
+u3i_vint(u3_noun a)
+{
+ u3_assert(u3_none != a);
+
+ if ( _(u3a_is_cat(a)) ) {
+ return ( a == 0x7fffffff ) ? u3i_word(a + 1) : (a + 1);
+ }
+ else if ( _(u3a_is_cell(a)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ mpz_t a_mp;
+
+ u3r_mp(a_mp, a);
+ u3z(a);
+
+ mpz_add_ui(a_mp, a_mp, 1);
+ return u3i_mp(a_mp);
+ }
+}
+
+/* u3i_defcons(): allocate cell for deferred construction.
+** NB: [hed] and [tel] pointers MUST be filled.
+*/
+u3_cell
+u3i_defcons(u3_noun** hed, u3_noun** tel)
+{
+ u3_noun pro;
+
+ u3t_on(mal_o);
+ {
+ c3_w* nov_w = u3a_celloc();
+ u3a_cell* nov_u = (void *)nov_w;
+
+ nov_u->use_w = 1;
+ nov_u->mug_w = 0;
+
+#ifdef U3_MEMORY_DEBUG
+ nov_u->hed = u3_none;
+ nov_u->tel = u3_none;
+#endif
+
+ *hed = &nov_u->hed;
+ *tel = &nov_u->tel;
+
+ pro = u3a_to_pom(u3a_outa(nov_w));
+ }
+ u3t_off(mal_o);
+
+ return pro;
+}
+
+/* u3i_cell(): Produce the cell `[a b]`.
+*/
+u3_noun
+u3i_cell(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+
+ u3t_on(mal_o);
+ {
+ c3_w* nov_w = u3a_celloc();
+ u3a_cell* nov_u = (void *)nov_w;
+
+ nov_u->use_w = 1;
+ nov_u->mug_w = 0;
+ nov_u->hed = a;
+ nov_u->tel = b;
+
+ pro = u3a_to_pom(u3a_outa(nov_w));
+ }
+ u3t_off(mal_o);
+
+ return pro;
+}
+
+/* u3i_trel(): Produce the triple `[a b c]`.
+*/
+u3_noun
+u3i_trel(u3_noun a, u3_noun b, u3_noun c)
+{
+ return u3i_cell(a, u3i_cell(b, c));
+}
+
+/* u3i_qual(): Produce the cell `[a b c d]`.
+*/
+u3_noun
+u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d)
+{
+ return u3i_cell(a, u3i_trel(b, c, d));
+}
+
+/* u3i_string(): Produce an LSB-first atom from the C string [a].
+*/
+u3_atom
+u3i_string(const c3_c* a_c)
+{
+ return u3i_bytes(strlen(a_c), (c3_y *)a_c);
+}
+
+/* u3i_tape(): from a C string, to a list of bytes.
+*/
+u3_noun
+u3i_tape(const c3_c* txt_c)
+{
+ if ( !*txt_c ) {
+ return u3_nul;
+ } else return u3i_cell(*txt_c, u3i_tape(txt_c + 1));
+}
+
+/* u3i_list(): list from `u3_none`-terminated varargs.
+*/
+u3_noun
+u3i_list(u3_weak som, ...)
+{
+ u3_noun lit = u3_nul;
+ va_list ap;
+
+ if ( u3_none == som ) {
+ return lit;
+ }
+ else {
+ lit = u3nc(som, lit);
+ }
+
+ {
+ u3_noun tem;
+
+ va_start(ap, som);
+ while ( 1 ) {
+ if ( u3_none == (tem = va_arg(ap, u3_weak)) ) {
+ break;
+ }
+ else {
+ lit = u3nc(tem, lit);
+ }
+ }
+ va_end(ap);
+ }
+
+ return u3kb_flop(lit);
+}
+
+/* u3i_edit():
+**
+** Mutate `big` at axis `axe` with new value `som`.
+** `axe` is RETAINED.
+*/
+u3_noun
+u3i_edit(u3_noun big, u3_noun axe, u3_noun som)
+{
+ u3_noun pro;
+ u3_noun* out = &pro;
+
+ switch ( axe ) {
+ case 0: return u3m_bail(c3__exit);
+ case 1: break;
+
+ default: {
+ c3_w dep_w = u3r_met(0, u3x_atom(axe)) - 2;
+ const c3_w* axe_w = ( c3y == u3a_is_cat(axe) )
+ ? &axe
+ : ((u3a_atom*)u3a_to_ptr(axe))->buf_w;
+
+ do {
+ u3a_cell* big_u = u3a_to_ptr(big);
+ u3_noun* old = (u3_noun*)&(big_u->hed);
+ const c3_y bit_y = 1 & (axe_w[dep_w >> 5] >> (dep_w & 31));
+
+ if ( c3n == u3a_is_cell(big) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( c3y == u3a_is_mutable(u3R, big) ) {
+ *out = big;
+ out = &(old[bit_y]);
+ big = *out;
+ big_u->mug_w = 0;
+ }
+ else {
+ u3_noun luz = big;
+ u3_noun* new[2];
+
+ *out = u3i_defcons(&new[0], &new[1]);
+ out = new[bit_y];
+ big = u3k(old[bit_y]);
+ *(new[!bit_y]) = u3k(old[!bit_y]);
+
+ u3z(luz);
+ }
+ }
+ while ( dep_w-- );
+ }
+ }
+
+ u3z(big);
+ *out = som;
+ return pro;
+}
+
+/* u3i_molt():
+**
+** Mutate `som` with a 0-terminated list of axis, noun pairs.
+** Axes must be cats (31 bit).
+*/
+ struct _molt_pair {
+ c3_w axe_w;
+ u3_noun som;
+ };
+
+ static c3_w
+ _molt_cut(c3_w len_w,
+ struct _molt_pair* pms_m)
+ {
+ c3_w i_w, cut_t, cut_w;
+
+ cut_t = 0;
+ cut_w = 0;
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w axe_w = pms_m[i_w].axe_w;
+
+ if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) {
+ cut_t = 1;
+ cut_w = i_w;
+ }
+ pms_m[i_w].axe_w = u3x_mas(axe_w);
+ }
+ return cut_t ? cut_w : i_w;
+ }
+
+ static u3_noun // transfer
+ _molt_apply(u3_noun som, // retain
+ c3_w len_w,
+ struct _molt_pair* pms_m) // transfer
+ {
+ if ( len_w == 0 ) {
+ return u3k(som);
+ }
+ else if ( (len_w == 1) && (1 == pms_m[0].axe_w) ) {
+ return pms_m[0].som;
+ }
+ else {
+ c3_w cut_w = _molt_cut(len_w, pms_m);
+
+ if ( c3n == u3a_is_cell(som) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_cell
+ (_molt_apply(u3a_h(som), cut_w, pms_m),
+ _molt_apply(u3a_t(som), (len_w - cut_w), (pms_m + cut_w)));
+ }
+ }
+ }
+
+u3_noun
+u3i_molt(u3_noun som, ...)
+{
+ va_list ap;
+ c3_w len_w;
+ struct _molt_pair* pms_m;
+ u3_noun pro;
+
+ // Count.
+ //
+ len_w = 0;
+ {
+ va_start(ap, som);
+ while ( 1 ) {
+ if ( 0 == va_arg(ap, c3_w) ) {
+ break;
+ }
+ va_arg(ap, u3_weak*);
+ len_w++;
+ }
+ va_end(ap);
+ }
+
+ u3_assert( 0 != len_w );
+ pms_m = alloca(len_w * sizeof(struct _molt_pair));
+
+ // Install.
+ //
+ {
+ c3_w i_w;
+
+ va_start(ap, som);
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ pms_m[i_w].axe_w = va_arg(ap, c3_w);
+ pms_m[i_w].som = va_arg(ap, u3_noun);
+ }
+ va_end(ap);
+ }
+
+ // Apply.
+ //
+ pro = _molt_apply(som, len_w, pms_m);
+ u3z(som);
+ return pro;
+}
diff --git a/vere/pkg/noun/imprison.h b/vere/pkg/noun/imprison.h
new file mode 100644
index 0000000..6d2dcb1
--- /dev/null
+++ b/vere/pkg/noun/imprison.h
@@ -0,0 +1,170 @@
+/// @file
+
+#ifndef U3_IMPRISON_H
+#define U3_IMPRISON_H
+
+#include "allocate.h"
+#include "c3/c3.h"
+#include "gmp.h"
+#include "types.h"
+
+ /** Structures.
+ **/
+ /* u3i_slab: atom builder.
+ */
+ typedef struct _u3i_slab {
+ struct { // internals
+ u3a_atom* _vat_u; // heap atom (nullable)
+ c3_w _sat_w; // static storage
+ } _; //
+ union { //
+ c3_y* buf_y; // bytes
+ c3_w* buf_w; // words
+ }; //
+ c3_w len_w; // word length
+ } u3i_slab;
+
+ /* staged atom-building api
+ */
+ /* u3i_slab_init(): configure bloq-length slab, zero-initialize.
+ */
+ void
+ u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
+
+ /* u3i_slab_bare(): configure bloq-length slab, uninitialized.
+ */
+ void
+ u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
+
+ /* u3i_slab_from(): configure bloq-length slab, initialize with [a].
+ */
+ void
+ u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d);
+
+ /* u3i_slab_grow(): resize slab, zero-initializing new space.
+ */
+ void
+ u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
+
+ /* u3i_slab_free(): dispose memory backing slab.
+ */
+ void
+ u3i_slab_free(u3i_slab* sab_u);
+
+ /* u3i_slab_mint(): produce atom from slab, trimming.
+ */
+ u3_atom
+ u3i_slab_mint(u3i_slab* sab_u);
+
+ /* u3i_slab_moot(): produce atom from slab, no trimming.
+ */
+ u3_atom
+ u3i_slab_moot(u3i_slab* sab_u);
+
+ /* u3i_slab_mint_bytes(): produce atom from byte-slab, trimming.
+ ** XX assumes little-endian, implement swap to support big-endian
+ */
+# define u3i_slab_mint_bytes u3i_slab_mint
+
+ /* u3i_slab_moot_bytes(): produce atom from byte-slab, no trimming.
+ ** XX assumes little-endian, implement swap to support big-endian
+ */
+# define u3i_slab_moot_bytes u3i_slab_moot
+
+ /* General constructors.
+ */
+ /* u3i_word(): construct u3_atom from c3_w.
+ */
+ u3_atom
+ u3i_word(c3_w dat_w);
+
+ /* u3i_chub(): construct u3_atom from c3_d.
+ */
+ u3_atom
+ u3i_chub(c3_d dat_d);
+
+ /* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom.
+ */
+ u3_atom
+ u3i_bytes(c3_w a_w,
+ const c3_y* b_y);
+
+ /* u3i_words(): Copy [a] words from [b] into an atom.
+ */
+ u3_atom
+ u3i_words(c3_w a_w,
+ const c3_w* b_w);
+
+ /* u3i_chubs(): Copy [a] chubs from [b] into an atom.
+ */
+ u3_atom
+ u3i_chubs(c3_w a_w,
+ const c3_d* b_d);
+
+ /* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it.
+ */
+ u3_atom
+ u3i_mp(mpz_t a_mp);
+
+ /* u3i_vint(): increment [a].
+ */
+ u3_atom
+ u3i_vint(u3_noun a);
+
+ /* u3i_cell(): Produce the cell `[a b]`.
+ */
+ u3_noun
+ u3i_cell(u3_noun a, u3_noun b);
+# define u3nc(a, b) u3i_cell(a, b)
+
+ /* u3i_defcons(): allocate cell for deferred construction.
+ ** NB: [hed] and [tel] pointers MUST be filled.
+ */
+ u3_cell
+ u3i_defcons(u3_noun** hed, u3_noun** tel);
+
+ /* u3i_trel(): Produce the triple `[a b c]`.
+ */
+ u3_noun
+ u3i_trel(u3_noun a, u3_noun b, u3_noun c);
+# define u3nt(a, b, c) u3i_trel(a, b, c)
+
+ /* u3i_qual(): Produce the cell `[a b c d]`.
+ */
+ u3_noun
+ u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d);
+# define u3nq(a, b, c, d) u3i_qual(a, b, c, d)
+
+ /* u3i_string(): Produce an LSB-first atom from the C string [a].
+ */
+ u3_atom
+ u3i_string(const c3_c* a_c);
+
+ /* u3i_tape(): from a C string, to a list of bytes.
+ */
+ u3_noun
+ u3i_tape(const c3_c* txt_c);
+
+ /* u3i_list(): list from `u3_none`-terminated varargs.
+ */
+ u3_noun
+ u3i_list(u3_weak som, ...);
+# define u3nl u3i_list
+
+ /* u3i_edit():
+ **
+ ** Mutate `big` at axis `axe` with new value `som`
+ ** `axe` is RETAINED.
+ */
+ u3_noun
+ u3i_edit(u3_noun big, u3_noun axe, u3_noun som);
+
+ /* u3i_molt():
+ **
+ ** Mutate `som` with a 0-terminated list of axis, noun pairs.
+ ** Axes must be cats (31 bit).
+ */
+ u3_noun
+ u3i_molt(u3_noun som, ...);
+
+#endif /* ifndef U3_IMPRISON_H */
diff --git a/vere/pkg/noun/jets.c b/vere/pkg/noun/jets.c
new file mode 100644
index 0000000..3598364
--- /dev/null
+++ b/vere/pkg/noun/jets.c
@@ -0,0 +1,2445 @@
+/// @file
+
+#include "jets.h"
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "log.h"
+#include "manage.h"
+#include "nock.h"
+#include "options.h"
+#include "retrieve.h"
+#include "serial.h"
+#include "trace.h"
+#include "urcrypt.h"
+#include "vortex.h"
+#include "xtract.h"
+
+
+/** Functions.
+**/
+
+/* _cj_count(): count and link dashboard entries.
+*/
+static c3_w
+_cj_count(u3j_core* par_u, u3j_core* dev_u)
+{
+ c3_w len_l = 0;
+ c3_w i_w;
+
+ if ( dev_u ) {
+ for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) {
+ u3j_core* kid_u = &dev_u[i_w];
+
+ if ( par_u ) {
+ kid_u->par_u = par_u;
+ }
+ len_l += _cj_count(kid_u, kid_u->dev_u);
+ }
+ }
+ return 1 + len_l;
+}
+
+/* _cj_core_loc(): location noun from u3j_core.
+ */
+static u3_noun
+_cj_core_loc(u3_noun pel, u3j_core* cop_u)
+{
+ c3_w i_w;
+ u3_noun nam = u3i_string(cop_u->cos_c),
+ huc = u3_nul,
+ pat;
+
+ if ( cop_u->huc_u ) {
+ for ( i_w = 0; 0 != cop_u->huc_u[i_w].nam_c; ++i_w ) {
+ u3j_hood* huc_u = &(cop_u->huc_u[i_w]);
+ u3_noun fol = ( c3n == huc_u->kic_o )
+ ? u3nc(0, huc_u->axe_l)
+ : u3nt(9, huc_u->axe_l, u3nc(0,
+ (0 == huc_u->sax_l) ? 1 : huc_u->sax_l));
+ huc = u3kdb_put(huc, u3i_string(huc_u->nam_c), fol);
+ }
+ }
+
+ pat = ( 0 == cop_u->axe_l )
+ ? u3nt(c3y, c3y, pel)
+ : ( (3 == cop_u->axe_l) && (c3y == u3h(u3h(pel))) )
+ ? u3nt(c3y, c3n, pel)
+ : u3nt(c3n, cop_u->axe_l, pel);
+
+ return u3nt(pat, nam, huc);
+}
+
+/* _cj_hash(): noun from pasted-in battery hash
+ */
+static u3_noun
+_cj_hash(c3_c* has_c)
+{
+ c3_w i_w, len_w = strlen(has_c);
+ if ( 64 != len_w ) {
+ u3l_log("bash not 64 characters: %s", has_c);
+ u3_assert(0);
+ }
+ u3_assert( 64 == len_w );
+ c3_y dig_y[32];
+ for ( i_w = 0; i_w < 64; ) {
+ c3_y hi_y = has_c[i_w++],
+ lo_y = has_c[i_w++],
+ hid_y = hi_y >= 'a' ? (hi_y - 'a') + 10 : hi_y - '0',
+ lod_y = lo_y >= 'a' ? (lo_y - 'a') + 10 : lo_y - '0';
+ dig_y[32-(i_w>>1)] = hid_y << 4 | lod_y;
+ }
+ u3_noun pro = u3i_bytes(32, dig_y);
+ return pro;
+}
+
+// in the jam jet file
+c3_w* u3qe_jam_buf(u3_noun, c3_w* bit_w);
+
+/* _cj_bash(): battery hash. RETAIN.
+ */
+static u3_noun
+_cj_bash(u3_noun bat)
+{
+ if ( u3C.wag_w & u3o_hashless ) {
+ return u3_nul;
+ }
+
+ u3_weak pro;
+ u3a_road* rod_u = u3R;
+ while ( 1 ) {
+ pro = u3h_get(rod_u->jed.bas_p, bat);
+
+ if ( u3_none != pro ) {
+ break;
+ }
+
+ if ( rod_u->par_p ) {
+ rod_u = u3to(u3_road, rod_u->par_p);
+ }
+ else {
+ u3i_slab sab_u;
+ c3_w bit_w = u3s_jam_fib(&sab_u, bat);
+ c3_w met_w = (bit_w + 0x7) >> 3;
+ // XX assumes little-endian
+ //
+ c3_y* fat_y = sab_u.buf_y;
+ c3_y dig_y[32];
+ urcrypt_shay(fat_y, met_w, dig_y);
+
+ pro = u3i_bytes(32, dig_y);
+ u3h_put(u3R->jed.bas_p, bat, u3k(pro));
+ u3i_slab_free(&sab_u);
+ break;
+ }
+ }
+ return pro;
+}
+
+/* _cj_mine_par_old(): register hooks and parent location within existing
+ * axis in ancestor list or u3_none.
+ */
+static u3_weak
+_cj_mine_par_old(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc)
+{
+ u3_noun par;
+ u3_weak pro;
+
+ if ( u3_nul == lan ) {
+ pro = u3_none;
+ u3z(axe); u3z(pel); u3z(loc);
+ }
+ else if ( c3y == u3r_sing(axe, u3h(par = u3h(lan))) ) {
+ u3_noun lol = u3kdb_put(u3k(u3t(par)), pel, loc),
+ rap = u3nc(axe, lol);
+ pro = u3nc(rap, u3k(u3t(lan)));
+ }
+ else {
+ u3_weak nex = _cj_mine_par_old(u3k(u3t(lan)), axe, pel, loc);
+ if ( u3_none == nex ) {
+ pro = u3_none;
+ }
+ else {
+ pro = u3nc(u3k(par), nex);
+ }
+ }
+
+ u3z(lan);
+ return pro;
+}
+
+/* _cj_mine_par_new(): insert ancestor within lan at sorted index.
+ */
+static u3_noun
+_cj_mine_par_new(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc)
+{
+ u3_weak pro;
+
+ if ( (u3_nul == lan) || (c3y == u3qa_lth(axe, u3h(u3h(lan)))) ) {
+ u3_noun par = u3nc(axe, u3kdb_put(u3_nul, pel, loc));
+ pro = u3nc(par, lan);
+ }
+ else {
+ pro = u3nc(u3k(u3h(lan)),
+ _cj_mine_par_new(u3k(u3t(lan)), axe, pel, loc));
+ u3z(lan);
+ }
+
+ return pro;
+}
+
+/* _cj_mine_par(): register a location as an ancestor
+ * in a list of ancestors.
+ */
+static u3_noun
+_cj_mine_par(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc)
+{
+ u3_weak old = _cj_mine_par_old(u3k(lan), u3k(axe), u3k(pel), u3k(loc));
+ if ( u3_none != old ) {
+ u3z(lan); u3z(axe); u3z(pel); u3z(loc);
+ return old;
+ }
+ else {
+ return _cj_mine_par_new(lan, axe, pel, loc);
+ }
+}
+
+
+/* _cj_gust(): add location to registry.
+*/
+static u3_noun
+_cj_gust(u3_weak reg, u3_noun axe, u3_noun pel, u3_noun loc)
+{
+ u3_noun ger;
+ if ( u3_none == reg ) {
+ reg = u3nc(u3_nul, u3_nul);
+ }
+
+ ger = ( 0 == axe )
+ ? u3nc(u3kdb_put(u3k(u3h(reg)), pel, loc), u3k(u3t(reg)))
+ : u3nc(u3k(u3h(reg)), _cj_mine_par(u3k(u3t(reg)), axe, pel, loc));
+
+ u3z(reg);
+ return ger;
+}
+
+/* _cj_axis(): axis from formula, or 0. `fol` is RETAINED.
+*/
+static c3_l
+_cj_axis(u3_noun fol)
+{
+ u3_noun p_fol, q_fol, r_fol;
+
+ while ( _(u3du(fol)) && (11 == u3h(fol)) )
+ { fol = u3t(u3t(fol)); }
+
+ if ( !_(u3r_trel(fol, &p_fol, &q_fol, &r_fol)) ) {
+ if ( !_(u3r_cell(fol, &p_fol, &q_fol)) ||
+ (0 != p_fol) ||
+ (!_(u3a_is_cat(q_fol))) )
+ {
+ u3l_log("axis: bad a");
+ return 0;
+ }
+ return q_fol;
+ }
+ else {
+ if ( 9 != p_fol )
+ { u3l_log("axis: bad b"); return 0; }
+ if ( !_(u3a_is_cat(q_fol)) )
+ { u3l_log("axis: bad c"); return 0; }
+ if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) )
+ { u3l_log("axis: bad d"); return 0; }
+
+ return q_fol;
+ }
+}
+
+/* _cj_warm_hump(): generate axis-to-arm map. RETAIN.
+*/
+static u3_noun
+_cj_warm_hump(c3_l jax_l, u3_noun huc)
+{
+ u3_noun hap = u3_nul;
+ u3j_core* cop_u;
+
+ /* Compute axes of all correctly declared arms.
+ */
+ if ( jax_l && (cop_u = &u3D.ray_u[jax_l])->arm_u ) {
+ u3j_harm* jet_u;
+ c3_l i_l;
+
+ for ( i_l = 0; (jet_u = &cop_u->arm_u[i_l])->fcs_c; i_l++ ) {
+ c3_l axe_l = 0;
+
+ if ( '.' == *(jet_u->fcs_c) ) {
+ c3_d axe_d = 0;
+
+ if ( (1 != sscanf(jet_u->fcs_c+1, "%" SCNu64, &axe_d)) ||
+ axe_d >> 32ULL ||
+ (((c3_w)1 << 31) & (axe_l = (c3_w)axe_d)) ||
+ (axe_l < 2) )
+ {
+ u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c);
+ }
+ }
+ else {
+ u3_noun nam = u3i_string(jet_u->fcs_c);
+ u3_noun fol = u3kdb_get(u3k(huc), nam);
+
+ if ( u3_none == fol ) {
+ u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c);
+ }
+ else {
+ axe_l = _cj_axis(fol);
+ u3z(fol);
+ }
+ }
+ if ( 0 != axe_l ) {
+ hap = u3kdb_put(hap, axe_l, i_l);
+ }
+ }
+ }
+ return hap;
+}
+
+/* _cj_install(): install dashboard entries.
+*/
+static c3_w
+_cj_install(u3j_core* ray_u, c3_w jax_l, u3_noun pel, u3_noun lab, u3j_core* dev_u)
+{
+ c3_w i_w;
+ u3_assert(u3R == &(u3H->rod_u));
+
+ if ( dev_u ) {
+ for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) {
+ u3j_core* kid_u = &dev_u[i_w];
+ u3_noun loc = _cj_core_loc(u3k(pel), kid_u),
+ bal = u3nc(u3k(u3h(u3t(loc))), u3k(lab));
+
+ kid_u->jax_l = jax_l;
+ ray_u[jax_l] = *kid_u;
+
+ if ( kid_u->bas_u ) {
+ c3_w j_w;
+ for ( j_w = 0; 0 != kid_u->bas_u[j_w]; j_w++ ) {
+ u3_noun key = _cj_hash(kid_u->bas_u[j_w]),
+ hot = u3h_git(u3R->jed.hot_p, key),
+ old = ( u3_none == hot ) ? u3_none : u3k(u3h(hot)),
+ reg = _cj_gust(old, kid_u->axe_l, u3k(pel), u3k(loc)),
+ huc = u3t(u3t(loc)),
+ hap = _cj_warm_hump(jax_l, huc),
+ toh = u3nq(reg, jax_l, hap, u3k(bal));
+
+ u3h_put(u3R->jed.hot_p, key, toh);
+ u3z(key);
+ }
+ }
+
+ jax_l = _cj_install(ray_u, ++jax_l, loc, bal, kid_u->dev_u);
+ }
+ }
+ u3z(pel);
+ u3z(lab);
+ return jax_l;
+}
+
+#if 0
+/* _cj_by_gut(): (~(get by a) b), unifying; RETAINS a, b, AND result.
+*/
+static u3_weak
+_cj_by_gut(u3_noun a, u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3_none;
+ }
+ else {
+ u3_noun l_a, n_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);
+ {
+ if ( (c3y == u3r_sing(b, pn_a)) ) {
+ return qn_a;
+ }
+ else {
+ if ( c3y == u3qc_gor(b, pn_a) ) {
+ return _cj_by_gut(l_a, b);
+ }
+ else return _cj_by_gut(r_a, b);
+ }
+ }
+ }
+}
+#endif
+
+/* _cj_chum(): decode chum as string.
+*/
+static c3_c*
+_cj_chum(u3_noun chu)
+{
+ if ( _(u3ud(chu)) ) {
+ return u3r_string(chu);
+ }
+ else {
+ u3_noun h_chu = u3h(chu);
+ u3_noun t_chu = u3t(chu);
+
+ if ( !_(u3a_is_cat(t_chu)) ) {
+ return 0;
+ } else {
+ c3_c* h_chu_c = u3r_string(h_chu);
+ c3_c buf[33];
+
+ memset(buf, 0, 33);
+ snprintf(buf, 32, "%s%d", h_chu_c, t_chu);
+
+ c3_free(h_chu_c);
+ return strdup(buf);
+ }
+ }
+}
+
+/* _cj_je_fsck: fsck:je, or none.
+*/
+static u3_noun
+_cj_je_fsck(u3_noun clu)
+{
+ u3_noun p_clu, q_clu, r_clu;
+ u3_noun huk;
+ c3_c* nam_c;
+ c3_l axe_l;
+
+ if ( c3n == u3r_trel(clu, &p_clu, &q_clu, &r_clu) ) {
+ u3z(clu); return u3_none;
+ }
+ if ( 0 == (nam_c = _cj_chum(p_clu)) ) {
+ u3z(clu); return u3_none;
+ }
+ while ( _(u3du(q_clu)) && (11 == u3h(q_clu)) ) {
+ q_clu = u3t(u3t(q_clu));
+ }
+ if ( !_(u3du(q_clu)) ) {
+ u3z(clu); c3_free(nam_c); return u3_none;
+ }
+
+ if ( (1 == u3h(q_clu)) && (0 == u3t(q_clu)) ) {
+ axe_l = 0;
+ }
+ else {
+ if ( (0 != u3h(q_clu)) || !_(u3a_is_cat(axe_l = u3t(q_clu))) ) {
+ u3z(clu); c3_free(nam_c); return u3_none;
+ }
+ }
+
+ {
+ huk = 0;
+
+ while ( _(u3du(r_clu)) ) {
+ u3_noun ir_clu, tr_clu, pir_clu, qir_clu;
+
+ if ( (c3n == u3r_cell(r_clu, &ir_clu, &tr_clu)) ||
+ (c3n == u3r_cell(ir_clu, &pir_clu, &qir_clu)) ||
+ (c3n == u3ud(pir_clu)) )
+ {
+ u3z(huk); u3z(clu); c3_free(nam_c); return u3_none;
+ }
+ huk = u3kdb_put(huk, u3k(pir_clu), u3k(qir_clu));
+ r_clu = tr_clu;
+ }
+ }
+ u3z(clu);
+
+ {
+ u3_noun pro = u3nt(u3i_string(nam_c), axe_l, huk);
+ c3_free(nam_c);
+ return pro;
+ }
+}
+
+/* _cj_find_cold(): search cold state for `bat`s [bash registry].
+ * RETAIN.
+ */
+static u3_weak
+_cj_find_cold(u3_noun bat)
+{
+ u3a_road* rod_u = u3R;
+
+ while ( 1 ) {
+ u3_weak bar = u3h_get(rod_u->jed.cod_p, bat);
+
+ if ( u3_none != bar ) {
+ return bar;
+ }
+
+ if ( rod_u->par_p ) {
+ rod_u = u3to(u3_road, rod_u->par_p);
+ }
+ else return u3_none;
+ }
+}
+
+/* _cj_find_warm(): search warm state for `loc`s activation.
+ * RETAIN.
+ */
+static u3_weak
+_cj_find_warm(u3_noun loc)
+{
+ u3a_road* rod_u = u3R;
+
+ while ( 1 ) {
+ u3_weak ank = u3h_get(rod_u->jed.war_p, loc);
+
+ if ( u3_none != ank ) {
+ return ank;
+ }
+
+ if ( rod_u->par_p ) {
+ rod_u = u3to(u3_road, rod_u->par_p);
+ }
+ else return u3_none;
+ }
+}
+
+static u3_weak _cj_spot(u3_noun cor, u3_weak* bas);
+
+/* _cj_reg_find(): locate core within registry. RETAIN.
+ */
+static u3_weak
+_cj_reg_find(u3_noun reg, u3_noun cor)
+{
+ u3_noun rut = u3h(reg),
+ pas = u3t(reg),
+ rum = u3qdb_get(rut, u3t(cor));
+ if ( u3_nul != rum ) {
+ u3_noun loc = u3k(u3t(rum));
+ u3z(rum);
+ return loc;
+ }
+ else {
+ while ( u3_nul != pas ) {
+ u3_noun pap = u3h(pas),
+ axe = u3h(pap),
+ lol = u3t(pap);
+ u3_weak par = u3r_at(axe, cor),
+ pel;
+ if ( u3_none != par ) {
+ pel = _cj_spot(par, NULL);
+ if ( u3_none != pel ) {
+ u3_noun nit = u3qdb_get(lol, pel);
+ u3z(pel);
+ if ( u3_nul != nit ) {
+ u3_noun loc = u3k(u3t(nit));
+ u3z(nit);
+ return loc;
+ }
+ }
+ }
+ pas = u3t(pas);
+ }
+ return u3_none;
+ }
+}
+
+/* _cj_jit(): generate arbitrary warm jet-associated data. RETAIN.
+*/
+static u3_noun
+_cj_jit(c3_l jax_l, u3_noun bat)
+{
+ return u3_nul;
+}
+
+/* _cj_loc_axe(): axis-within-core from location (0 for root). RETAIN.
+ */
+static u3_noun
+_cj_loc_axe(u3_noun loc)
+{
+ u3_noun pat = u3h(loc);
+ return ( c3n == u3h(pat) )
+ ? u3k(u3h(u3t(pat)))
+ : (c3y == u3h(u3t(pat))) ? 0 : 3;
+}
+
+/* _cj_loc_pel(): parent location (or root noun, if root) of loc. RETAIN.
+ */
+static u3_noun
+_cj_loc_pel(u3_noun loc)
+{
+ return u3k(u3t(u3t(u3h(loc))));
+}
+
+/* _cj_spot_cold(): spot, cold dashboard only. *bar is set to
+ * the [bash registry] found for battery. RETAIN.
+ */
+static u3_weak
+_cj_spot_cold(u3_noun cor, u3_weak* bar)
+{
+ *bar = _cj_find_cold(u3h(cor));
+ if ( u3_none == *bar ) {
+ return u3_none;
+ }
+ else {
+ return _cj_reg_find(u3t(*bar), cor);
+ }
+}
+
+/* _cj_spot_hot(): try to locate core by hot dashboard. if found,
+ * the activation (warm state) is returned and the
+ * location is produced at *loc. RETAIN.
+ */
+static u3_weak
+_cj_spot_hot(u3_noun cor, u3_noun bas, u3_noun* loc)
+{
+ u3_noun bat = u3h(cor);
+ u3_weak act = u3_none,
+ hot = u3h_get(u3H->rod_u.jed.hot_p, bas);
+ if ( u3_none != hot ) {
+ u3_noun reg, jax, hap, bal;
+ c3_l jax_l;
+ u3x_qual(hot, &reg, &jax, &hap, &bal);
+ jax_l = (c3_l) jax;
+ if ( u3_none != (*loc = _cj_reg_find(reg, cor)) ) {
+ act = u3nq(jax_l, u3k(hap), u3k(bal), _cj_jit(jax_l, bat));
+ }
+ u3z(hot);
+ }
+ return act;
+}
+
+/* _cj_spot(): find location of cor. expensive. RETAIN.
+ * bas is complicated to make it easy to cache bashes.
+ * you can safely ignore it by passing NULL. Otherwise,
+ * if it points to u3_none, and no location is found,
+ * a bash will be PRODUCED there. if it contains a bash,
+ * that will be used instead of calling _cj_bash.
+ */
+static u3_weak
+_cj_spot(u3_noun cor, u3_weak* bas)
+{
+ u3_weak bak = u3_none,
+ bar = u3_none,
+ reg = u3_none,
+ loc = _cj_spot_cold(cor, &bar);
+
+ if ( NULL == bas ) {
+ bas = &bak;
+ }
+
+ if ( u3_none != bar ) {
+ if ( (u3_none == *bas) ) {
+ *bas = u3k(u3h(bar));
+ }
+ reg = u3k(u3t(bar));
+ u3z(bar);
+ }
+
+ if ( u3_none == loc ) {
+ if ( u3_none == *bas ) {
+ *bas = _cj_bash(u3h(cor));
+ }
+
+ if ( !(u3C.wag_w & u3o_hashless) ) {
+ u3_weak act = _cj_spot_hot(cor, *bas, &loc);
+ if ( u3_none != act ) {
+ reg = _cj_gust(reg, _cj_loc_axe(loc), _cj_loc_pel(loc), u3k(loc));
+ u3h_put(u3R->jed.cod_p, u3h(cor), u3nc(u3k(*bas), u3k(reg)));
+ /* caution: could overwrites old value, debug batteries etc.
+ ** old value contains old _cj_jit (from different
+ ** battery). if we change jit to (map battery *),
+ ** will need to merge with that map here.
+ */
+ u3h_put(u3R->jed.war_p, loc, act);
+ }
+ }
+ }
+ if ( u3_none != bak ) {
+ u3z(bak);
+ }
+ if ( u3_none != reg ) {
+ u3z(reg);
+ }
+ return loc;
+}
+
+/* _cj_cast(): create a u3j_fink that can be used to efficiently verify
+ * that another core is located where this one is. RETAIN.
+ */
+static u3p(u3j_fink)
+_cj_cast(u3_noun cor, u3_noun loc)
+{
+ c3_w i_w = 0;
+ u3_noun j, par, bat, dyn, pax,
+ rev = u3_nul,
+ pat = u3h(loc);
+ u3j_fink* fin_u;
+
+ while ( c3n == u3h(pat) ) {
+ bat = u3h(cor);
+ dyn = u3t(pat);
+ pax = u3h(dyn);
+ loc = u3t(dyn);
+ pat = u3h(loc);
+ rev = u3nc(u3nc(u3k(bat), u3k(pax)), rev);
+ // pax already known-valid
+ cor = u3r_at(pax, cor);
+ ++i_w;
+ }
+
+ fin_u = u3a_walloc(c3_wiseof(u3j_fink) +
+ (i_w * c3_wiseof(u3j_fist)));
+ fin_u->len_w = i_w;
+ fin_u->sat = u3k(cor);
+ for ( j = rev; i_w-- > 0; j = u3t(j) ) {
+ u3j_fist* fis_u = &(fin_u->fis_u[i_w]);
+ par = u3h(j);
+ fis_u->bat = u3k(u3h(par));
+ fis_u->pax = u3k(u3t(par));
+ }
+ u3z(rev);
+ u3_assert( u3_nul == j );
+
+ return u3of(u3j_fink, fin_u);
+}
+
+/* _cj_fine(): check that a core matches a u3j_fink. RETAIN.
+ */
+static c3_o
+_cj_fine(u3_noun cor, u3p(u3j_fink) fin_p)
+{
+ u3j_fink* fin_u = u3to(u3j_fink, fin_p);
+ c3_w i_w;
+ for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) {
+ u3j_fist* fis_u = &(fin_u->fis_u[i_w]);
+ if ( c3n == u3r_sing(fis_u->bat, u3h(cor)) ) {
+ return c3n;
+ }
+ else {
+ cor = u3r_at(fis_u->pax, cor);
+ }
+ }
+ return u3r_sing(fin_u->sat, cor);
+}
+
+/* _cj_nail(): resolve hot state for arm at axis within cores located
+ * at loc. a label will be PRODUCED at *lab, unconditionally.
+ * Arguments are RETAINED. Return value is yes if a jet driver
+ * is present.
+ */
+static c3_o
+_cj_nail(u3_noun loc, u3_noun axe,
+ u3_noun* lab, u3j_core** cop_u, u3j_harm** ham_u)
+{
+ c3_o ret_o;
+ u3_noun jax, hap, bal, jit;
+ u3_weak act;
+ act = _cj_find_warm(loc);
+ u3_assert(u3_none != act);
+ u3x_qual(act, &jax, &hap, &bal, &jit);
+
+ *lab = u3k(bal);
+ if ( 0 == jax ) {
+ ret_o = c3n;
+ }
+ else {
+ u3_weak inx = u3kdb_get(u3k(hap), u3k(axe));
+ if ( u3_none == inx ) {
+ ret_o = c3n;
+ }
+ else {
+ c3_l jax_l = jax,
+ inx_l = inx;
+ *cop_u = &(u3D.ray_u[jax_l]);
+ *ham_u = &((*cop_u)->arm_u[inx_l]);
+ ret_o = c3y;
+ }
+ }
+
+ u3z(act);
+ return ret_o;
+}
+
+/* _cj_hot_mean(): in parent, declare a core. RETAINS.
+*/
+static c3_l
+_cj_hot_mean(c3_l par_l, u3_noun nam)
+{
+ u3j_core* par_u;
+ u3j_core* dev_u;
+
+ if ( 0 != par_l ) {
+ par_u = &u3D.ray_u[par_l];
+ dev_u = par_u->dev_u;
+ }
+ else {
+ par_u = 0;
+ dev_u = u3D.dev_u;
+ }
+
+ {
+ c3_w i_l = 0;
+ u3j_core* cop_u;
+
+ while ( (cop_u = &dev_u[i_l])->cos_c ) {
+ if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) {
+#if 0
+ u3l_log("hot: bound jet %d/%s/%s/",
+ cop_u->jax_l,
+ cop_u->cos_c,
+ par_u ? par_u->cos_c : "~");
+#endif
+ return cop_u->jax_l;
+ }
+ i_l++;
+ }
+ }
+ return 0;
+}
+
+/* u3j_boot(): initialize jet system.
+*/
+c3_w
+u3j_boot(c3_o nuu_o)
+{
+ u3_assert(u3R == &(u3H->rod_u));
+
+ u3D.len_l = _cj_count(0, u3D.dev_u);
+ u3D.all_l = (2 * u3D.len_l) + 1024; // horrid heuristic
+
+ u3D.ray_u = c3_malloc(u3D.all_l * sizeof(u3j_core));
+ memset(u3D.ray_u, 0, (u3D.all_l * sizeof(u3j_core)));
+
+ if ( c3n == nuu_o ) {
+ u3h_free(u3R->jed.hot_p);
+ }
+ u3R->jed.hot_p = u3h_new();
+
+ return _cj_install(u3D.ray_u, 1,
+ (c3_l) (long long) u3D.dev_u[0].par_u,
+ u3_nul,
+ u3D.dev_u);
+}
+
+/* _cj_soft(): kick softly by arm axis.
+*/
+static u3_noun
+_cj_soft(u3_noun cor, u3_noun axe)
+{
+ u3_noun arm = u3x_at(axe, cor);
+
+ return u3n_nock_on(cor, u3k(arm));
+}
+
+ void
+ find_error(u3_noun cor,
+ u3_noun old,
+ u3_noun new);
+
+/* _cj_kick_z(): try to kick by jet. If no kick, produce u3_none.
+**
+** `cor` is RETAINED iff there is no kick, TRANSFERRED if one.
+** `axe` is RETAINED.
+*/
+static u3_weak
+_cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe)
+{
+ if ( 0 == ham_u->fun_f ) {
+ return u3_none;
+ }
+
+ if ( !_(ham_u->liv) ) {
+ return u3_none;
+ }
+ else {
+#ifdef U3_MEMORY_DEBUG
+ c3_w cod_w;
+
+ {
+ char soc_c[5];
+
+ memset(soc_c, 0, 5);
+ strncpy(soc_c, cop_u->cos_c, 4);
+ soc_c[4] = 0;
+ cod_w = u3i_string(soc_c);
+ cod_w = u3a_lush(cod_w);
+ }
+#endif
+
+ if ( _(ham_u->ice) ) {
+ u3_weak pro = ham_u->fun_f(cor);
+
+#ifdef U3_MEMORY_DEBUG
+ u3a_lop(cod_w);
+#endif
+ if ( u3_none != pro ) {
+ u3z(cor);
+ return pro;
+ }
+ }
+ else {
+ u3_weak pro, ame;
+
+ ham_u->ice = c3y;
+ pro = ham_u->fun_f(cor);
+ ham_u->ice = c3n;
+
+#ifdef U3_MEMORY_DEBUG
+ u3a_lop(cod_w);
+#endif
+ if ( u3_none == pro ) {
+ u3z(cor);
+ return pro;
+ }
+ ham_u->liv = c3n;
+ ame = _cj_soft(cor, axe);
+ ham_u->liv = c3y;
+
+ if ( c3n == u3r_sing(ame, pro) ) {
+ u3l_log("test: %s %s: mismatch: good %x, bad %x",
+ cop_u->cos_c,
+ (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c,
+ u3r_mug(ame),
+ u3r_mug(pro));
+ ham_u->liv = c3n;
+
+ return u3m_bail(c3__fail);
+ }
+ else {
+
+#if 0
+ u3l_log("test: %s %s",
+ cop_u->cos_c,
+ (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c);
+#endif
+ u3z(ame);
+ return pro;
+ }
+ }
+ return u3_none;
+ }
+}
+
+/* _cj_hook_in(): execute hook from core, or fail.
+*/
+static u3_noun
+_cj_hook_in(u3_noun cor,
+ const c3_c* tam_c,
+ c3_o jet_o)
+{
+ u3_weak loc, col;
+ u3_noun roc, tem, got, pat, nam, huc;
+
+ if ( c3n == u3du(cor) ) {
+ u3l_log("_cj_hook_in failure: c3n == u3du(cor)");
+ return u3m_bail(c3__fail);
+ }
+
+ loc = _cj_spot(cor, NULL);
+ if ( u3_none == loc ) {
+ u3l_log("_cj_hook_in failure: u3_none == loc");
+ return u3m_bail(c3__fail);
+ }
+
+ tem = u3i_string(tam_c);
+ while ( 1 ) {
+ u3x_trel(loc, &pat, &nam, &huc);
+ got = u3qdb_get(huc, tem);
+ if ( u3_nul != got ) {
+ c3_l axe_l;
+ u3_noun pro, fol;
+ u3j_core* cop_u;
+
+ u3z(tem);
+ fol = u3k(u3t(got));
+ u3z(got);
+ axe_l = _cj_axis(fol);
+ if ( 0 == axe_l ) {
+ u3t_off(glu_o);
+ pro = u3n_nock_on(cor, fol);
+ u3t_on(glu_o);
+ }
+ else {
+ c3_l jax_l, inx_l;
+ u3_noun hap, act;
+
+ u3z(fol);
+ act = _cj_find_warm(loc);
+ jax_l = u3h(act);
+ hap = u3h(u3t(act));
+ cop_u = &u3D.ray_u[jax_l];
+
+ // Tricky: the above case would work here too, but would
+ // disable jet_o and create some infinite recursions.
+ //
+ u3t_off(glu_o);
+ if ( (c3n == jet_o) ||
+ (u3_none == (inx_l = u3kdb_get(u3k(hap), axe_l))) ||
+ (u3_none == (pro = _cj_kick_z(cor,
+ cop_u,
+ &cop_u->arm_u[inx_l],
+ axe_l))) ) {
+ pro = u3n_nock_on(cor, u3k(u3x_at(axe_l, cor)));
+ }
+ u3t_on(glu_o);
+ u3z(act);
+ }
+ u3z(loc);
+ return pro;
+ }
+ else if ( c3n == u3h(pat) ) {
+ u3_noun dyn = u3t(pat),
+ axe = u3h(dyn),
+ pel = u3t(dyn);
+ // axe already known-valid
+ roc = u3k(u3r_at(axe, cor));
+ u3z(cor);
+ cor = roc;
+ col = u3k(pel);
+ u3z(loc);
+ loc = col;
+ }
+ else {
+ u3_noun sat = u3t(pat);
+ if ( c3y == u3h(sat) ) {
+ u3l_log("_cj_hook_in failure: c3y == u3h(sat)");
+ return u3m_bail(c3__fail);
+ }
+ else {
+ col = u3k(u3t(sat));
+ u3z(loc);
+ loc = col;
+ roc = u3k(u3t(cor));
+ u3z(cor);
+ cor = roc;
+ }
+ }
+ }
+}
+
+/* u3j_soft(): execute soft hook.
+*/
+u3_noun
+u3j_soft(u3_noun cor,
+ const c3_c* tam_c)
+{
+ u3_noun pro;
+ u3t_on(glu_o);
+ pro = _cj_hook_in(cor, tam_c, c3n);
+ u3t_off(glu_o);
+ return pro;
+}
+
+/* u3j_hook(): execute hook from core, or fail.
+*/
+u3_noun
+u3j_hook(u3_noun cor,
+ const c3_c* tam_c)
+{
+ u3_noun pro;
+ u3t_on(glu_o);
+ pro = _cj_hook_in(cor, tam_c, c3y);
+ u3t_off(glu_o);
+ return pro;
+}
+
+/* _cj_prog(): stop tracing glu and find a nock program
+ */
+static u3p(u3n_prog)
+_cj_prog(u3_weak loc, u3_noun fol)
+{
+ u3p(u3n_prog) pog_p;
+ u3t_off(glu_o);
+ pog_p = u3n_find((loc == u3_none ? u3_nul : loc), fol);
+ u3t_on(glu_o);
+ return pog_p;
+}
+
+static inline c3_w
+_cj_of_hank(u3j_hank *han_u)
+{
+ u3_post han_p = u3of(u3j_hank, han_u);
+ return han_p >> u3a_vits;
+}
+
+static inline u3j_hank*
+_cj_to_hank(c3_w han_w)
+{
+ u3_post han_p = han_w << u3a_vits;
+ return u3to(u3j_hank, han_p);
+}
+
+/* cj_hank_find(): find cached hook information, keyed by arbitrary
+ * prefix and term cords. RETAIN.
+ */
+static u3j_hank*
+_cj_hank_find(u3_noun pre, u3_noun tam)
+{
+ u3_noun key = u3nc(u3k(pre), u3k(tam));
+ u3_noun got = u3h_git(u3R->jed.han_p, key);
+
+ if ( u3_none != got ) {
+ u3z(key);
+ return _cj_to_hank(got);
+ }
+ else {
+ u3j_hank* new_u = u3a_walloc(c3_wiseof(u3j_hank));
+ u3a_road* rod_u = u3R;
+
+ while ( rod_u->par_p && u3_none == got ) {
+ rod_u = u3to(u3a_road, rod_u->par_p);
+ got = u3h_git(rod_u->jed.han_p, key);
+ }
+
+ if ( u3_none == got ) {
+ new_u->hax = u3_none;
+ }
+ else {
+ u3j_hank* old_u = _cj_to_hank(got);
+ if ( u3_none != (new_u->hax = old_u->hax) ) {
+ // it's unusual but safe to "take" here, because
+ // u3a_take will no-op on senior nouns (just as u3k would)
+ //
+ u3j_site_take(&(new_u->sit_u), &(old_u->sit_u));
+ }
+ }
+
+ u3h_put(u3R->jed.han_p, key, _cj_of_hank(new_u));
+ u3z(key);
+ return new_u;
+ }
+}
+
+/* _cj_hank_fine(): check that cached hook information is valid
+ * for given core. *inn will point to the hooked
+ * core on return if valid. RETAIN.
+ */
+static c3_o
+_cj_hank_fine(u3j_hank* han_u, u3_noun cor, u3_noun *inn)
+{
+ u3_noun hax = han_u->hax;
+ if ( u3_none == hax ) {
+ return c3n;
+ }
+ else {
+ *inn = u3r_at(hax, cor);
+ if ( u3_none == *inn ) {
+ return c3n;
+ }
+ else {
+ u3j_site* sit_u = &(han_u->sit_u);
+ u3_assert(u3_none != sit_u->loc);
+ return _cj_fine(*inn, sit_u->fin_p);
+ }
+ }
+}
+
+/* _cj_hank_lose(): release memory maintained in a hook cache.
+*/
+static void
+_cj_hank_lose(u3j_hank* han_u)
+{
+ if ( u3_none != han_u->hax ) {
+ u3z(han_u->hax);
+ u3j_site_lose(&(han_u->sit_u));
+ }
+}
+
+/* _cj_hank_fill(): slow path, populate han_u.
+ */
+static u3_noun
+_cj_hank_fill(u3j_hank* han_u, u3_noun tam, u3_noun cor)
+{
+ u3_weak loc, col;
+ u3_noun got, pat, nam, huc;
+ u3_noun hax = 1;
+ u3j_site* sit_u = &(han_u->sit_u);
+
+ if ( c3n == u3du(cor) ) {
+ u3l_log("fail in _cj_hank_fill (c3n == u3du(cor))");
+ return u3m_bail(c3__fail);
+ }
+
+ sit_u->bas = u3_none;
+ if ( u3_none == (col = loc = _cj_spot(cor, NULL)) ) {
+ u3l_log("fail in _cj_hank_fill (_cj_spot(cor, NULL))");
+ return u3m_bail(c3__fail);
+ }
+
+ while ( 1 ) {
+ u3x_trel(loc, &pat, &nam, &huc);
+ got = u3qdb_get(huc, tam);
+ if ( u3_nul != got ) {
+ u3_noun fol = u3k(u3t(got));
+ u3z(got);
+ sit_u->bat = u3k(u3h(cor));
+ sit_u->loc = u3k(loc);
+ sit_u->fin_p = _cj_cast(cor, loc);
+ sit_u->fon_o = c3y;
+ if ( 0 == (sit_u->axe = _cj_axis(fol)) ) {
+ sit_u->jet_o = c3n;
+ sit_u->pog_p = _cj_prog(loc, fol);
+ }
+ else {
+ // loc already known-valid
+ han_u->sit_u.pog_p = _cj_prog(loc, u3r_at(sit_u->axe, cor));
+ han_u->sit_u.jet_o = _cj_nail(loc, sit_u->axe,
+ &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u));
+ }
+ u3z(fol);
+ u3z(col);
+ han_u->hax = hax;
+ return cor;
+ }
+ else if ( c3n == u3h(pat) ) {
+ u3_noun dyn = u3t(pat),
+ axe = u3h(dyn),
+ xah;
+ // axe already known-valid
+ cor = u3r_at(axe, cor);
+ loc = u3t(dyn);
+ xah = u3qc_peg(axe, hax);
+ u3z(hax);
+ hax = xah;
+ }
+ else {
+ u3_noun sat = u3t(pat);
+ if ( c3y == u3h(sat) ) {
+ u3l_log("fail in _cj_hank_fill (c3y == u3h(sat))");
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun xah;
+ cor = u3t(cor);
+ loc = u3t(sat);
+ xah = u3qc_peg(3, hax);
+ u3z(hax);
+ hax = xah;
+ }
+ }
+ }
+}
+
+/* _cj_sink(): kick by nock.
+ */
+static u3_noun
+_cj_sink(u3_noun cor, u3_noun axe)
+{
+ u3_noun fol = u3x_at(axe, cor);
+ u3z(axe);
+ return u3n_nock_on(cor, u3k(fol));
+}
+
+/* u3j_kick(): new kick.
+**
+** `axe` is RETAINED by the caller; `cor` is RETAINED iff there
+** is no kick, TRANSFERRED if one.
+*/
+u3_weak
+u3j_kick(u3_noun cor, u3_noun axe)
+{
+ u3t_on(glu_o);
+ u3_weak loc = _cj_spot(cor, NULL);
+ if ( u3_none == loc ) {
+ u3t_off(glu_o);
+ return u3_none;
+ }
+ else {
+ u3_weak act = _cj_find_warm(loc);
+ u3z(loc);
+ if ( u3_none == act ) {
+ u3t_off(glu_o);
+ return u3_none;
+ }
+ else {
+ c3_l jax_l;
+ u3_noun hap, bal, jit, inx;
+
+ u3x_qual(act, &jax_l, &hap, &bal, &jit);
+
+ if ( u3_none == (inx = u3kdb_get(u3k(hap), u3k(axe))) ) {
+ u3t_off(glu_o);
+ {
+ c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu);
+ c3_o trc_o = __(u3C.wag_w & u3o_trace);
+
+ if ( _(pof_o) ) {
+ pof_o = u3t_come(bal);
+ }
+ if ( _(trc_o) ) {
+ trc_o = u3t_nock_trace_push(bal);
+ }
+ u3z(act);
+ if ( _(pof_o) || _(trc_o) ) {
+ u3_noun pro = _cj_sink(cor, u3k(axe));
+
+ if (_(pof_o)) {
+ u3t_flee();
+ }
+ if ( _(trc_o) ) {
+ u3t_nock_trace_pop();
+ }
+ return pro;
+ }
+ else {
+ return u3_none;
+ }
+ }
+ }
+ else {
+ u3j_core* cop_u = &u3D.ray_u[jax_l];
+ c3_l inx_l = inx;
+ u3j_harm* ham_u = &cop_u->arm_u[inx_l];
+ c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu);
+ c3_o trc_o = __(u3C.wag_w & u3o_trace);
+ u3_noun pro;
+
+ if ( _(pof_o) ) {
+ pof_o = u3t_come(bal);
+ }
+ if ( _(trc_o) ) {
+ trc_o = u3t_nock_trace_push(bal);
+ }
+ u3z(act);
+ u3t_off(glu_o);
+ pro = _cj_kick_z(cor, cop_u, ham_u, axe);
+
+ if ( u3_none == pro ) {
+ if ( _(pof_o) || _(trc_o) ) {
+ pro = _cj_sink(cor, u3k(axe));
+
+ if (_(pof_o)) {
+ u3t_flee();
+ }
+ if ( _(trc_o) ) {
+ u3t_nock_trace_pop();
+ }
+ }
+ return pro;
+ }
+ else {
+ if ( _(pof_o) ) {
+ u3t_flee();
+ }
+ if ( _(trc_o) ) {
+ u3t_nock_trace_pop();
+ }
+ return pro;
+ }
+ }
+ }
+ }
+}
+
+/* _cj_fink_take(): copy u3j_fink from junior road.
+*/
+static u3j_fink*
+_cj_fink_take(u3j_fink* jun_u)
+{
+ c3_w i_w, len_w = jun_u->len_w;
+ u3j_fink* fin_u = u3a_walloc(c3_wiseof(u3j_fink) +
+ (len_w * c3_wiseof(u3j_fist)));
+
+ fin_u->len_w = len_w;
+ fin_u->sat = u3a_take(jun_u->sat);
+ for ( i_w = 0; i_w < len_w; ++i_w ) {
+ u3j_fist* fis_u = &(fin_u->fis_u[i_w]);
+ u3j_fist* sif_u = &(jun_u->fis_u[i_w]);
+ fis_u->bat = u3a_take(sif_u->bat);
+ fis_u->pax = u3a_take(sif_u->pax);
+ }
+ return fin_u;
+}
+
+/* _cj_fink_free(): lose and free everything in a u3j_fink.
+*/
+static void
+_cj_fink_free(u3p(u3j_fink) fin_p)
+{
+ c3_w i_w;
+ u3j_fink* fin_u = u3to(u3j_fink, fin_p);
+ u3z(fin_u->sat);
+ for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) {
+ u3j_fist* fis_u = &(fin_u->fis_u[i_w]);
+ u3z(fis_u->bat);
+ u3z(fis_u->pax);
+ }
+ u3a_wfree(fin_u);
+}
+
+/* u3j_rite_take(): copy junior rite references. [dst_u] is uninitialized
+*/
+void
+u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u)
+{
+ if ( u3_none == src_u->clu ) {
+ dst_u->clu = u3_none;
+ dst_u->fin_p = 0;
+ dst_u->own_o = c3n;
+ }
+ else {
+ dst_u->clu = u3a_take(src_u->clu);
+ dst_u->own_o = src_u->own_o;
+ dst_u->fin_p = ( c3n == src_u->own_o )
+ ? src_u->fin_p
+ : u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p)));
+ }
+}
+
+/* u3j_rite_merge(): copy rite references from src_u to dst_u,
+** losing old references
+*/
+void
+u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u)
+{
+ if ( u3_none != src_u->clu ) {
+ if ( u3_none != dst_u->clu ) {
+ u3z(dst_u->clu);
+ }
+
+ dst_u->clu = src_u->clu;
+
+ if ( dst_u->fin_p != src_u->fin_p ) {
+ if ( c3y == dst_u->own_o ) {
+ _cj_fink_free(dst_u->fin_p);
+ }
+
+ dst_u->fin_p = src_u->fin_p;
+ dst_u->own_o = src_u->own_o;
+ }
+ }
+}
+
+/* u3j_site_take(): copy junior site references. [dst_u] is uninitialized
+*/
+void
+u3j_site_take(u3j_site* dst_u, u3j_site* src_u)
+{
+ dst_u->axe = u3a_take(src_u->axe);
+ dst_u->bat = u3_none;
+ dst_u->bas = u3_none;
+ dst_u->pog_p = 0;
+
+ if ( u3_none == src_u->loc ) {
+ dst_u->loc = u3_none;
+ dst_u->lab = u3_none;
+ dst_u->jet_o = c3n;
+ dst_u->cop_u = NULL;
+ dst_u->ham_u = NULL;
+ dst_u->fin_p = 0;
+ dst_u->fon_o = c3n;
+ }
+ else {
+ dst_u->loc = u3a_take(src_u->loc);
+ dst_u->lab = u3a_take(src_u->lab);
+ dst_u->jet_o = src_u->jet_o;
+ dst_u->cop_u = src_u->cop_u;
+ dst_u->ham_u = src_u->ham_u;
+
+ if ( c3y == src_u->fon_o ) {
+ dst_u->fin_p = u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p)));
+ dst_u->fon_o = c3y;
+ }
+ else {
+ dst_u->fin_p = src_u->fin_p;
+ dst_u->fon_o = c3n;
+ }
+ }
+}
+
+/* u3j_site_merge(): copy site references from src_u to dst_u,
+** losing old references
+*/
+void
+u3j_site_merge(u3j_site* dst_u, u3j_site* src_u)
+{
+ u3z(dst_u->axe);
+ dst_u->axe = src_u->axe;
+
+ if ( u3_none != src_u->loc ) {
+ u3z(dst_u->loc); // XX these may be u3_none
+ u3z(dst_u->lab);
+ dst_u->loc = src_u->loc;
+ dst_u->lab = src_u->lab;
+ dst_u->cop_u = src_u->cop_u;
+ dst_u->ham_u = src_u->ham_u;
+ dst_u->jet_o = src_u->jet_o;
+
+ if ( dst_u->fin_p != src_u->fin_p ) {
+ if ( c3y == dst_u->fon_o ) {
+ _cj_fink_free(dst_u->fin_p);
+ }
+
+ dst_u->fin_p = src_u->fin_p;
+ dst_u->fon_o = src_u->fon_o;
+ }
+ }
+}
+
+/* u3j_site_ream(): refresh u3j_site after restoring from checkpoint
+*/
+void
+u3j_site_ream(u3j_site* sit_u)
+{
+ if ( u3_none != sit_u->loc ) {
+ u3z(sit_u->lab);
+ sit_u->jet_o = _cj_nail(sit_u->loc, sit_u->axe,
+ &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u));
+ }
+}
+
+/* _cj_site_lock(): ensure site has a valid program pointer
+ */
+static void
+_cj_site_lock(u3_noun loc, u3_noun cor, u3j_site* sit_u)
+{
+ if ( (u3_none != sit_u->bat) &&
+ (c3y == u3r_sing(sit_u->bat, u3h(cor))) ) {
+ return;
+ }
+ sit_u->pog_p = _cj_prog(loc, u3x_at(sit_u->axe, cor));
+ if ( u3_none != sit_u->bat ) {
+ u3z(sit_u->bat);
+ }
+ sit_u->bat = u3k(u3h(cor));
+}
+
+/* _cj_burn(): stop tracing glu and call a nock program
+ */
+static u3_noun
+_cj_burn(u3p(u3n_prog) pog_p, u3_noun cor)
+{
+ u3_noun pro;
+ u3t_off(glu_o);
+ pro = u3n_burn(pog_p, cor);
+ u3t_on(glu_o);
+ return pro;
+}
+
+/* _cj_site_kick_hot(): execute site's kick on located core
+** (no validity checks).
+*/
+static u3_weak
+_cj_site_kick_hot(u3_noun loc, u3_noun cor, u3j_site* sit_u, c3_o lok_o)
+{
+ u3_weak pro = u3_none;
+ c3_o jet_o = sit_u->jet_o;
+ c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu);
+ c3_o trc_o = __(u3C.wag_w & u3o_trace);
+
+ if ( c3n == pof_o && c3n == trc_o ) {
+ if ( c3y == jet_o ) {
+ u3t_off(glu_o);
+ pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe);
+ u3t_on(glu_o);
+ }
+ if ( u3_none == pro ) {
+ if ( c3y == lok_o ) {
+ _cj_site_lock(loc, cor, sit_u);
+ }
+ }
+ }
+ else {
+ if ( _(pof_o) ) {
+ pof_o = u3t_come(sit_u->lab);
+ }
+ if ( _(trc_o) ) {
+ trc_o = u3t_nock_trace_push(sit_u->lab);
+ }
+
+ if ( c3y == jet_o ) {
+ u3t_off(glu_o);
+ pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe);
+ u3t_on(glu_o);
+ }
+ if ( u3_none == pro ) {
+ if ( c3y == lok_o ) {
+ _cj_site_lock(loc, cor, sit_u);
+ }
+ pro = _cj_burn(sit_u->pog_p, cor);
+ }
+
+ if ( c3y == pof_o ) {
+ u3t_flee();
+ }
+ if ( c3y == trc_o ) {
+ u3t_nock_trace_pop();
+ }
+ }
+
+ return pro;
+}
+
+/* _cj_site_kick(): execute site's kick on core.
+ */
+static u3_weak
+_cj_site_kick(u3_noun cor, u3j_site* sit_u)
+{
+ u3_weak loc, pro;
+
+ loc = pro = u3_none;
+
+ if ( u3_none != sit_u->loc ) {
+ if ( c3y == _cj_fine(cor, sit_u->fin_p) ) {
+ loc = sit_u->loc;
+ pro = _cj_site_kick_hot(loc, cor, sit_u, c3y);
+ }
+ }
+
+ if ( u3_none == loc ) {
+ loc = _cj_spot(cor, &(sit_u->bas));
+ if ( u3_none != loc ) {
+ u3p(u3j_fink) fon_p = 0;
+ u3_weak lod = u3_none;
+ u3_weak lob = u3_none;
+
+ if ( u3_none != sit_u->loc ) {
+ lod = sit_u->loc;
+ lob = sit_u->lab;
+ if ( c3y == sit_u->fon_o ) {
+ fon_p = sit_u->fin_p;
+ }
+ }
+
+ sit_u->loc = loc;
+ sit_u->fin_p = _cj_cast(cor, loc);
+ sit_u->fon_o = c3y;
+ sit_u->jet_o = _cj_nail(loc, sit_u->axe,
+ &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u));
+ pro = _cj_site_kick_hot(loc, cor, sit_u, c3y);
+
+ if ( u3_none != lod ) {
+ u3z(lod);
+ u3z(lob);
+ if ( 0 != fon_p ) {
+ _cj_fink_free(fon_p);
+ }
+ }
+ }
+ }
+
+ if ( u3_none == pro ) {
+ _cj_site_lock(loc, cor, sit_u);
+ }
+
+ return pro;
+}
+
+/* u3j_site_kick(): kick a core with a u3j_site cache.
+ */
+u3_weak
+u3j_site_kick(u3_noun cor, u3j_site* sit_u)
+{
+ u3_weak pro;
+ u3t_on(glu_o);
+ pro = _cj_site_kick(cor, sit_u);
+ u3t_off(glu_o);
+ return pro;
+}
+
+/* u3j_cook(): Execute hook from core, call site cached by arbitrary c string
+*/
+u3_noun
+u3j_cook(const c3_c* key_c,
+ u3_noun cor,
+ const c3_c* tam_c)
+{
+ u3_noun pro, key, tam, inn;
+ u3j_hank* han_u;
+
+ u3t_on(glu_o);
+ key = u3i_string(key_c);
+ tam = u3i_string(tam_c);
+ han_u = _cj_hank_find(key, tam);
+ if ( c3n == _cj_hank_fine(han_u, cor, &inn) ) {
+ _cj_hank_lose(han_u);
+ inn = _cj_hank_fill(han_u, tam, cor);
+ }
+ pro = _cj_site_kick(u3k(inn), &(han_u->sit_u));
+ if ( u3_none == pro ) {
+ pro = _cj_burn(han_u->sit_u.pog_p, inn);
+ }
+ u3z(cor);
+
+ u3z(key);
+ u3z(tam);
+ u3t_off(glu_o);
+ return pro;
+}
+
+/* u3j_kink(): kick either by jet or by nock.
+*/
+u3_noun
+u3j_kink(u3_noun cor, u3_noun axe)
+{
+ u3_weak pro = u3j_kick(cor, axe);
+
+ if ( u3_none != pro ) {
+ return pro;
+ }
+ else {
+ return _cj_sink(cor, axe);
+ }
+}
+
+/* u3j_gate_prep(): prepare a locally cached gate to call repeatedly.
+ * core is TRANSFERRED.
+ */
+void
+u3j_gate_prep(u3j_site* sit_u, u3_noun cor)
+{
+ u3_noun loc;
+ u3t_on(glu_o);
+ if ( c3n == u3du(cor) || c3n == u3du(u3t(cor)) ) {
+ u3m_bail(c3__exit);
+ return;
+ }
+ sit_u->bas = u3_none;
+ sit_u->axe = 2;
+ sit_u->bat = cor; // a lie, this isn't really the battery!
+ sit_u->loc = loc = _cj_spot(cor, &(sit_u->bas));
+ sit_u->pog_p = _cj_prog(loc, u3h(cor));
+ if ( u3_none != loc ) {
+ u3_noun pax = _cj_loc_axe(loc),
+ pay = u3qc_cap(pax),
+ pam = u3qc_mas(pax);
+ if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) {
+ u3l_log("u3j_gate_prep(): parent axis includes sample");
+ u3m_p("axis", pax);
+ u3_weak act = _cj_find_warm(loc);
+ u3_assert( u3_none != act );
+ sit_u->jet_o = c3n;
+ sit_u->lab = u3k(u3h(u3t(u3t(act))));
+ u3z(act);
+ }
+ else {
+ sit_u->jet_o = _cj_nail(loc, 2,
+ &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u));
+ }
+ u3z(pam); u3z(pax);
+ }
+ u3t_off(glu_o);
+}
+
+/* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample.
+ * sam is TRANSFERRED.
+ */
+u3_noun
+u3j_gate_slam(u3j_site* sit_u, u3_noun sam)
+{
+ u3_weak pro;
+ u3_noun cor;
+
+ u3t_on(glu_o);
+ pro = u3_none;
+ cor = u3nt(u3k(u3h(sit_u->bat)),
+ sam,
+ u3k(u3t(u3t(sit_u->bat))));
+ if ( u3_none != sit_u->loc ) {
+ pro = _cj_site_kick_hot(sit_u->loc, cor, sit_u, c3n);
+ }
+ if ( u3_none == pro ) {
+ pro = _cj_burn(sit_u->pog_p, cor);
+ }
+ u3t_off(glu_o);
+ return pro;
+}
+
+/* u3j_gate_lose(): clean up site prepared by u3j_gate_find().
+ */
+void
+u3j_gate_lose(u3j_site* sit_u)
+{
+ u3z(sit_u->bat);
+ u3z(sit_u->bas);
+ if ( u3_none != sit_u->loc ) {
+ u3z(sit_u->loc);
+ u3z(sit_u->lab);
+ }
+}
+
+/* _cj_minx(): produce location of core from fsck'd clue. RETAIN.
+ */
+static u3_weak
+_cj_minx(u3_noun cey, u3_noun cor)
+{
+ u3_noun nam, axe, huc;
+ u3x_trel(cey, &nam, &axe, &huc);
+
+ if ( 0 == axe ) {
+ return u3nt(u3nt(c3y, c3y, u3k(u3t(cor))), u3k(nam), u3k(huc));
+ }
+ else {
+ u3_weak par, pel;
+ u3_noun pat;
+
+ par = u3r_at(axe, cor);
+ if ( u3_none == par || c3n == u3du(par) ) {
+ u3l_log("fund: %s is bogus", u3r_string(nam));
+ return u3_none;
+ }
+ pel = _cj_spot(par, NULL);
+ if ( u3_none == pel ) {
+ u3l_log("fund: in %s, parent %x not found at %d",
+ u3r_string(nam),
+ u3r_mug(u3h(par)),
+ axe);
+ return u3_none;
+ }
+ pat = ( ( 3 == axe ) && (c3y == u3h(u3h(pel))) )
+ ? u3nt(c3y, c3n, pel)
+ : u3nt(c3n, u3k(axe), pel);
+ return u3nt(pat, u3k(nam), u3k(huc));
+ }
+}
+
+static void
+_cj_print_tas(u3_noun tas)
+{
+ c3_w met_w = u3r_met(3, tas);
+ c3_c* str_c = alloca(met_w + 1);
+ u3r_bytes(0, met_w, (c3_y*)str_c, tas);
+ str_c[met_w] = 0;
+ u3l_log("/%s", str_c);
+}
+
+/* _cj_mine(): declare a core and produce location. RETAIN.
+*/
+static u3_weak
+_cj_mine(u3_noun cey, u3_noun cor, u3_noun bas)
+{
+ u3_weak loc = _cj_minx(cey, cor);
+ if ( u3_none != loc ) {
+ c3_l par_l, jax_l;
+ u3_noun pel = _cj_loc_pel(loc),
+ axe = _cj_loc_axe(loc),
+ bat = u3h(cor),
+ nam = u3h(u3t(loc)),
+ bar = _cj_find_cold(bat),
+ reg, hap, bal, act;
+ if ( u3_none == bar ) {
+ reg = u3_none;
+ }
+ else {
+ reg = u3k(u3t(bar));
+ u3z(bar);
+ }
+ reg = _cj_gust(reg, u3k(axe), u3k(pel), u3k(loc));
+ if ( 0 == axe ) {
+ par_l = 0;
+ bal = u3nc(u3k(nam), u3_nul);
+ }
+ else {
+ u3_weak pac = _cj_find_warm(pel);
+ u3_assert(u3_none != pac);
+ par_l = u3h(pac);
+ bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac)))));
+ u3z(pac);
+ }
+ jax_l = _cj_hot_mean(par_l, nam);
+#if 0
+ u3m_p("new jet", bal);
+ u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
+#endif
+
+ if ( !(u3C.wag_w & u3o_hashless) ) {
+ if ( jax_l ) {
+ c3_y dig_y[32];
+ c3_w i_w;
+ u3_noun i = bal;
+ u3l_log("hot jet: ");
+ while ( i != u3_nul ) {
+ _cj_print_tas(u3h(i));
+ i = u3t(i);
+ }
+ u3l_log("\r\n axe %d, jax %d,\r\n bash ", axe, jax_l);
+ u3r_bytes(0, 32, dig_y, bas);
+ for ( i_w = 32; i_w > 0; ) {
+ u3l_log("%02x", dig_y[--i_w]);
+ }
+ u3l_log("");
+ }
+ }
+
+ hap = _cj_warm_hump(jax_l, u3t(u3t(loc)));
+ act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat));
+ u3h_put(u3R->jed.cod_p, bat, u3nc(u3k(bas), reg));
+ u3h_put(u3R->jed.war_p, loc, act); // see note in _cj_spot
+ u3z(pel); u3z(axe);
+ }
+
+ return loc;
+#if 0
+ {
+ u3_noun bas = _cj_bash(bat),
+ hot = u3h_get(u3D.hot_p, bas);
+ c3_o hav_o = c3n;
+
+ if ( u3_none != hot ) {
+ u3_noun her = u3h(hot),
+ hol = _cj_reg_find(her, cor);
+ if ( hol != u3_none ) {
+ hav_o = c3y;
+ u3z(hol);
+ }
+ u3z(hot);
+ }
+
+ if ( c3n == hav_o ) {
+ u3m_p("unregistered battery", bal);
+ u3l_log("hash: %x", bas);
+ }
+ u3z(bas);
+ }
+#endif
+}
+
+static void
+_cj_audit(u3_noun loc, u3_noun cey, u3_noun cor)
+{
+ u3_noun pat, nam, huc, cax, can, cuc, pax;
+
+ u3x_trel(loc, &pat, &nam, &huc);
+ u3x_trel(cey, &can, &cax, &cuc);
+
+ pax = _cj_loc_axe(loc);
+
+ if ( (c3n == u3r_sing(nam, can)) ||
+ (c3n == u3r_sing(pax, cax)) ||
+ (c3n == u3r_sing(huc, cuc)) ) {
+ u3_noun mix = _cj_minx(cey, cor);
+ u3m_p("bad audit", loc);
+ u3m_p("hint says", mix);
+ u3z(mix);
+ }
+
+ u3z(pax);
+}
+
+/* _cj_mile(): register core for jets, returning location.
+*/
+static u3_weak
+_cj_mile(u3_noun clu, u3_noun cor)
+{
+ u3_weak loc = u3_none;
+ if ( c3n == u3du(cor) ) {
+ u3z(clu);
+ u3z(cor);
+ }
+ else {
+ u3_weak cey = _cj_je_fsck(clu);
+ if ( u3_none != cey ) {
+ u3_weak bas = u3_none;
+ loc = _cj_spot(cor, &bas);
+ if ( u3_none == loc ) {
+ loc = _cj_mine(cey, cor, bas);
+ }
+ else {
+ _cj_audit(loc, cey, cor);
+ }
+ u3z(cey);
+ if ( u3_none != bas ) {
+ u3z(bas);
+ }
+ }
+ u3z(cor);
+ }
+ return loc;
+}
+
+/* u3j_mine(): register core for jets.
+*/
+void
+u3j_mine(u3_noun clu, u3_noun cor)
+{
+ u3_weak loc;
+ u3t_on(glu_o);
+ loc = _cj_mile(clu, cor);
+ u3z(loc);
+ u3t_off(glu_o);
+}
+
+/* u3j_rite_mine(): mine cor with clue, using u3j_rite for caching
+*/
+void
+u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor)
+{
+ c3_t non_t;
+ u3t_on(glu_o);
+
+ non_t = (u3_none == rit_u->clu);
+
+ if ( non_t ||
+ c3n == u3r_sing(rit_u->clu, clu) ||
+ c3n == _cj_fine(cor, rit_u->fin_p) ) {
+ u3_weak loc = _cj_mile(u3k(clu), u3k(cor));
+ if ( u3_none != loc ) {
+ u3p(u3j_fink) fon_p = rit_u->fin_p;
+ u3_noun old = rit_u->clu;
+ c3_o own_o = rit_u->own_o;
+ rit_u->own_o = c3y;
+ rit_u->clu = u3k(clu);
+ rit_u->fin_p = _cj_cast(cor, loc);
+ u3z(loc);
+
+ if ( !non_t && (c3y == own_o) ) {
+ u3z(old);
+ _cj_fink_free(fon_p);
+ }
+ }
+ }
+ u3z(clu);
+ u3z(cor);
+ u3t_off(glu_o);
+}
+
+/* _cj_take_hank_cb(): u3h_take_with cb for taking hanks
+*/
+static c3_w
+_cj_take_hank_cb(c3_w nah_w)
+{
+ u3j_hank* nah_u = _cj_to_hank(nah_w);
+ u3j_hank* han_u = u3a_walloc(c3_wiseof(u3j_hank));
+
+ if ( u3_none == nah_u->hax ) {
+ han_u->hax = u3_none;
+ // han_u->sit_u left uninitialized, will be ignored
+ }
+ else {
+ han_u->hax = u3a_take(nah_u->hax);
+ u3j_site_take(&(han_u->sit_u), &(nah_u->sit_u));
+ }
+
+ return _cj_of_hank(han_u);
+}
+
+/* u3j_take(): copy junior jet state.
+*/
+u3a_jets
+u3j_take(u3a_jets jed_u)
+{
+ jed_u.war_p = u3h_take(jed_u.war_p);
+ jed_u.cod_p = u3h_take(jed_u.cod_p);
+ jed_u.han_p = u3h_take_with(jed_u.han_p, _cj_take_hank_cb);
+ jed_u.bas_p = u3h_take(jed_u.bas_p);
+ return jed_u;
+}
+
+/* _cj_merge_hank_cb(): u3h_uni_with cb for integrating taken hanks
+** NB "transfers" or frees hanks in jed_u.han_p
+*/
+static void
+_cj_merge_hank_cb(u3_noun kev, void* wit)
+{
+ u3p(u3h_root) han_p = *(u3p(u3h_root)*)wit;
+ u3j_hank* nah_u;
+ u3_noun key;
+ c3_w nah_w;
+ u3x_cell(kev, &key, &nah_w);
+
+ nah_u = _cj_to_hank(nah_w);
+
+ if ( u3_none == nah_u->hax ) {
+ u3a_wfree(nah_u);
+ }
+ else {
+ u3j_hank* han_u;
+ u3_weak got = u3h_git(u3R->jed.han_p, key);
+
+ if ( u3_none == got ) {
+ han_u = nah_u;
+ }
+ else {
+ han_u = _cj_to_hank(got);
+
+ if ( u3_none != han_u->hax ) {
+ u3z(han_u->hax);
+ }
+ han_u->hax = nah_u->hax;
+
+ u3j_site_merge(&(han_u->sit_u), &(nah_u->sit_u));
+ u3a_wfree(nah_u);
+ }
+
+ u3h_put(han_p, key, _cj_of_hank(han_u));
+ }
+}
+
+/* u3j_reap(): promote jet state.
+*/
+void
+u3j_reap(u3a_jets jed_u)
+{
+ u3h_uni(u3R->jed.war_p, jed_u.war_p);
+ u3h_free(jed_u.war_p);
+
+ u3h_uni(u3R->jed.cod_p, jed_u.cod_p);
+ u3h_free(jed_u.cod_p);
+
+ u3h_walk_with(jed_u.han_p, _cj_merge_hank_cb, &u3R->jed.han_p);
+ u3h_free(jed_u.han_p);
+
+ u3h_uni(u3R->jed.bas_p, jed_u.bas_p);
+ u3h_free(jed_u.bas_p);
+}
+
+/* _cj_ream(): ream list of battery [bash registry] pairs. RETAIN.
+ */
+static void
+_cj_ream(u3_noun all)
+{
+ c3_l par_l, jax_l;
+ u3_noun i, j, k, rul, loc, bal, act, lop, kev, rut, hap,
+ pat, reg, pol, rem, rec, bat, pel, nam, huc;
+ u3_weak pac;
+
+ for ( i = all, lop = u3_nul; i != u3_nul; i = u3t(i) ) {
+ kev = u3h(i);
+ bat = u3h(kev);
+ reg = u3t(u3t(kev));
+ rut = u3h(reg);
+
+ // register roots
+ rul = u3qdb_tap(rut);
+ for ( j = rul; j != u3_nul; j = u3t(j) ) {
+ loc = u3t(u3h(j));
+ u3x_trel(loc, &pat, &nam, &huc);
+ bal = u3nc(u3k(nam), u3_nul);
+ jax_l = _cj_hot_mean(0, nam);
+ hap = _cj_warm_hump(jax_l, huc);
+ act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat));
+#if 0
+ u3m_p("old jet", bal);
+ u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
+#endif
+ u3h_put(u3R->jed.war_p, loc, act);
+ }
+ u3z(rul);
+
+ // put ancestors in lop (list [battery=^ parent=location this=location])
+ for ( j = u3t(reg); j != u3_nul; j = u3t(j) ) {
+ pol = lop;
+ lop = u3qdb_tap(u3t(u3h(j)));
+ for ( k = lop; u3_nul != k; k = u3t(k) ) {
+ pol = u3nc(u3nc(u3k(bat), u3k(u3h(k))), pol);
+ }
+ u3z(lop);
+ lop = pol;
+ }
+ }
+
+ // ordering is random so we need to push onto rem when parent
+ // isn't yet present in the warm state
+ while ( u3_nul != lop ) {
+ rem = u3_nul;
+ for ( i = lop; u3_nul != i; i = u3t(i) ) {
+ rec = u3h(i);
+ u3x_trel(rec, &bat, &pel, &loc);
+ pac = _cj_find_warm(pel);
+ if ( u3_none == pac ) {
+ rem = u3nc(u3k(rec), rem);
+ }
+ else {
+ u3x_trel(loc, &pat, &nam, &huc);
+ par_l = u3h(pac);
+ jax_l = _cj_hot_mean(par_l, nam);
+ bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac)))));
+ hap = _cj_warm_hump(jax_l, huc),
+ u3z(pac);
+ act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat));
+#if 0
+ u3m_p("old jet", bal);
+ u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l);
+#endif
+ u3h_put(u3R->jed.war_p, loc, act);
+ }
+ }
+ u3z(lop);
+ lop = rem;
+ }
+}
+
+/* _cj_warm_tap(): tap war_p to rel
+*/
+static void
+_cj_warm_tap(u3_noun kev, void* wit)
+{
+ u3_noun* rel = wit;
+ *rel = u3nc(u3k(kev), *rel);
+}
+
+/* _cj_ream_hank(): clear hot state out of hook sites.
+*/
+static void
+_cj_ream_hank(u3_noun kev)
+{
+ u3j_site_ream(&(_cj_to_hank(u3t(kev))->sit_u));
+}
+
+/* u3j_ream(): rebuild warm state
+*/
+void
+u3j_ream(void)
+{
+ u3_noun rel = u3_nul;
+ u3_assert(u3R == &(u3H->rod_u));
+ u3h_free(u3R->jed.war_p);
+ u3R->jed.war_p = u3h_new();
+ u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel);
+ _cj_ream(rel);
+ u3z(rel);
+
+ u3h_walk(u3R->jed.han_p, _cj_ream_hank);
+}
+
+/* u3j_stay(): extract cold state
+*/
+u3_noun
+u3j_stay(void)
+{
+ u3_noun rel = u3_nul;
+ u3_assert(u3R == &(u3H->rod_u));
+ u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel);
+ return rel;
+}
+
+/* u3j_load(): inject cold state
+*/
+void
+u3j_load(u3_noun rel)
+{
+ u3_noun ler = rel;
+ u3_noun lor;
+
+ while ( u3_nul != ler ) {
+ u3x_cell(ler, &lor, &ler);
+ u3h_put(u3R->jed.cod_p, u3h(lor), u3k(u3t(lor)));
+ }
+
+ u3z(rel);
+}
+
+/* _cj_fink_mark(): mark a u3j_fink for gc.
+*/
+static c3_w
+_cj_fink_mark(u3j_fink* fin_u)
+{
+ c3_w i_w, tot_w = u3a_mark_noun(fin_u->sat);
+ for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) {
+ u3j_fist* fis_u = &(fin_u->fis_u[i_w]);
+ tot_w += u3a_mark_noun(fis_u->bat);
+ tot_w += u3a_mark_noun(fis_u->pax);
+ }
+ tot_w += u3a_mark_ptr(fin_u);
+ return tot_w;
+}
+
+/* u3j_site_lose(): lose references of u3j_site (but do not free).
+ */
+void
+u3j_site_lose(u3j_site* sit_u)
+{
+ u3z(sit_u->axe);
+ if ( u3_none != sit_u->bat ) {
+ u3z(sit_u->bat);
+ }
+ if ( u3_none != sit_u->bas ) {
+ u3z(sit_u->bas);
+ }
+ if ( u3_none != sit_u->loc ) {
+ u3z(sit_u->loc);
+ u3z(sit_u->lab);
+ if ( c3y == sit_u->fon_o ) {
+ _cj_fink_free(sit_u->fin_p);
+ }
+ }
+}
+
+/* u3j_rite_lose(): lose references of u3j_rite (but do not free).
+ */
+void
+u3j_rite_lose(u3j_rite* rit_u)
+{
+ if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) {
+ u3z(rit_u->clu);
+ _cj_fink_free(rit_u->fin_p);
+ }
+}
+
+/* u3j_rite_mark(): mark u3j_rite for gc.
+*/
+c3_w
+u3j_rite_mark(u3j_rite* rit_u)
+{
+ c3_w tot_w = 0;
+ if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) {
+ tot_w += u3a_mark_noun(rit_u->clu);
+ tot_w += _cj_fink_mark(u3to(u3j_fink, rit_u->fin_p));
+ }
+ return tot_w;
+}
+
+/* u3j_site_mark(): mark u3j_site for gc.
+*/
+c3_w
+u3j_site_mark(u3j_site* sit_u)
+{
+ c3_w tot_w = u3a_mark_noun(sit_u->axe);
+ if ( u3_none != sit_u->bat ) {
+ tot_w += u3a_mark_noun(sit_u->bat);
+ }
+ if ( u3_none != sit_u->bas ) {
+ tot_w += u3a_mark_noun(sit_u->bas);
+ }
+ if ( u3_none != sit_u->loc ) {
+ tot_w += u3a_mark_noun(sit_u->loc);
+ tot_w += u3a_mark_noun(sit_u->lab);
+ if ( c3y == sit_u->fon_o ) {
+ tot_w += _cj_fink_mark(u3to(u3j_fink, sit_u->fin_p));
+ }
+ }
+ return tot_w;
+}
+
+/* _cj_mark_hank(): mark hank cache for gc.
+*/
+static void
+_cj_mark_hank(u3_noun kev, void* dat)
+{
+ c3_w* tot_w = (c3_w*) dat;
+ u3j_hank* han_u = _cj_to_hank(u3t(kev));
+ *tot_w += u3a_mark_ptr(han_u);
+ if ( u3_none != han_u->hax ) {
+ *tot_w += u3a_mark_noun(han_u->hax);
+ *tot_w += u3j_site_mark(&(han_u->sit_u));
+ }
+}
+
+/* u3j_mark(): mark jet state for gc.
+*/
+u3m_quac*
+u3j_mark()
+{
+ u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 7);
+
+ qua_u[0] = c3_calloc(sizeof(*qua_u[0]));
+ qua_u[0]->nam_c = strdup("warm jet state");
+ qua_u[0]->siz_w = u3h_mark(u3R->jed.war_p) * 4;
+
+ qua_u[1] = c3_calloc(sizeof(*qua_u[1]));
+ qua_u[1]->nam_c = strdup("cold jet state");
+ qua_u[1]->siz_w = u3h_mark(u3R->jed.cod_p) * 4;
+
+ qua_u[2] = c3_calloc(sizeof(*qua_u[2]));
+ qua_u[2]->nam_c = strdup("hank cache");
+ qua_u[2]->siz_w = u3h_mark(u3R->jed.han_p) * 4;
+
+ qua_u[3] = c3_calloc(sizeof(*qua_u[3]));
+ qua_u[3]->nam_c = strdup("battery hash cache");
+ qua_u[3]->siz_w = u3h_mark(u3R->jed.bas_p) * 4;
+
+ qua_u[4] = c3_calloc(sizeof(*qua_u[4]));
+ qua_u[4]->nam_c = strdup("call site cache");
+ u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &qua_u[4]->siz_w);
+ qua_u[4]->siz_w *= 4;
+
+ c3_w sum_w = 0;
+ for ( c3_w i_w = 0; i_w < 5; i_w++ ) {
+ sum_w += qua_u[i_w]->siz_w;
+ }
+
+ u3m_quac* tot_u = c3_calloc(sizeof(*tot_u));
+ tot_u->nam_c = strdup("total jet stuff");
+
+ if ( u3R == &(u3H->rod_u) ) {
+ qua_u[5] = c3_calloc(sizeof(*qua_u[5]));
+ qua_u[5]->nam_c = strdup("hot jet state");
+ qua_u[5]->siz_w = u3h_mark(u3R->jed.hot_p) * 4;
+
+ sum_w += qua_u[5]->siz_w;
+
+ qua_u[6] = NULL;
+
+ tot_u->siz_w = sum_w;
+ tot_u->qua_u = qua_u;
+
+ return tot_u;
+ } else {
+ qua_u[5] = NULL;
+
+ tot_u->siz_w = sum_w;
+ tot_u->qua_u = qua_u;
+
+ return tot_u;
+ }
+}
+
+/* u3j_free_hank(): free an entry from the hank cache.
+*/
+void
+u3j_free_hank(u3_noun kev)
+{
+ u3j_hank* han_u = _cj_to_hank(u3t(kev));
+ if ( u3_none != han_u->hax ) {
+ u3z(han_u->hax);
+ u3j_site_lose(&(han_u->sit_u));
+ }
+ u3a_wfree(han_u);
+}
+
+/* u3j_free(): free jet state.
+*/
+void
+u3j_free(void)
+{
+ u3h_walk(u3R->jed.han_p, u3j_free_hank);
+ u3h_free(u3R->jed.war_p);
+ u3h_free(u3R->jed.cod_p);
+ u3h_free(u3R->jed.han_p);
+ u3h_free(u3R->jed.bas_p);
+ if ( u3R == &(u3H->rod_u) ) {
+ u3h_free(u3R->jed.hot_p);
+ }
+}
+
+/* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3j_reclaim(void)
+{
+ // re-establish the warm jet state
+ //
+ // XX might this reduce fragmentation?
+ //
+ // if ( &(u3H->rod_u) == u3R ) {
+ // u3j_ream();
+ // }
+ // clear the jet hank cache
+ //
+ u3h_walk(u3R->jed.han_p, u3j_free_hank);
+ u3h_free(u3R->jed.han_p);
+ u3R->jed.han_p = u3h_new();
+}
+
+/* u3j_rewrite_compact(): rewrite jet state for compaction.
+ *
+ * NB: u3R->jed.han_p *must* be cleared (currently via u3j_reclaim above)
+ * since it contains hanks which are not nouns but have loom pointers.
+ * Alternately, rewrite the entries with u3h_walk, using u3j_mark as a
+ * template for how to walk. There's an untested attempt at this in git
+ * history at e8a307a.
+*/
+void
+u3j_rewrite_compact(void)
+{
+ u3h_relocate(&(u3R->jed.war_p));
+ u3h_relocate(&(u3R->jed.cod_p));
+ u3h_relocate(&(u3R->jed.han_p));
+ u3h_relocate(&(u3R->jed.bas_p));
+
+ if ( u3R == &(u3H->rod_u) ) {
+ u3h_relocate(&(u3R->jed.hot_p));
+ }
+}
diff --git a/vere/pkg/noun/jets.h b/vere/pkg/noun/jets.h
new file mode 100644
index 0000000..c81ab18
--- /dev/null
+++ b/vere/pkg/noun/jets.h
@@ -0,0 +1,322 @@
+/// @file
+
+#ifndef U3_JETS_H
+#define U3_JETS_H
+
+#include "allocate.h"
+#include "c3/c3.h"
+#include "types.h"
+
+ /** Noun semantics.
+ **/
+#if 0
++= location $: pattern=(each static dynamic)
+ name=term
+ hooks=(map term axis)
+ ==
++= static (each payload=* parent=location)
++= dynamic [where=axis parent=location]
+::
++= registry [roots=(map * location) parents=(list parent)]
++= parent (pair axis (map location location))
+::
++= activation $: hot-index=@ud
+ drivers=(map axis @ud)
+ label=path
+ jit=* :: FIXME: should probably be (map battery *)
+ :: since there can be multiple batteries per location
+ ==
++= hot-info $: reg=registry
+ hot-index=@ud
+ drivers=(map axis @ud)
+ label=path
+ ==
++= bash @ :: battery hash (sha-256 based)
+::
++= hot (map bash hot-info)
++= cold (map battery=^ (pair bash registry))
++= warm (map location activation)
+#endif
+
+ /** Data structures.
+ ***
+ *** All of these are transient structures allocated with malloc.
+ **/
+ /* u3j_harm: jet arm.
+ */
+ typedef struct _u3j_harm {
+ c3_c* fcs_c; // `.axe` or name
+ u3_noun (*fun_f)(u3_noun); // compute or 0 / semitransfer
+ // c3_o (*val_f)(u3_noun); // validate or 0 / retain
+ c3_o ice; // perfect (don't test)
+ c3_o tot; // total (never punts)
+ c3_o liv; // live (enabled)
+ c3_l axe_l; // computed/discovered axis
+ struct _u3j_core* cop_u; // containing core
+ } u3j_harm;
+
+ /* u3j_hood: hook description.
+ */
+ typedef struct _u3j_hood {
+ c3_c* nam_c; // hook name
+ c3_l axe_l; // hook axis (XX: direct)
+ c3_o kic_o; // hook is kick (vs. fragment)
+ c3_l sax_l; // hook subject axis (XX: direct)
+ } u3j_hood;
+
+ /* u3j_core: driver definition.
+ */
+ typedef struct _u3j_core {
+ c3_c* cos_c; // control string
+ c3_l axe_l; // axis to parent
+ struct _u3j_harm* arm_u; // blank-terminated static list
+ struct _u3j_core* dev_u; // blank-terminated static list
+ c3_c** bas_u; // blank-terminated static list
+ struct _u3j_hood* huc_u; // blank-terminated static list
+ struct _u3j_core* par_u; // dynamic parent pointer
+ c3_l jax_l; // index in global dashboard
+ } u3j_core;
+
+ /* u3j_dash, u3_Dash, u3D: jet dashboard singleton
+ */
+ typedef struct _u3j_dash {
+ u3j_core* dev_u; // null-terminated static list
+ c3_l len_l; // dynamic array length
+ c3_l all_l; // allocated length
+ u3j_core* ray_u; // dynamic array by axis
+ } u3j_dash;
+
+ /* u3j_fist: a single step in a fine check.
+ */
+ typedef struct {
+ u3_noun bat; // battery
+ u3_noun pax; // parent axis
+ } u3j_fist;
+
+ /* u3j_fink: (fine check) enough data to verify a located core.
+ */
+ typedef struct {
+ c3_w len_w; // number of fists
+ u3_noun sat; // static noun at end of check
+ u3j_fist fis_u[]; // fists
+ } u3j_fink;
+
+ /* u3j_rite: site of a %fast, used to skip re-mining.
+ */
+ typedef struct {
+ c3_o own_o; // rite owns fink?
+ u3_weak clu; // cached product of clue formula
+ u3p(u3j_fink) fin_p; // fine check
+ } u3j_rite;
+
+ /* u3j_site: site of a kick (nock 9), used to cache call target.
+ */
+ struct _u3n_prog;
+ typedef struct {
+ u3p(struct _u3n_prog) pog_p; // program for formula
+ u3_noun axe; // axis
+ u3_weak bat; // battery (for verification)
+ u3_weak bas; // hash of battery (for hot find)
+ u3_weak loc; // location (for reaming)
+ c3_o jet_o; // have jet driver?
+ c3_o fon_o; // site owns fink?
+ u3_weak lab; // label (for tracing)
+ u3j_core* cop_u; // jet core
+ u3j_harm* ham_u; // jet arm
+ u3p(u3j_fink) fin_p; // fine check
+ } u3j_site;
+
+ /* u3j_hank: cached hook information.
+ */
+ typedef struct {
+ u3_weak hax; // axis of hooked inner core
+ u3j_site sit_u; // call-site data
+ } u3j_hank;
+
+ /** Globals.
+ **/
+ /* u3_Dash: jet dashboard.
+ */
+ extern u3j_dash u3j_Dash;
+# define u3D u3j_Dash
+
+ /** Functions.
+ **/
+ /* u3j_boot(): initialize jet system.
+ */
+ c3_w
+ u3j_boot(c3_o nuu_o);
+
+ /* u3j_clear(): clear jet table to re-register.
+ */
+ void
+ u3j_clear(void);
+
+ /* u3j_cook():
+ **
+ ** Execute hook from core, call site cached by arbitrary c string
+ */
+ u3_noun
+ u3j_cook(const c3_c* key_c,
+ u3_noun cor,
+ const c3_c* tam_c);
+
+ /* u3j_hook():
+ **
+ ** Execute hook from core.
+ */
+ u3_noun
+ u3j_hook(u3_noun cor,
+ const c3_c* tam_c);
+
+ /* u3j_soft():
+ **
+ ** Execute hook from core, without jet.
+ */
+ u3_noun
+ u3j_soft(u3_noun cor,
+ const c3_c* tam_c);
+
+ /* u3j_kick(): try to kick by jet. If no kick, produce u3_none.
+ **
+ ** `axe` is RETAINED by the caller; `cor` is RETAINED iff there
+ ** is no kick, TRANSFERRED if one.
+ */
+ u3_weak
+ u3j_kick(u3_noun cor, u3_noun axe);
+
+ /* u3j_kink(): kick either by jet or by nock.
+ */
+ u3_noun
+ u3j_kink(u3_noun cor,
+ u3_noun axe);
+
+ /* u3j_mine(): register core for jets.
+ */
+ void
+ u3j_mine(u3_noun clu,
+ u3_noun cor);
+
+ /* u3j_ream(): refresh after restoring from checkpoint.
+ */
+ void
+ u3j_ream(void);
+
+ /* u3j_stay(): extract cold state
+ */
+ u3_noun
+ u3j_stay(void);
+
+ /* u3j_load(): inject cold state
+ */
+ void
+ u3j_load(u3_noun rel);
+
+ /* u3j_reap(): promote jet state.
+ */
+ void
+ u3j_reap(u3a_jets jed_u);
+
+ /* u3j_take(): copy junior jet state.
+ */
+ u3a_jets
+ u3j_take(u3a_jets jed_u);
+
+ /* u3j_rite_mine(): mine cor with clu, using u3j_rite for caching
+ */
+ void
+ u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor);
+
+ /* u3j_rite_take(): copy junior rite references from src_u to dst_u.
+ */
+ void
+ u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u);
+
+ /* u3j_rite_merge(): copy rite references from src_u to dst_u,
+ ** losing old references
+ */
+ void
+ u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u);
+
+ /* u3j_site_take(): copy junior site references.
+ */
+ void
+ u3j_site_take(u3j_site* dst_u, u3j_site* src_u);
+
+ /* u3j_site_merge(): copy site references from src_u to dst_u,
+ ** losing old references
+ */
+ void
+ u3j_site_merge(u3j_site* dst_u, u3j_site* src_u);
+
+ /* u3j_site_ream(): refresh u3j_site after restoring from checkpoint
+ */
+ void
+ u3j_site_ream(u3j_site* sit_u);
+
+ /* u3j_site_kick(): kick a core with a u3j_site cache.
+ */
+ u3_weak
+ u3j_site_kick(u3_noun cor, u3j_site* sit_u);
+
+ /* u3j_gate_prep(): prepare a locally cached gate to call repeatedly.
+ */
+ void
+ u3j_gate_prep(u3j_site* sit_u, u3_noun cor);
+
+ /* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample.
+ */
+ u3_noun
+ u3j_gate_slam(u3j_site* sit_u, u3_noun sam);
+
+ /* u3j_gate_lose(): clean up site prepared by u3j_gate_find().
+ */
+ void
+ u3j_gate_lose(u3j_site* sit_u);
+
+ /* u3j_rite_mark(): mark u3j_rite for gc.
+ */
+ c3_w
+ u3j_rite_mark(u3j_rite* rit_u);
+
+ /* u3j_rite_lose(): lose references of u3j_rite (but do not free).
+ */
+ void
+ u3j_rite_lose(u3j_rite* rit_u);
+
+ /* u3j_site_lose(): lose references of u3j_site (but do not free).
+ */
+ void
+ u3j_site_lose(u3j_site* sit_u);
+
+ /* u3j_site_mark(): mark u3j_site for gc.
+ */
+ c3_w
+ u3j_site_mark(u3j_site* sit_u);
+
+ /* u3j_mark(): mark jet state for gc.
+ */
+ u3m_quac*
+ u3j_mark();
+
+ /* u3j_free(): free jet state.
+ */
+ void
+ u3j_free(void);
+
+ /* u3j_free_hank(): free an entry from the hank cache.
+ */
+ void
+ u3j_free_hank(u3_noun kev);
+
+ /* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3j_reclaim(void);
+
+ /* u3j_rewrite_compact(): rewrite jet state for compaction.
+ */
+ void
+ u3j_rewrite_compact(void);
+
+#endif /* ifndef U3_JETS_H */
diff --git a/vere/pkg/noun/jets/136/tree.c b/vere/pkg/noun/jets/136/tree.c
new file mode 100644
index 0000000..345fe3a
--- /dev/null
+++ b/vere/pkg/noun/jets/136/tree.c
@@ -0,0 +1,1268 @@
+#include "c3/c3.h"
+#include "jets.h"
+#include "jets/w.h"
+
+
+static c3_c* no_hashes[] = { 0 };
+
+static u3j_harm _136_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}};
+static u3j_harm _136_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}};
+static u3j_core _136_hex_mimes_base16_d[] =
+ { { "en", 7, _136_hex_mimes_base16_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_mimes_base16_de_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _136_hex_mimes_d[] =
+ { { "base16", 3, 0, _136_hex_mimes_base16_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}};
+static u3j_harm _136_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}};
+static u3j_core _136_hex_aes_ecba_d[] =
+ { { "en", 7, _136_hex_aes_ecba_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_ecba_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}};
+static u3j_harm _136_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}};
+static u3j_core _136_hex_aes_ecbb_d[] =
+ { { "en", 7, _136_hex_aes_ecbb_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_ecbb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}};
+static u3j_harm _136_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}};
+static u3j_core _136_hex_aes_ecbc_d[] =
+ { { "en", 7, _136_hex_aes_ecbc_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_ecbc_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}};
+static u3j_harm _136_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}};
+static u3j_core _136_hex_aes_cbca_d[] =
+ { { "en", 7, _136_hex_aes_cbca_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_cbca_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}};
+static u3j_harm _136_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}};
+static u3j_core _136_hex_aes_cbcb_d[] =
+ { { "en", 7, _136_hex_aes_cbcb_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_cbcb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}};
+static u3j_harm _136_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}};
+static u3j_core _136_hex_aes_cbcc_d[] =
+ { { "en", 7, _136_hex_aes_cbcc_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_cbcc_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}};
+static u3j_harm _136_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}};
+static u3j_core _136_hex_aes_siva_d[] =
+ { { "en", 7, _136_hex_aes_siva_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_siva_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}};
+static u3j_harm _136_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}};
+static u3j_core _136_hex_aes_sivb_d[] =
+ { { "en", 7, _136_hex_aes_sivb_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_sivb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}};
+static u3j_harm _136_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}};
+static u3j_core _136_hex_aes_sivc_d[] =
+ { { "en", 7, _136_hex_aes_sivc_en_a, 0, no_hashes },
+ { "de", 7, _136_hex_aes_sivc_de_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _136_hex_aes_d[] =
+ { { "ecba", 7, 0, _136_hex_aes_ecba_d, no_hashes },
+ { "ecbb", 7, 0, _136_hex_aes_ecbb_d, no_hashes },
+ { "ecbc", 7, 0, _136_hex_aes_ecbc_d, no_hashes },
+ { "cbca", 7, 0, _136_hex_aes_cbca_d, no_hashes },
+ { "cbcb", 7, 0, _136_hex_aes_cbcb_d, no_hashes },
+ { "cbcc", 7, 0, _136_hex_aes_cbcc_d, no_hashes },
+ { "siva", 7, 0, _136_hex_aes_siva_d, no_hashes },
+ { "sivb", 7, 0, _136_hex_aes_sivb_d, no_hashes },
+ { "sivc", 7, 0, _136_hex_aes_sivc_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_leer_a[] = {{".2", u3we_leer}, {}};
+static u3j_harm _136_hex_lore_a[] = {{".2", u3we_lore}, {}};
+static u3j_harm _136_hex_loss_a[] = {{".2", u3we_loss}, {}};
+static u3j_harm _136_hex_lune_a[] = {{".2", u3we_lune}, {}};
+
+
+static u3j_harm _136_hex__adler32_a[] = {{".2", u3we_adler32, c3y}, {}};
+static u3j_core _136_hex__adler_d[] =
+ { { "adler32", 7, _136_hex__adler32_a, 0, no_hashes },
+ {}
+ };
+static u3j_harm _136_hex__crc32_a[] = {{".2", u3we_crc32}, {}};
+static u3j_core _136_hex__crc_d[] =
+ { {"crc32", 7, _136_hex__crc32_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _136_hex_checksum_d[] =
+ { { "adler", 3, 0, _136_hex__adler_d, no_hashes },
+ { "crc", 3, 0, _136_hex__crc_d, no_hashes},
+ {}
+ };
+
+
+static u3j_harm _136_hex__decompress_zlib_a[] = {{".2", u3we_decompress_zlib}, {}};
+static u3j_harm _136_hex__decompress_gzip_a[] = {{".2", u3we_decompress_gzip}, {}};
+static u3j_core _136_hex__zlib_d[] = {
+ {"decompress-zlib", 7, _136_hex__decompress_zlib_a, 0, no_hashes },
+ {"decompress-gzip", 7, _136_hex__decompress_gzip_a, 0, no_hashes },
+ {}};
+
+
+static u3j_harm _136_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}};
+static u3j_harm _136_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}};
+static u3j_harm _136_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}};
+
+static u3j_harm _136_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}};
+static u3j_harm _136_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}};
+static u3j_harm _136_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}};
+static u3j_harm _136_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}};
+static u3j_harm _136_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}};
+static u3j_harm _136_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}};
+static u3j_harm _136_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}};
+static u3j_harm _136_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}};
+static u3j_harm _136_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}};
+static u3j_harm _136_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}};
+
+static u3j_harm _136_hex_coed__ed_smac_a[] =
+ {{".2", u3wee_smac}, {}};
+
+static u3j_harm _136_hex_coed__ed_recs_a[] =
+ {{".2", u3wee_recs}, {}};
+
+static u3j_harm _136_hex_coed__ed_point_neg_a[] =
+ {{".2", u3wee_point_neg}, {}};
+
+static u3j_harm _136_hex_coed__ed_point_add_a[] =
+ {{".2", u3wee_point_add}, {}};
+
+static u3j_harm _136_hex_coed__ed_scalarmult_a[] =
+ {{".2", u3wee_scalarmult}, {}};
+
+static u3j_harm _136_hex_coed__ed_scalarmult_base_a[] =
+ {{".2", u3wee_scalarmult_base}, {}};
+
+static u3j_harm _136_hex_coed__ed_add_scalarmult_scalarmult_base_a[] =
+ {{".2", u3wee_add_scalarmult_scalarmult_base}, {}};
+
+static u3j_harm _136_hex_coed__ed_add_double_scalarmult_a[] =
+ {{".2", u3wee_add_double_scalarmult}, {}};
+
+static u3j_core _136_hex_coed__ed_d[] =
+ { { "sign", 7, _136_hex_coed__ed_sign_a, 0, no_hashes },
+ { "sign-raw", 7, _136_hex_coed__ed_sign_raw_a, 0, no_hashes },
+ { "sign-octs", 7, _136_hex_coed__ed_sign_octs_a, 0, no_hashes },
+ { "sign-octs-raw", 7, _136_hex_coed__ed_sign_octs_raw_a, 0, no_hashes },
+ { "puck", 7, _136_hex_coed__ed_puck_a, 0, no_hashes },
+ { "luck", 7, _136_hex_coed__ed_luck_a, 0, no_hashes },
+ { "scad", 7, _136_hex_coed__ed_scad_a, 0, no_hashes },
+ { "scas", 7, _136_hex_coed__ed_scas_a, 0, no_hashes },
+ { "scap", 7, _136_hex_coed__ed_scap_a, 0, no_hashes },
+ { "veri-octs", 7, _136_hex_coed__ed_veri_octs_a, 0, no_hashes },
+ { "veri", 7, _136_hex_coed__ed_veri_a, 0, no_hashes },
+ { "shar", 7, _136_hex_coed__ed_shar_a, 0, no_hashes },
+ { "slar", 7, _136_hex_coed__ed_slar_a, 0, no_hashes },
+ { "point-add", 7, _136_hex_coed__ed_point_add_a, 0, 0 },
+ { "point-neg", 7, _136_hex_coed__ed_point_neg_a, 0, 0 },
+ { "recs", 7, _136_hex_coed__ed_recs_a, 0, 0 },
+ { "smac", 7, _136_hex_coed__ed_smac_a, 0, 0 },
+ { "scalarmult", 7, _136_hex_coed__ed_scalarmult_a, 0,
+ no_hashes },
+ { "scalarmult-base", 7, _136_hex_coed__ed_scalarmult_base_a, 0,
+ no_hashes },
+ { "add-scalarmult-scalarmult-base", 7,
+ _136_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0,
+ no_hashes },
+ { "add-double-scalarmult", 7,
+ _136_hex_coed__ed_add_double_scalarmult_a, 0,
+ no_hashes },
+ {}
+ };
+
+static u3j_core _136_hex_coed_d[] =
+ { { "ed", 3, 0, _136_hex_coed__ed_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}};
+static u3j_core _136_hex_hmac_d[] =
+ { { "hmac", 7, _136_hex_hmac_hmac_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_argon2_a[] = {{".2", u3we_argon2}, {}};
+static u3j_core _136_hex_argon_d[] =
+ { { "argon2", 511, _136_hex_argon2_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}};
+static u3j_harm _136_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}};
+static u3j_harm _136_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}};
+static u3j_harm _136_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}};
+static u3j_core _136_hex_scr_d[] =
+ { { "pbk", 7, _136_hex_scr_pbk_a, 0, no_hashes },
+ { "pbl", 7, _136_hex_scr_pbl_a, 0, no_hashes },
+ { "hsh", 7, _136_hex_scr_hsh_a, 0, no_hashes },
+ { "hsl", 7, _136_hex_scr_hsl_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}};
+static u3j_harm _136_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}};
+static u3j_harm _136_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}};
+
+static u3j_harm _136_hex_secp_secp256k1_schnorr_sosi_a[] =
+ {{".2", u3we_sosi}, {}};
+static u3j_harm _136_hex_secp_secp256k1_schnorr_sove_a[] =
+ {{".2", u3we_sove}, {}};
+static u3j_core _136_hex_secp_secp256k1_schnorr_d[] =
+ { { "sosi", 7,
+ _136_hex_secp_secp256k1_schnorr_sosi_a, 0,
+ no_hashes },
+ { "sove", 7,
+ _136_hex_secp_secp256k1_schnorr_sove_a, 0,
+ no_hashes },
+ {}
+ };
+
+static u3j_core _136_hex_secp_secp256k1_d[] =
+ { { "make", 7, _136_hex_secp_secp256k1_make_a, 0, no_hashes },
+ { "sign", 7, _136_hex_secp_secp256k1_sign_a, 0, no_hashes },
+ { "reco", 7, _136_hex_secp_secp256k1_reco_a, 0, no_hashes },
+ { "schnorr", 7, 0,
+ _136_hex_secp_secp256k1_schnorr_d,
+ no_hashes },
+ {}
+ };
+static u3j_core _136_hex_secp_d[] =
+ { { "secp256k1", 3, 0, _136_hex_secp_secp256k1_d, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _136_hex_kecc_k224_a[] =
+ {{".2", u3we_kecc224, c3y, c3y, c3y}, {}};
+static u3j_harm _136_hex_kecc_k256_a[] =
+ {{".2", u3we_kecc256, c3y, c3y, c3y}, {}};
+static u3j_harm _136_hex_kecc_k384_a[] =
+ {{".2", u3we_kecc384, c3y, c3y, c3y}, {}};
+static u3j_harm _136_hex_kecc_k512_a[] =
+ {{".2", u3we_kecc512, c3y, c3y, c3y}, {}};
+static u3j_core _136_hex_kecc_d[] =
+ { { "k224", 7, _136_hex_kecc_k224_a, 0, no_hashes },
+ { "k256", 7, _136_hex_kecc_k256_a, 0, no_hashes },
+ { "k384", 7, _136_hex_kecc_k384_a, 0, no_hashes },
+ { "k512", 7, _136_hex_kecc_k512_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}};
+static u3j_core _136_hex_ripe_d[] =
+ { { "ripemd160", 7, _136_hex_ripemd_160_a, 0, no_hashes },
+ {}
+ };
+
+
+
+/* layer five
+ */
+static u3j_harm _136_pen_cell_a[] = {{".2", u3wf_cell}, {}};
+static u3j_harm _136_pen_comb_a[] = {{".2", u3wf_comb}, {}};
+static u3j_harm _136_pen_cons_a[] = {{".2", u3wf_cons}, {}};
+static u3j_harm _136_pen_core_a[] = {{".2", u3wf_core}, {}};
+static u3j_harm _136_pen_face_a[] = {{".2", u3wf_face}, {}};
+static u3j_harm _136_pen_fitz_a[] = {{".2", u3wf_fitz}, {}};
+static u3j_harm _136_pen_fork_a[] = {{".2", u3wf_fork}, {}};
+
+static u3j_harm _136_pen_look_a[] = {{".2", u3wf_look}, {}};
+static u3j_harm _136_pen_loot_a[] = {{".2", u3wf_loot}, {}};
+
+static u3j_harm _136_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}};
+static u3j_harm _136_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}};
+static u3j_harm _136_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}};
+static u3j_harm _136_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}};
+static u3j_harm _136_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}};
+static u3j_harm _136_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}};
+
+static u3j_harm _136_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}};
+static u3j_core _136_pen__ut_nest_in_d[] =
+ {
+ { "nest-dext", 3, _136_pen__ut_nest_dext_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _136_pen__ut_nest_d[] =
+ {
+ { "nest-in", 7, 0, _136_pen__ut_nest_in_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}};
+
+static u3j_core _136_pen__ut_d[] =
+ {
+ { "crop", 7, _136_pen__ut_crop_a, 0, no_hashes },
+ { "fish", 7, _136_pen__ut_fish_a, 0, no_hashes },
+ { "fuse", 7, _136_pen__ut_fuse_a, 0, no_hashes },
+ { "redo", 7, _136_pen__ut_redo_a, 0, no_hashes },
+ { "mint", 7, _136_pen__ut_mint_a, 0, no_hashes },
+ { "mull", 7, _136_pen__ut_mull_a, 0, no_hashes },
+ { "nest", 7, 0, _136_pen__ut_nest_d, no_hashes },
+ { "rest", 7, _136_pen__ut_rest_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_hood _136_pen__ut_ho[] =
+ { { "ar", 12282 },
+ { "fan", 28, c3n },
+ { "rib", 58, c3n },
+ { "vet", 59, c3n },
+
+ { "blow", 6015 },
+ { "burp", 342 },
+ { "busk", 1363 },
+ { "buss", 374 },
+ { "crop", 1494 },
+ { "duck", 1524 },
+ { "dune", 2991 },
+ { "dunk", 3066 },
+ { "epla", 12206 },
+ { "emin", 1534 },
+ { "emul", 6134 },
+ { "feel", 1502 },
+ { "felt", 94 },
+ { "fine", 49086 },
+ { "fire", 4 },
+ { "fish", 6006 },
+ { "fond", 12283 },
+ { "fund", 6014 },
+ // XX +funk is not part of +ut, and this hook appears to be unused
+ // remove from here and the +ut hint
+ //
+ { "funk", 0xbefafa, c3y, 31 },
+ { "fuse", 24021 },
+ { "gain", 380 },
+ { "lose", 0x2fefe },
+ { "mile", 382 },
+ { "mine", 372 },
+ { "mint", 49083 },
+ { "moot", 0x2feff },
+ { "mull", 24020 },
+ { "nest", 92 },
+ { "peel", 1526 },
+ { "play", 3006 },
+ { "peek", 1532 },
+ { "repo", 22 },
+ { "rest", 6102 },
+ { "tack", 6007 },
+ { "toss", 24540 },
+ { "wrap", 6136 },
+ {},
+ };
+
+
+static u3j_hood _136_pen_ho[] = {
+ { "ap", 22 },
+ { "ut", 86 },
+ {},
+};
+
+
+/* layer four
+ */
+static u3j_harm _136_qua_trip_a[] = {{".2", u3we_trip}, {}};
+
+static u3j_harm _136_qua_slaw_a[] = {{".2", u3we_slaw}, {}};
+static u3j_harm _136_qua_scot_a[] = {{".2", u3we_scot}, {}};
+static u3j_harm _136_qua_scow_a[] = {{".2", u3we_scow}, {}};
+
+static u3j_harm _136_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}};
+static u3j_harm _136_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}};
+static u3j_harm _136_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}};
+static u3j_harm _136_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}};
+static u3j_core _136_qua__po_d[] =
+ { { "ind", 7, _136_qua__po_ind_a, 0, no_hashes },
+ { "ins", 7, _136_qua__po_ins_a, 0, no_hashes },
+ { "tod", 7, _136_qua__po_tod_a, 0, no_hashes },
+ { "tos", 7, _136_qua__po_tos_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}};
+static u3j_core _136_qua__bend_d[] =
+ { { "fun", 7, _136_qua__bend_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}};
+static u3j_core _136_qua__cold_d[] =
+ { { "fun", 7, _136_qua__cold_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}};
+static u3j_core _136_qua__cook_d[] =
+ { { "fun", 7, _136_qua__cook_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}};
+static u3j_core _136_qua__comp_d[] =
+ { { "fun", 7, _136_qua__comp_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}};
+static u3j_core _136_qua__easy_d[] =
+ { { "fun", 7, _136_qua__easy_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}};
+static u3j_core _136_qua__glue_d[] =
+ { { "fun", 7, _136_qua__glue_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}};
+static u3j_core _136_qua__here_d[] =
+ { { "fun", 7, _136_qua__here_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}};
+static u3j_core _136_qua__just_d[] =
+ { { "fun", 7, _136_qua__just_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}};
+static u3j_core _136_qua__mask_d[] =
+ { { "fun", 7, _136_qua__mask_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}};
+static u3j_core _136_qua__shim_d[] =
+ { { "fun", 7, _136_qua__shim_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}};
+static u3j_core _136_qua__stag_d[] =
+ { { "fun", 7, _136_qua__stag_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}};
+static u3j_core _136_qua__stew_d[] =
+ { { "fun", 31, _136_qua__stew_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}};
+static u3j_core _136_qua__stir_d[] =
+ { { "fun", 7, _136_qua__stir_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_qua_pfix_a[] = {{".2", u3we_pfix}, {}};
+
+static u3j_harm _136_qua_plug_a[] = {{".2", u3we_plug}, {}};
+static u3j_harm _136_qua_pose_a[] = {{".2", u3we_pose}, {}};
+
+static u3j_harm _136_qua_sfix_a[] = {{".2", u3we_sfix}, {}};
+
+static u3j_harm _136_qua_mink_a[] = {{".2", u3we_mink}, {}};
+static u3j_harm _136_qua_mole_a[] = {{".2", u3we_mole}, {}};
+static u3j_harm _136_qua_mule_a[] = {{".2", u3we_mule}, {}};
+
+
+static u3j_hood _136_qua_ho[] = {
+ { "show", 188 },
+ {},
+};
+
+
+/* layer three
+ */
+static u3j_harm _136_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}};
+static u3j_harm _136_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}};
+static u3j_core _136_tri__cofl_d[] =
+ { { "drg", 7, _136_tri__cofl__drg_a, 0, no_hashes },
+ { "lug", 7, _136_tri__cofl__lug_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__rd_add_a[] = {{".2", u3wer_add}, {}};
+static u3j_harm _136_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}};
+static u3j_harm _136_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}};
+static u3j_harm _136_tri__rd_div_a[] = {{".2", u3wer_div}, {}};
+static u3j_harm _136_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}};
+static u3j_harm _136_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}};
+static u3j_harm _136_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}};
+static u3j_harm _136_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}};
+static u3j_harm _136_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}};
+static u3j_harm _136_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}};
+static u3j_harm _136_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}};
+static u3j_core _136_tri__rd_d[] =
+ { { "add", 7, _136_tri__rd_add_a, 0, no_hashes },
+ { "sub", 7, _136_tri__rd_sub_a, 0, no_hashes },
+ { "mul", 7, _136_tri__rd_mul_a, 0, no_hashes },
+ { "div", 7, _136_tri__rd_div_a, 0, no_hashes },
+ { "sqt", 7, _136_tri__rd_sqt_a, 0, no_hashes },
+ { "fma", 7, _136_tri__rd_fma_a, 0, no_hashes },
+ { "lth", 7, _136_tri__rd_lth_a, 0, no_hashes },
+ { "lte", 7, _136_tri__rd_lte_a, 0, no_hashes },
+ { "equ", 7, _136_tri__rd_equ_a, 0, no_hashes },
+ { "gte", 7, _136_tri__rd_gte_a, 0, no_hashes },
+ { "gth", 7, _136_tri__rd_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__rs_add_a[] = {{".2", u3wet_add}, {}};
+static u3j_harm _136_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}};
+static u3j_harm _136_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}};
+static u3j_harm _136_tri__rs_div_a[] = {{".2", u3wet_div}, {}};
+static u3j_harm _136_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}};
+static u3j_harm _136_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}};
+static u3j_harm _136_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}};
+static u3j_harm _136_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}};
+static u3j_harm _136_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}};
+static u3j_harm _136_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}};
+static u3j_harm _136_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}};
+static u3j_core _136_tri__rs_d[] =
+ { { "add", 7, _136_tri__rs_add_a, 0, no_hashes },
+ { "sub", 7, _136_tri__rs_sub_a, 0, no_hashes },
+ { "mul", 7, _136_tri__rs_mul_a, 0, no_hashes },
+ { "div", 7, _136_tri__rs_div_a, 0, no_hashes },
+ { "sqt", 7, _136_tri__rs_sqt_a, 0, no_hashes },
+ { "fma", 7, _136_tri__rs_fma_a, 0, no_hashes },
+ { "lth", 7, _136_tri__rs_lth_a, 0, no_hashes },
+ { "lte", 7, _136_tri__rs_lte_a, 0, no_hashes },
+ { "equ", 7, _136_tri__rs_equ_a, 0, no_hashes },
+ { "gte", 7, _136_tri__rs_gte_a, 0, no_hashes },
+ { "gth", 7, _136_tri__rs_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__rq_add_a[] = {{".2", u3weq_add}, {}};
+static u3j_harm _136_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}};
+static u3j_harm _136_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}};
+static u3j_harm _136_tri__rq_div_a[] = {{".2", u3weq_div}, {}};
+static u3j_harm _136_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}};
+static u3j_harm _136_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}};
+static u3j_harm _136_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}};
+static u3j_harm _136_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}};
+static u3j_harm _136_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}};
+static u3j_harm _136_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}};
+static u3j_harm _136_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}};
+static u3j_core _136_tri__rq_d[] =
+ { { "add", 7, _136_tri__rq_add_a, 0, no_hashes },
+ { "sub", 7, _136_tri__rq_sub_a, 0, no_hashes },
+ { "mul", 7, _136_tri__rq_mul_a, 0, no_hashes },
+ { "div", 7, _136_tri__rq_div_a, 0, no_hashes },
+ { "sqt", 7, _136_tri__rq_sqt_a, 0, no_hashes },
+ { "fma", 7, _136_tri__rq_fma_a, 0, no_hashes },
+ { "lth", 7, _136_tri__rq_lth_a, 0, no_hashes },
+ { "lte", 7, _136_tri__rq_lte_a, 0, no_hashes },
+ { "equ", 7, _136_tri__rq_equ_a, 0, no_hashes },
+ { "gte", 7, _136_tri__rq_gte_a, 0, no_hashes },
+ { "gth", 7, _136_tri__rq_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__rh_add_a[] = {{".2", u3wes_add}, {}};
+static u3j_harm _136_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}};
+static u3j_harm _136_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}};
+static u3j_harm _136_tri__rh_div_a[] = {{".2", u3wes_div}, {}};
+static u3j_harm _136_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}};
+static u3j_harm _136_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}};
+static u3j_harm _136_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}};
+static u3j_harm _136_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}};
+static u3j_harm _136_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}};
+static u3j_harm _136_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}};
+static u3j_harm _136_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}};
+static u3j_core _136_tri__rh_d[] =
+ { { "add", 7, _136_tri__rh_add_a, 0, no_hashes },
+ { "sub", 7, _136_tri__rh_sub_a, 0, no_hashes },
+ { "mul", 7, _136_tri__rh_mul_a, 0, no_hashes },
+ { "div", 7, _136_tri__rh_div_a, 0, no_hashes },
+ { "sqt", 7, _136_tri__rh_sqt_a, 0, no_hashes },
+ { "fma", 7, _136_tri__rh_fma_a, 0, no_hashes },
+ { "lth", 7, _136_tri__rh_lth_a, 0, no_hashes },
+ { "lte", 7, _136_tri__rh_lte_a, 0, no_hashes },
+ { "equ", 7, _136_tri__rh_equ_a, 0, no_hashes },
+ { "gte", 7, _136_tri__rh_gte_a, 0, no_hashes },
+ { "gth", 7, _136_tri__rh_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__og_raw_a[] = {{".2", u3weo_raw}, {}};
+static u3j_core _136_tri__og_d[] =
+ { { "raw", 7, _136_tri__og_raw_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}};
+static u3j_core _136_tri__sha_d[] =
+ { { "sha1", 7, _136_tri__sha_sha1_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_tri_shax_a[] = {{".2", u3we_shax}, {}};
+static u3j_harm _136_tri_shay_a[] = {{".2", u3we_shay}, {}};
+static u3j_harm _136_tri_shas_a[] = {{".2", u3we_shas}, {}};
+static u3j_harm _136_tri_shal_a[] = {{".2", u3we_shal}, {}};
+
+static u3j_harm _136_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}};
+static u3j_harm _136_ob_fein_a[] = {{".2", u3we_fein_ob}, {}};
+static u3j_core _136_ob_d[] = {
+ { "fein", 7, _136_ob_fein_a, 0, no_hashes },
+ { "fynd", 7, _136_ob_fynd_a, 0, no_hashes },
+ {}
+};
+static u3j_hood _136_ob_ho[] = {
+ { "fein", 42 },
+ { "fynd", 20 },
+ {},
+};
+
+
+static u3j_hood _136_tri_ho[] = {
+ { "ob", 20 },
+ { "yore", 5462 },
+ { "year", 44975 },
+ {},
+};
+
+
+/* layer two
+ */
+static u3j_harm _136_two_find_a[] = {{".2", u3wb_find, c3y}, {}};
+static u3j_harm _136_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}};
+static u3j_harm _136_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}};
+static u3j_harm _136_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}};
+static u3j_harm _136_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}};
+static u3j_harm _136_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}};
+static u3j_harm _136_two_need_a[] = {{".2", u3wb_need, c3y}, {}};
+static u3j_harm _136_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}};
+static u3j_harm _136_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}};
+static u3j_harm _136_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}};
+static u3j_harm _136_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}};
+static u3j_harm _136_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}};
+static u3j_harm _136_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}};
+static u3j_harm _136_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}};
+static u3j_harm _136_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}};
+static u3j_harm _136_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}};
+static u3j_harm _136_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}};
+static u3j_harm _136_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}};
+static u3j_harm _136_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}};
+static u3j_harm _136_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}};
+static u3j_harm _136_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}};
+
+static u3j_harm _136_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}};
+static u3j_harm _136_two_can_a[] = {{".2", u3wc_can, c3y}, {}};
+static u3j_harm _136_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}};
+static u3j_harm _136_two_con_a[] = {{".2", u3wc_con, c3y}, {}};
+static u3j_harm _136_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}};
+static u3j_harm _136_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}};
+static u3j_harm _136_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}};
+static u3j_harm _136_two_end_a[] = {{".2", u3wc_end, c3y}, {}};
+static u3j_harm _136_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}};
+static u3j_harm _136_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}};
+static u3j_harm _136_two_met_a[] = {{".2", u3wc_met, c3y}, {}};
+static u3j_harm _136_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}};
+static u3j_harm _136_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}};
+static u3j_harm _136_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}};
+static u3j_harm _136_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}};
+static u3j_harm _136_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}};
+static u3j_harm _136_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}};
+static u3j_harm _136_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}};
+static u3j_harm _136_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}};
+static u3j_harm _136_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}};
+static u3j_harm _136_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}};
+static u3j_harm _136_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}};
+static u3j_harm _136_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}};
+static u3j_harm _136_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}};
+
+static u3j_harm _136_two__in_bif_a[] = {{".2", u3wdi_bif}, {}};
+static u3j_harm _136_two__in_del_a[] = {{".2", u3wdi_del}, {}};
+static u3j_harm _136_two__in_dif_a[] = {{".2", u3wdi_dif}, {}};
+static u3j_harm _136_two__in_gas_a[] = {{".2", u3wdi_gas}, {}};
+static u3j_harm _136_two__in_has_a[] = {{".2", u3wdi_has}, {}};
+static u3j_harm _136_two__in_int_a[] = {{".2", u3wdi_int}, {}};
+static u3j_harm _136_two__in_put_a[] = {{".2", u3wdi_put}, {}};
+static u3j_harm _136_two__in_rep_a[] = {{".2", u3wdi_rep}, {}};
+static u3j_harm _136_two__in_run_a[] = {{".2", u3wdi_run}, {}};
+static u3j_harm _136_two__in_tap_a[] = {{".2", u3wdi_tap}, {}};
+static u3j_harm _136_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}};
+static u3j_harm _136_two__in_uni_a[] = {{".2", u3wdi_uni}, {}};
+
+static u3j_harm _136_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}};
+static u3j_harm _136_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}};
+static u3j_harm _136_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}};
+
+static u3j_harm _136_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}};
+static u3j_harm _136_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}};
+static u3j_harm _136_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}};
+static u3j_harm _136_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}};
+static u3j_harm _136_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}};
+static u3j_harm _136_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}};
+static u3j_harm _136_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}};
+static u3j_harm _136_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}};
+static u3j_harm _136_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}};
+static u3j_harm _136_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}};
+static u3j_harm _136_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}};
+static u3j_harm _136_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}};
+static u3j_harm _136_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}};
+static u3j_harm _136_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}};
+static u3j_harm _136_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}};
+
+static u3j_harm _136_two_cue_a[] = {{".2", u3we_cue}, {}};
+static u3j_harm _136_two_jam_a[] = {{".2", u3we_jam}, {}};
+static u3j_harm _136_two_mat_a[] = {{".2", u3we_mat}, {}};
+static u3j_harm _136_two_rub_a[] = {{".2", u3we_rub}, {}};
+
+
+
+/* layer one
+ */
+static u3j_harm _136_one_add_a[] = {{".2", u3wa_add, c3y}, {}};
+static u3j_harm _136_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}};
+static u3j_harm _136_one_div_a[] = {{".2", u3wa_div, c3y}, {}};
+static u3j_harm _136_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}};
+static u3j_harm _136_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}};
+static u3j_harm _136_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}};
+static u3j_harm _136_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}};
+static u3j_harm _136_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}};
+static u3j_harm _136_one_max_a[] = {{".2", u3wa_max, c3y}, {}};
+static u3j_harm _136_one_min_a[] = {{".2", u3wa_min, c3y}, {}};
+static u3j_harm _136_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}};
+static u3j_harm _136_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}};
+static u3j_harm _136_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}};
+
+static u3j_harm _136_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}};
+static u3j_harm _136_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}};
+static u3j_harm _136_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}};
+
+static u3j_harm _136_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}};
+static u3j_harm _136_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}};
+
+static u3j_core _136_lull_plot_d[] =
+ { { "fax", 7, _136_lull_plot_fax_a, 0, no_hashes },
+ { "met", 7, _136_lull_plot_met_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _136_lull_d[] =
+ { { "plot", 31, 0, _136_lull_plot_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}};
+static u3j_harm _136_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}};
+static u3j_harm _136_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}};
+
+static u3j_core _136_hex_blake3_d[] =
+ { { "hash", 7, _136_hex_blake3_hash_a, 0, no_hashes },
+ { "chunk-output", 7, _136_hex_blake3_chunk_output_a, 0, no_hashes },
+ {}
+ };
+
+
+static u3j_core _136_hex_blake3_impl_d[] =
+ { { "compress", 7, _136_hex_blake3_compress_a, 0, no_hashes },
+ { "blake3", 7, 0, _136_hex_blake3_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}};
+
+static u3j_core _136_hex_blake_d[] =
+ { { "blake2b", 7, _136_hex_blake2b_a, 0, no_hashes },
+ { "blake3-impl", 7, 0, _136_hex_blake3_impl_d, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _136_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}};
+static u3j_harm _136_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}};
+static u3j_core _136_hex_chacha_d[] =
+ { { "crypt", 7, _136_hex_chacha_crypt_a, 0, no_hashes },
+ { "xchacha", 7, _136_hex_chacha_xchacha_a, 0, no_hashes },
+ {}
+ };
+
+
+//+| %utilities
+static u3j_harm _136_hex_bytestream_rip_octs_a[] = {{".2", u3we_bytestream_rip_octs, c3y}, {}};
+static u3j_harm _136_hex_bytestream_cat_octs_a[] = {{".2", u3we_bytestream_cat_octs, c3y}, {}};
+static u3j_harm _136_hex_bytestream_can_octs_a[] = {{".2", u3we_bytestream_can_octs, c3y}, {}};
+//+| %read-byte
+static u3j_harm _136_hex_bytestream_read_byte_a[] = {{".2", u3we_bytestream_read_byte, c3y}, {}};
+//+| %read-octs
+static u3j_harm _136_hex_bytestream_read_octs_a[] = {{".2", u3we_bytestream_read_octs, c3y}, {}};
+//+| %navigation
+static u3j_harm _136_hex_bytestream_skip_line_a[] = {{".2", u3we_bytestream_skip_line, c3y}, {}};
+static u3j_harm _136_hex_bytestream_find_byte_a[] = {{".2", u3we_bytestream_find_byte, c3y}, {}};
+static u3j_harm _136_hex_bytestream_seek_byte_a[] = {{".2", u3we_bytestream_seek_byte, c3y}, {}};
+//+| %transformation
+static u3j_harm _136_hex_bytestream_chunk_a[] = {{".2", u3we_bytestream_chunk}, {}};
+static u3j_harm _136_hex_bytestream_extract_a[] = {{".2", u3we_bytestream_extract}, {}};
+static u3j_harm _136_hex_bytestream_fuse_extract_a[] = {{".2", u3we_bytestream_fuse_extract}, {}};
+//+| %bitstream
+static u3j_harm _136_hex_bytestream_need_bits_a[] = {{".2", u3we_bytestream_need_bits}, {}};
+static u3j_harm _136_hex_bytestream_drop_bits_a[] = {{".2", u3we_bytestream_drop_bits}, {}};
+// static u3j_harm _136_hex_bytestream_skip_bits_a[] = {{".2", u3we_bytestream_skip_bits}, {}};
+static u3j_harm _136_hex_bytestream_peek_bits_a[] = {{".2", u3we_bytestream_peek_bits}, {}};
+static u3j_harm _136_hex_bytestream_read_bits_a[] = {{".2", u3we_bytestream_read_bits}, {}};
+// static u3j_harm _136_hex_bytestream_read_need_bits_a[] = {{".2", u3we_bytestream_read_need_bits}, {}};
+static u3j_harm _136_hex_bytestream_byte_bits_a[] = {{".2", u3we_bytestream_byte_bits}, {}};
+
+static u3j_core _136_hex_bytestream_d[] =
+ { //+| %utilities
+ {"rip-octs", 7, _136_hex_bytestream_rip_octs_a, 0, no_hashes },
+ {"cat-octs", 7, _136_hex_bytestream_cat_octs_a, 0, no_hashes },
+ {"can-octs", 7, _136_hex_bytestream_can_octs_a, 0, no_hashes },
+ //+| %navigation
+ {"skip-line", 7, _136_hex_bytestream_skip_line_a, 0, no_hashes },
+ {"find-byte", 7, _136_hex_bytestream_find_byte_a, 0, no_hashes },
+ {"seek-byte", 7, _136_hex_bytestream_seek_byte_a, 0, no_hashes },
+ //+| %read-byte
+ {"read-byte", 7, _136_hex_bytestream_read_byte_a, 0, no_hashes },
+ //+| %read-octs
+ {"read-octs", 7, _136_hex_bytestream_read_octs_a, 0, no_hashes },
+ //+| %transformation
+ {"chunk", 7, _136_hex_bytestream_chunk_a, 0, no_hashes },
+ {"extract", 7, _136_hex_bytestream_extract_a, 0, no_hashes },
+ {"fuse-extract", 7, _136_hex_bytestream_fuse_extract_a, 0, no_hashes },
+ //+| %bitstream
+ {"need-bits", 7, _136_hex_bytestream_need_bits_a, 0, no_hashes },
+ {"drop-bits", 7, _136_hex_bytestream_drop_bits_a, 0, no_hashes },
+ // {"skip-bits", 7, _136_hex_bytestream_skip_bits_a, 0, no_hashes },
+ {"peek-bits", 7, _136_hex_bytestream_peek_bits_a, 0, no_hashes },
+ {"read-bits", 7, _136_hex_bytestream_read_bits_a, 0, no_hashes },
+ // {"read-need-bits", 7, _136_hex_bytestream_read_need_bits_a, 0, no_hashes },
+ {"byte-bits", 7, _136_hex_bytestream_byte_bits_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_hex_json_de_a[] = {{".2", u3we_json_de}, {}};
+static u3j_harm _136_hex_json_en_a[] = {{".2", u3we_json_en}, {}};
+static u3j_core _136_hex_json_d[] =
+ { { "de", 15, _136_hex_json_de_a, 0, no_hashes },
+ { "en", 15, _136_hex_json_en_a, 0, no_hashes },
+ {}
+ };
+
+/* /lib jets in non core
+*/
+static u3j_harm _136_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}};
+static u3j_harm _136_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}};
+static u3j_harm _136_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}};
+static u3j_harm _136_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}};
+static u3j_harm _136_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}};
+static u3j_harm _136_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}};
+static u3j_harm _136_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}};
+static u3j_harm _136_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}};
+static u3j_harm _136_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}};
+static u3j_harm _136_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}};
+static u3j_harm _136_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}};
+static u3j_harm _136_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}};
+static u3j_harm _136_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}};
+static u3j_harm _136_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}};
+static u3j_harm _136_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}};
+static u3j_harm _136_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}};
+static u3j_harm _136_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}};
+static u3j_harm _136_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}};
+static u3j_harm _136_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}};
+static u3j_harm _136_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}};
+static u3j_harm _136_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}};
+static u3j_harm _136_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}};
+static u3j_harm _136_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}};
+static u3j_harm _136_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}};
+static u3j_harm _136_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}};
+static u3j_harm _136_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}};
+static u3j_harm _136_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}};
+static u3j_harm _136_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}};
+static u3j_harm _136_non__mice_a[] = {{".2", u3we_mice}, {}};
+
+static u3j_core _136_non__la_core_d[] =
+ { { "add-rays", 7, _136_non__lagoon_add_a, 0, no_hashes },
+ { "sub-rays", 7, _136_non__lagoon_sub_a, 0, no_hashes },
+ { "mul-rays", 7, _136_non__lagoon_mul_a, 0, no_hashes },
+ { "div-rays", 7, _136_non__lagoon_div_a, 0, no_hashes },
+ { "mod-rays", 7, _136_non__lagoon_mod_a, 0, no_hashes },
+ { "add-scal", 7, _136_non__lagoon_adds_a, 0, no_hashes },
+ { "sub-scal", 7, _136_non__lagoon_subs_a, 0, no_hashes },
+ { "mul-scal", 7, _136_non__lagoon_muls_a, 0, no_hashes },
+ { "div-scal", 7, _136_non__lagoon_divs_a, 0, no_hashes },
+ { "mod-scal", 7, _136_non__lagoon_mods_a, 0, no_hashes },
+ { "dot", 7, _136_non__lagoon_dot_a, 0, no_hashes },
+ { "transpose",7, _136_non__lagoon_trans_a, 0, no_hashes },
+ { "cumsum", 7, _136_non__lagoon_cumsum_a, 0, no_hashes },
+ { "argmin", 7, _136_non__lagoon_argmin_a, 0, no_hashes },
+ { "argmax", 7, _136_non__lagoon_argmax_a, 0, no_hashes },
+ { "ravel", 7, _136_non__lagoon_ravel_a, 0, no_hashes },
+ { "min", 7, _136_non__lagoon_min_a, 0, no_hashes },
+ { "max", 7, _136_non__lagoon_max_a, 0, no_hashes },
+ { "linspace", 7, _136_non__lagoon_linspace_a, 0, no_hashes },
+ { "range", 7, _136_non__lagoon_range_a, 0, no_hashes },
+ { "abs", 7, _136_non__lagoon_abs_a, 0, no_hashes },
+ { "gth", 7, _136_non__lagoon_gth_a, 0, no_hashes },
+ { "gte", 7, _136_non__lagoon_gte_a, 0, no_hashes },
+ { "lth", 7, _136_non__lagoon_lth_a, 0, no_hashes },
+ { "lte", 7, _136_non__lagoon_lte_a, 0, no_hashes },
+ { "diag", 7, _136_non__lagoon_diag_a, 0, no_hashes },
+ { "trace", 7, _136_non__lagoon_trace_a,0, no_hashes },
+ { "mmul", 7, _136_non__lagoon_mmul_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _136_non_d[] =
+ { { "lagoon", 7, 0, _136_non__la_core_d, no_hashes },
+ { "mice", 7, _136_non__mice_a, 0, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _136_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}};
+
+static u3j_harm _136_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}};
+
+static u3j_core _136_hex_lia_run_once_d[] = {
+ { "run-once-inner-v0", 15, _136_hex_lia_run_once_inner_a, 0, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_lia_monad_d[] = {
+ { "run-v1", 7, _136_hex_lia_run_v1_a, 0, no_hashes },
+ { "run-once-v0", 7, 0, _136_hex_lia_run_once_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_engine_d[] = {
+ { "monad-v0", 3, 0, _136_hex_lia_monad_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_op_def_d[] = {
+ { "wasm-engine-v0", 3, 0, _136_hex_wasm_engine_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_validator_d[] = {
+ { "wasm-op-def-v0", 3, 0, _136_hex_wasm_op_def_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_parser_d[] = {
+ { "validator-v0", 3, 0, _136_hex_wasm_validator_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_lia_sur_d[] = {
+ { "wasm-parser-v0", 3, 0, _136_hex_wasm_parser_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_engine_sur_d[] = {
+ { "monad-sur-v1", 3, 0, _136_hex_lia_sur_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_wasm_sur_d[] = {
+ { "engine-sur-v0", 3, 0, _136_hex_wasm_engine_sur_d, no_hashes },
+ {}
+};
+
+static u3j_core _136_hex_d[] =
+ { { "non", 7, 0, _136_non_d, no_hashes },
+
+ { "lull", 3, 0, _136_lull_d, no_hashes },
+
+ { "lore", 63, _136_hex_lore_a, 0, no_hashes },
+
+ { "leer", 63, _136_hex_leer_a, 0, no_hashes },
+ { "loss", 63, _136_hex_loss_a, 0, no_hashes },
+ { "lune", 127, _136_hex_lune_a, 0, no_hashes },
+
+ { "crc", 31, 0, _136_hex__crc_d, no_hashes },
+
+ { "coed", 63, 0, _136_hex_coed_d, no_hashes },
+ { "aes", 31, 0, _136_hex_aes_d, no_hashes },
+
+ { "hmac", 63, 0, _136_hex_hmac_d, no_hashes },
+ { "argon", 31, 0, _136_hex_argon_d, no_hashes },
+ { "blake", 31, 0, _136_hex_blake_d, no_hashes },
+ { "chacha", 31, 0, _136_hex_chacha_d, no_hashes },
+ { "kecc", 31, 0, _136_hex_kecc_d, no_hashes },
+ { "ripemd", 31, 0, _136_hex_ripe_d, no_hashes },
+ { "scr", 31, 0, _136_hex_scr_d, no_hashes },
+ { "secp", 6, 0, _136_hex_secp_d, no_hashes },
+ { "mimes", 31, 0, _136_hex_mimes_d, no_hashes },
+ { "json", 31, 0, _136_hex_json_d, no_hashes },
+ { "checksum", 15, 0, _136_hex_checksum_d, no_hashes},
+ { "wasm-sur-v0", 3, 0, _136_hex_wasm_sur_d, no_hashes },
+ { "bytestream-v0", 31, 0, _136_hex_bytestream_d, no_hashes},
+ { "zlib-v0", 31, 0, _136_hex__zlib_d, no_hashes },
+ {}
+ };
+
+static u3j_core _136_pen_d[] =
+ { { "hex", 7, 0, _136_hex_d, no_hashes },
+
+ { "cell", 7, _136_pen_cell_a, 0, no_hashes },
+ { "comb", 7, _136_pen_comb_a, 0, no_hashes },
+ { "cons", 7, _136_pen_cons_a, 0, no_hashes },
+ { "core", 7, _136_pen_core_a, 0, no_hashes },
+ { "face", 7, _136_pen_face_a, 0, no_hashes },
+ { "fitz", 7, _136_pen_fitz_a, 0, no_hashes },
+ { "fork", 7, _136_pen_fork_a, 0, no_hashes },
+ { "look", 7, _136_pen_look_a, 0, no_hashes },
+ { "loot", 7, _136_pen_loot_a, 0, no_hashes },
+ { "ut", 15, 0, _136_pen__ut_d, no_hashes, _136_pen__ut_ho },
+ {}
+ };
+
+static u3j_core _136_qua__vi_d[] =
+ {
+ { "mole", 7, _136_qua_mole_a, 0, no_hashes },
+ { "mule", 7, _136_qua_mule_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _136_qua_d[] =
+ { { "pen", 3, 0, _136_pen_d, no_hashes, _136_pen_ho },
+
+ { "po", 7, 0, _136_qua__po_d, no_hashes },
+
+ { "trip", 7, _136_qua_trip_a, 0, no_hashes },
+
+ { "bend", 7, 0, _136_qua__bend_d, no_hashes },
+ { "cold", 7, 0, _136_qua__cold_d, no_hashes },
+ { "comp", 7, 0, _136_qua__comp_d, no_hashes },
+ { "cook", 7, 0, _136_qua__cook_d, no_hashes },
+ { "easy", 7, 0, _136_qua__easy_d, no_hashes },
+ { "glue", 7, 0, _136_qua__glue_d, no_hashes },
+ { "here", 7, 0, _136_qua__here_d, no_hashes },
+ { "just", 7, 0, _136_qua__just_d, no_hashes },
+ { "mask", 7, 0, _136_qua__mask_d, no_hashes },
+ { "shim", 7, 0, _136_qua__shim_d, no_hashes },
+ { "stag", 7, 0, _136_qua__stag_d, no_hashes },
+ { "stew", 7, 0, _136_qua__stew_d, no_hashes },
+ { "stir", 7, 0, _136_qua__stir_d, no_hashes },
+
+ { "pfix", 7, _136_qua_pfix_a, 0, no_hashes },
+ { "plug", 7, _136_qua_plug_a, 0, no_hashes },
+ { "pose", 7, _136_qua_pose_a, 0, no_hashes },
+ { "sfix", 7, _136_qua_sfix_a, 0, no_hashes },
+
+ { "mink", 7, _136_qua_mink_a, 0, no_hashes },
+ { "vi", 7, 0, _136_qua__vi_d, no_hashes },
+
+ { "scot", 7, _136_qua_scot_a, 0, no_hashes },
+ { "scow", 7, _136_qua_scow_a, 0, no_hashes },
+ { "slaw", 7, _136_qua_slaw_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _136_tri_d[] =
+ { { "qua", 3, 0, _136_qua_d, no_hashes, _136_qua_ho },
+
+ { "cofl", 7, 0, _136_tri__cofl_d, no_hashes },
+ { "rd", 7, 0, _136_tri__rd_d, no_hashes },
+ { "rs", 7, 0, _136_tri__rs_d, no_hashes },
+ { "rq", 7, 0, _136_tri__rq_d, no_hashes },
+ { "rh", 7, 0, _136_tri__rh_d, no_hashes },
+ { "og", 7, 0, _136_tri__og_d, no_hashes },
+
+ { "sha", 7, 0, _136_tri__sha_d, no_hashes },
+ { "shax", 7, _136_tri_shax_a, 0, no_hashes },
+ { "shay", 7, _136_tri_shay_a, 0, no_hashes },
+ { "shas", 7, _136_tri_shas_a, 0, no_hashes },
+ { "shal", 7, _136_tri_shal_a, 0, no_hashes },
+
+ { "ob", 3, 0, _136_ob_d, no_hashes, _136_ob_ho },
+ {}
+ };
+
+static u3j_harm _136_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}};
+static u3j_harm _136_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}};
+static u3j_harm _136_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}};
+
+static u3j_harm _136_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}};
+static u3j_core _136_two__hew_d[] =
+ { { "fun", 15, _136_two__hew_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}};
+
+static u3j_core _136_two__by_d[] =
+ { { "all", 7, _136_two__by_all_a, 0, no_hashes },
+ { "any", 7, _136_two__by_any_a, 0, no_hashes },
+ { "apt", 7, _136_two__by_apt_a, 0, no_hashes },
+ { "bif", 7, _136_two__by_bif_a, 0, no_hashes },
+ { "del", 7, _136_two__by_del_a, 0, no_hashes },
+ { "dif", 7, _136_two__by_dif_a, 0, no_hashes },
+ { "gas", 7, _136_two__by_gas_a, 0, no_hashes },
+ { "get", 7, _136_two__by_get_a, 0, no_hashes },
+ { "has", 7, _136_two__by_has_a, 0, no_hashes },
+ { "int", 7, _136_two__by_int_a, 0, no_hashes },
+ { "jab", 7, _136_two__by_jab_a, 0, no_hashes },
+ { "key", 7, _136_two__by_key_a, 0, no_hashes },
+ { "put", 7, _136_two__by_put_a, 0, no_hashes },
+ { "rep", 7, _136_two__by_rep_a, 0, no_hashes },
+ { "run", 7, _136_two__by_run_a, 0, no_hashes },
+ { "tap", 7, _136_two__by_tap_a, 0, no_hashes },
+ { "uni", 7, _136_two__by_uni_a, 0, no_hashes },
+ { "urn", 7, _136_two__by_urn_a, 0, no_hashes },
+ { "wyt", 3, _136_two__by_wyt_a, 0, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _136_two__in_apt_a[] = {{".2", u3wdi_apt}, {}};
+
+static u3j_core _136_two__in_d[] =
+ { { "apt", 7, _136_two__in_apt_a, 0, no_hashes },
+ { "bif", 7, _136_two__in_bif_a, 0, no_hashes },
+ { "del", 7, _136_two__in_del_a, 0, no_hashes },
+ { "dif", 7, _136_two__in_dif_a, 0, no_hashes },
+ { "gas", 7, _136_two__in_gas_a, 0, no_hashes },
+ { "has", 7, _136_two__in_has_a, 0, no_hashes },
+ { "int", 7, _136_two__in_int_a, 0, no_hashes },
+ { "put", 7, _136_two__in_put_a, 0, no_hashes },
+ { "rep", 7, _136_two__in_rep_a, 0, no_hashes },
+ { "run", 7, _136_two__in_run_a, 0, no_hashes },
+ { "tap", 7, _136_two__in_tap_a, 0, no_hashes },
+ { "uni", 7, _136_two__in_uni_a, 0, no_hashes },
+ { "wyt", 3, _136_two__in_wyt_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _136_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}};
+
+static u3j_harm _136_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}};
+static u3j_harm _136_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}};
+
+static u3j_core _136_two_d[] =
+ { { "tri", 3, 0, _136_tri_d, no_hashes, _136_tri_ho },
+
+ { "find", 7, _136_two_find_a, 0, no_hashes },
+ { "flop", 7, _136_two_flop_a, 0, no_hashes },
+ { "lent", 7, _136_two_lent_a, 0, no_hashes },
+ { "levy", 7, _136_two_levy_a, 0, no_hashes },
+ { "lien", 7, _136_two_lien_a, 0, no_hashes },
+ { "murn", 7, _136_two_murn_a, 0, no_hashes },
+ { "need", 7, _136_two_need_a, 0, no_hashes },
+ { "mate", 7, _136_two_mate_a, 0, no_hashes },
+ { "reap", 7, _136_two_reap_a, 0, no_hashes },
+ { "reel", 7, _136_two_reel_a, 0, no_hashes },
+ { "roll", 7, _136_two_roll_a, 0, no_hashes },
+ { "skid", 7, _136_two_skid_a, 0, no_hashes },
+ { "skim", 7, _136_two_skim_a, 0, no_hashes },
+ { "skip", 7, _136_two_skip_a, 0, no_hashes },
+ { "scag", 7, _136_two_scag_a, 0, no_hashes },
+ { "slag", 7, _136_two_slag_a, 0, no_hashes },
+ { "snag", 7, _136_two_snag_a, 0, no_hashes },
+ { "sort", 7, _136_two_sort_a, 0, no_hashes },
+ { "turn", 7, _136_two_turn_a, 0, no_hashes },
+ { "weld", 7, _136_two_weld_a, 0, no_hashes },
+ { "welp", 7, _136_two_welp_a, 0, no_hashes },
+ { "zing", 7, _136_two_zing_a, 0, no_hashes },
+
+ { "bex", 7, _136_two_bex_a, 0, no_hashes },
+ { "cat", 7, _136_two_cat_a, 0, no_hashes },
+ { "can", 7, _136_two_can_a, 0, no_hashes },
+ { "clz", 7, _136_two_clz_a, 0, no_hashes },
+ { "con", 7, _136_two_con_a, 0, no_hashes },
+ { "ctz", 7, _136_two_ctz_a, 0, no_hashes },
+ { "cue", 7, _136_two_cue_a, 0, no_hashes },
+ { "cut", 7, _136_two_cut_a, 0, no_hashes },
+ { "dis", 7, _136_two_dis_a, 0, no_hashes },
+ { "dor", 7, _136_two_dor_a, 0, no_hashes },
+ { "end", 7, _136_two_end_a, 0, no_hashes },
+ { "gor", 7, _136_two_gor_a, 0, no_hashes },
+ { "ham", 7, _136_two_ham_a, 0, no_hashes },
+ { "hew", 7, 0, _136_two__hew_d, no_hashes },
+ { "jam", 7, _136_two_jam_a, 0, no_hashes },
+ { "lsh", 7, _136_two_lsh_a, 0, no_hashes },
+ { "mat", 7, _136_two_mat_a, 0, no_hashes },
+ { "met", 7, _136_two_met_a, 0, no_hashes },
+ { "mix", 7, _136_two_mix_a, 0, no_hashes },
+ { "mor", 7, _136_two_mor_a, 0, no_hashes },
+ { "mug", 7, _136_two_mug_a, 0, no_hashes },
+ { "muk", 7, _136_two_muk_a, 0, no_hashes },
+ { "rap", 7, _136_two_rap_a, 0, no_hashes },
+ { "rep", 7, _136_two_rep_a, 0, no_hashes },
+ { "rev", 7, _136_two_rev_a, 0, no_hashes },
+ { "rig", 7, _136_two_rig_a, 0, no_hashes },
+ { "rip", 7, _136_two_rip_a, 0, no_hashes },
+ { "rsh", 7, _136_two_rsh_a, 0, no_hashes },
+ { "swp", 7, _136_two_swp_a, 0, no_hashes },
+ { "rub", 7, _136_two_rub_a, 0, no_hashes },
+ { "pow", 7, _136_two_pow_a, 0, no_hashes },
+ { "sew", 7, _136_two_sew_a, 0, no_hashes },
+ { "sqt", 7, _136_two_sqt_a, 0, no_hashes },
+ { "xeb", 7, _136_two_xeb_a, 0, no_hashes },
+
+ { "by", 7, 0, _136_two__by_d, no_hashes },
+ { "in", 7, 0, _136_two__in_d, no_hashes },
+ {}
+ };
+
+static u3j_core _136_one_d[] =
+ { { "two", 3, 0, _136_two_d, no_hashes },
+
+ { "add", 7, _136_one_add_a, 0, no_hashes },
+ { "dec", 7, _136_one_dec_a, 0, no_hashes },
+ { "div", 7, _136_one_div_a, 0, no_hashes },
+ { "dvr", 7, _136_one_dvr_a, 0, no_hashes },
+ { "gte", 7, _136_one_gte_a, 0, no_hashes },
+ { "gth", 7, _136_one_gth_a, 0, no_hashes },
+ { "lte", 7, _136_one_lte_a, 0, no_hashes },
+ { "lth", 7, _136_one_lth_a, 0, no_hashes },
+ { "max", 7, _136_one_max_a, 0, no_hashes },
+ { "min", 7, _136_one_min_a, 0, no_hashes },
+ { "mod", 7, _136_one_mod_a, 0, no_hashes },
+ { "mul", 7, _136_one_mul_a, 0, no_hashes },
+ { "sub", 7, _136_one_sub_a, 0, no_hashes },
+
+ { "cap", 7, _136_one_cap_a, 0, no_hashes },
+ { "mas", 7, _136_one_mas_a, 0, no_hashes },
+ { "peg", 7, _136_one_peg_a, 0, no_hashes },
+ {}
+ };
+
+u3j_core _k136_d[] =
+ { { "one", 3, 0, _136_one_d, no_hashes },
+ {}
+ };
+
diff --git a/vere/pkg/noun/jets/137/tree.c b/vere/pkg/noun/jets/137/tree.c
new file mode 100644
index 0000000..9564135
--- /dev/null
+++ b/vere/pkg/noun/jets/137/tree.c
@@ -0,0 +1,1184 @@
+#include "c3/c3.h"
+#include "jets.h"
+#include "jets/w.h"
+
+
+static c3_c* no_hashes[] = { 0 };
+
+static u3j_harm _137_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}};
+static u3j_harm _137_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}};
+static u3j_core _137_hex_mimes_base16_d[] =
+ { { "en", 7, _137_hex_mimes_base16_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_mimes_base16_de_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _137_hex_mimes_d[] =
+ { { "base16", 3, 0, _137_hex_mimes_base16_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}};
+static u3j_harm _137_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}};
+static u3j_core _137_hex_aes_ecba_d[] =
+ { { "en", 7, _137_hex_aes_ecba_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_ecba_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}};
+static u3j_harm _137_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}};
+static u3j_core _137_hex_aes_ecbb_d[] =
+ { { "en", 7, _137_hex_aes_ecbb_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_ecbb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}};
+static u3j_harm _137_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}};
+static u3j_core _137_hex_aes_ecbc_d[] =
+ { { "en", 7, _137_hex_aes_ecbc_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_ecbc_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}};
+static u3j_harm _137_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}};
+static u3j_core _137_hex_aes_cbca_d[] =
+ { { "en", 7, _137_hex_aes_cbca_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_cbca_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}};
+static u3j_harm _137_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}};
+static u3j_core _137_hex_aes_cbcb_d[] =
+ { { "en", 7, _137_hex_aes_cbcb_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_cbcb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}};
+static u3j_harm _137_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}};
+static u3j_core _137_hex_aes_cbcc_d[] =
+ { { "en", 7, _137_hex_aes_cbcc_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_cbcc_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}};
+static u3j_harm _137_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}};
+static u3j_core _137_hex_aes_siva_d[] =
+ { { "en", 7, _137_hex_aes_siva_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_siva_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}};
+static u3j_harm _137_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}};
+static u3j_core _137_hex_aes_sivb_d[] =
+ { { "en", 7, _137_hex_aes_sivb_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_sivb_de_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}};
+static u3j_harm _137_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}};
+static u3j_core _137_hex_aes_sivc_d[] =
+ { { "en", 7, _137_hex_aes_sivc_en_a, 0, no_hashes },
+ { "de", 7, _137_hex_aes_sivc_de_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _137_hex_aes_d[] =
+ { { "ecba", 7, 0, _137_hex_aes_ecba_d, no_hashes },
+ { "ecbb", 7, 0, _137_hex_aes_ecbb_d, no_hashes },
+ { "ecbc", 7, 0, _137_hex_aes_ecbc_d, no_hashes },
+ { "cbca", 7, 0, _137_hex_aes_cbca_d, no_hashes },
+ { "cbcb", 7, 0, _137_hex_aes_cbcb_d, no_hashes },
+ { "cbcc", 7, 0, _137_hex_aes_cbcc_d, no_hashes },
+ { "siva", 7, 0, _137_hex_aes_siva_d, no_hashes },
+ { "sivb", 7, 0, _137_hex_aes_sivb_d, no_hashes },
+ { "sivc", 7, 0, _137_hex_aes_sivc_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_leer_a[] = {{".2", u3we_leer}, {}};
+static u3j_harm _137_hex_lore_a[] = {{".2", u3we_lore}, {}};
+static u3j_harm _137_hex_loss_a[] = {{".2", u3we_loss}, {}};
+static u3j_harm _137_hex_lune_a[] = {{".2", u3we_lune}, {}};
+
+
+static u3j_harm _137_hex__crc32_a[] = {{".2", u3we_crc32}, {}};
+
+static u3j_core _137_hex__crc_d[] = {{"crc32", 7, _137_hex__crc32_a, 0, no_hashes }, {}};
+
+
+static u3j_harm _137_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}};
+static u3j_harm _137_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}};
+static u3j_harm _137_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}};
+
+static u3j_harm _137_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}};
+static u3j_harm _137_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}};
+static u3j_harm _137_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}};
+static u3j_harm _137_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}};
+static u3j_harm _137_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}};
+static u3j_harm _137_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}};
+static u3j_harm _137_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}};
+static u3j_harm _137_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}};
+static u3j_harm _137_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}};
+static u3j_harm _137_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}};
+
+static u3j_harm _137_hex_coed__ed_smac_a[] =
+ {{".2", u3wee_smac}, {}};
+
+static u3j_harm _137_hex_coed__ed_recs_a[] =
+ {{".2", u3wee_recs}, {}};
+
+static u3j_harm _137_hex_coed__ed_point_neg_a[] =
+ {{".2", u3wee_point_neg}, {}};
+
+static u3j_harm _137_hex_coed__ed_point_add_a[] =
+ {{".2", u3wee_point_add}, {}};
+
+static u3j_harm _137_hex_coed__ed_scalarmult_a[] =
+ {{".2", u3wee_scalarmult}, {}};
+
+static u3j_harm _137_hex_coed__ed_scalarmult_base_a[] =
+ {{".2", u3wee_scalarmult_base}, {}};
+
+static u3j_harm _137_hex_coed__ed_add_scalarmult_scalarmult_base_a[] =
+ {{".2", u3wee_add_scalarmult_scalarmult_base}, {}};
+
+static u3j_harm _137_hex_coed__ed_add_double_scalarmult_a[] =
+ {{".2", u3wee_add_double_scalarmult}, {}};
+
+static u3j_core _137_hex_coed__ed_d[] =
+ { { "sign", 7, _137_hex_coed__ed_sign_a, 0, no_hashes },
+ { "sign-raw", 7, _137_hex_coed__ed_sign_raw_a, 0, no_hashes },
+ { "sign-octs", 7, _137_hex_coed__ed_sign_octs_a, 0, no_hashes },
+ { "sign-octs-raw", 7, _137_hex_coed__ed_sign_octs_raw_a, 0, no_hashes },
+ { "puck", 7, _137_hex_coed__ed_puck_a, 0, no_hashes },
+ { "luck", 7, _137_hex_coed__ed_luck_a, 0, no_hashes },
+ { "scad", 7, _137_hex_coed__ed_scad_a, 0, no_hashes },
+ { "scas", 7, _137_hex_coed__ed_scas_a, 0, no_hashes },
+ { "scap", 7, _137_hex_coed__ed_scap_a, 0, no_hashes },
+ { "veri-octs", 7, _137_hex_coed__ed_veri_octs_a, 0, no_hashes },
+ { "veri", 7, _137_hex_coed__ed_veri_a, 0, no_hashes },
+ { "shar", 7, _137_hex_coed__ed_shar_a, 0, no_hashes },
+ { "slar", 7, _137_hex_coed__ed_slar_a, 0, no_hashes },
+ { "point-add", 7, _137_hex_coed__ed_point_add_a, 0, 0 },
+ { "point-neg", 7, _137_hex_coed__ed_point_neg_a, 0, 0 },
+ { "recs", 7, _137_hex_coed__ed_recs_a, 0, 0 },
+ { "smac", 7, _137_hex_coed__ed_smac_a, 0, 0 },
+ { "scalarmult", 7, _137_hex_coed__ed_scalarmult_a, 0,
+ no_hashes },
+ { "scalarmult-base", 7, _137_hex_coed__ed_scalarmult_base_a, 0,
+ no_hashes },
+ { "add-scalarmult-scalarmult-base", 7,
+ _137_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0,
+ no_hashes },
+ { "add-double-scalarmult", 7,
+ _137_hex_coed__ed_add_double_scalarmult_a, 0,
+ no_hashes },
+ {}
+ };
+
+static u3j_core _137_hex_coed_d[] =
+ { { "ed", 3, 0, _137_hex_coed__ed_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}};
+static u3j_core _137_hex_hmac_d[] =
+ { { "hmac", 7, _137_hex_hmac_hmac_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_argon2_a[] = {{".2", u3we_argon2}, {}};
+static u3j_core _137_hex_argon_d[] =
+ { { "argon2", 511, _137_hex_argon2_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}};
+static u3j_harm _137_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}};
+static u3j_harm _137_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}};
+static u3j_harm _137_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}};
+static u3j_core _137_hex_scr_d[] =
+ { { "pbk", 7, _137_hex_scr_pbk_a, 0, no_hashes },
+ { "pbl", 7, _137_hex_scr_pbl_a, 0, no_hashes },
+ { "hsh", 7, _137_hex_scr_hsh_a, 0, no_hashes },
+ { "hsl", 7, _137_hex_scr_hsl_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}};
+static u3j_harm _137_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}};
+static u3j_harm _137_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}};
+
+static u3j_harm _137_hex_secp_secp256k1_schnorr_sosi_a[] =
+ {{".2", u3we_sosi}, {}};
+static u3j_harm _137_hex_secp_secp256k1_schnorr_sove_a[] =
+ {{".2", u3we_sove}, {}};
+static u3j_core _137_hex_secp_secp256k1_schnorr_d[] =
+ { { "sosi", 7,
+ _137_hex_secp_secp256k1_schnorr_sosi_a, 0,
+ no_hashes },
+ { "sove", 7,
+ _137_hex_secp_secp256k1_schnorr_sove_a, 0,
+ no_hashes },
+ {}
+ };
+
+static u3j_core _137_hex_secp_secp256k1_d[] =
+ { { "make", 7, _137_hex_secp_secp256k1_make_a, 0, no_hashes },
+ { "sign", 7, _137_hex_secp_secp256k1_sign_a, 0, no_hashes },
+ { "reco", 7, _137_hex_secp_secp256k1_reco_a, 0, no_hashes },
+ { "schnorr", 7, 0,
+ _137_hex_secp_secp256k1_schnorr_d,
+ no_hashes },
+ {}
+ };
+static u3j_core _137_hex_secp_d[] =
+ { { "secp256k1", 3, 0, _137_hex_secp_secp256k1_d, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _137_hex_kecc_k224_a[] =
+ {{".2", u3we_kecc224, c3y, c3y, c3y}, {}};
+static u3j_harm _137_hex_kecc_k256_a[] =
+ {{".2", u3we_kecc256, c3y, c3y, c3y}, {}};
+static u3j_harm _137_hex_kecc_k384_a[] =
+ {{".2", u3we_kecc384, c3y, c3y, c3y}, {}};
+static u3j_harm _137_hex_kecc_k512_a[] =
+ {{".2", u3we_kecc512, c3y, c3y, c3y}, {}};
+static u3j_core _137_hex_kecc_d[] =
+ { { "k224", 7, _137_hex_kecc_k224_a, 0, no_hashes },
+ { "k256", 7, _137_hex_kecc_k256_a, 0, no_hashes },
+ { "k384", 7, _137_hex_kecc_k384_a, 0, no_hashes },
+ { "k512", 7, _137_hex_kecc_k512_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}};
+static u3j_core _137_hex_ripe_d[] =
+ { { "ripemd160", 7, _137_hex_ripemd_160_a, 0, no_hashes },
+ {}
+ };
+
+
+
+/* layer five
+ */
+static u3j_harm _137_pen_cell_a[] = {{".2", u3wf_cell}, {}};
+static u3j_harm _137_pen_comb_a[] = {{".2", u3wf_comb}, {}};
+static u3j_harm _137_pen_cons_a[] = {{".2", u3wf_cons}, {}};
+static u3j_harm _137_pen_core_a[] = {{".2", u3wf_core}, {}};
+static u3j_harm _137_pen_face_a[] = {{".2", u3wf_face}, {}};
+static u3j_harm _137_pen_fitz_a[] = {{".2", u3wf_fitz}, {}};
+static u3j_harm _137_pen_fork_a[] = {{".2", u3wf_fork}, {}};
+
+static u3j_harm _137_pen_look_a[] = {{".2", u3wf_look}, {}};
+static u3j_harm _137_pen_loot_a[] = {{".2", u3wf_loot}, {}};
+
+static u3j_harm _137_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}};
+static u3j_harm _137_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}};
+static u3j_harm _137_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}};
+static u3j_harm _137_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}};
+static u3j_harm _137_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}};
+static u3j_harm _137_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}};
+
+static u3j_harm _137_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}};
+static u3j_core _137_pen__ut_nest_in_d[] =
+ {
+ { "nest-dext", 3, _137_pen__ut_nest_dext_a, 0, no_hashes },
+ {}
+ };
+static u3j_core _137_pen__ut_nest_d[] =
+ {
+ { "nest-in", 7, 0, _137_pen__ut_nest_in_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}};
+
+static u3j_core _137_pen__ut_d[] =
+ {
+ { "crop", 7, _137_pen__ut_crop_a, 0, no_hashes },
+ { "fish", 7, _137_pen__ut_fish_a, 0, no_hashes },
+ { "fuse", 7, _137_pen__ut_fuse_a, 0, no_hashes },
+ { "redo", 7, _137_pen__ut_redo_a, 0, no_hashes },
+ { "mint", 7, _137_pen__ut_mint_a, 0, no_hashes },
+ { "mull", 7, _137_pen__ut_mull_a, 0, no_hashes },
+ { "nest", 7, 0, _137_pen__ut_nest_d, no_hashes },
+ { "rest", 7, _137_pen__ut_rest_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_hood _137_pen__ut_ho[] =
+ { { "ar", 12282 },
+ { "fan", 28, c3n },
+ { "rib", 58, c3n },
+ { "vet", 59, c3n },
+
+ { "blow", 6015 },
+ { "burp", 342 },
+ { "busk", 1373 },
+ { "buss", 374 },
+ { "crop", 1494 },
+ { "duck", 1524 },
+ { "dune", 2991 },
+ { "dunk", 3066 },
+ { "epla", 12206 },
+ { "emin", 1534 },
+ { "emul", 6134 },
+ { "feel", 1502 },
+ { "felt", 94 },
+ { "fine", 49086 },
+ { "fire", 4 },
+ { "fish", 6006 },
+ { "fond", 12283 },
+ { "fund", 6014 },
+ // XX +funk is not part of +ut, and this hook appears to be unused
+ // remove from here and the +ut hint
+ //
+ { "funk", 0xbefafa, c3y, 31 },
+ { "fuse", 24021 },
+ { "gain", 380 },
+ { "lose", 0x2fefe },
+ { "mile", 382 },
+ { "mine", 372 },
+ { "mint", 49083 },
+ { "moot", 0x2feff },
+ { "mull", 24020 },
+ { "nest", 92 },
+ { "peel", 1526 },
+ { "play", 3006 },
+ { "peek", 1532 },
+ { "repo", 22 },
+ { "rest", 6102 },
+ { "tack", 6007 },
+ { "toss", 24540 },
+ { "wrap", 6137 },
+ {},
+ };
+
+
+static u3j_hood _137_pen_ho[] = {
+ { "ap", 22 },
+ { "ut", 86 },
+ {},
+};
+
+
+/* layer four
+ */
+static u3j_harm _137_qua_trip_a[] = {{".2", u3we_trip}, {}};
+
+static u3j_harm _137_qua_slaw_a[] = {{".2", u3we_slaw}, {}};
+static u3j_harm _137_qua_scot_a[] = {{".2", u3we_scot}, {}};
+static u3j_harm _137_qua_scow_a[] = {{".2", u3we_scow}, {}};
+
+static u3j_harm _137_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}};
+static u3j_harm _137_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}};
+static u3j_harm _137_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}};
+static u3j_harm _137_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}};
+static u3j_core _137_qua__po_d[] =
+ { { "ind", 7, _137_qua__po_ind_a, 0, no_hashes },
+ { "ins", 7, _137_qua__po_ins_a, 0, no_hashes },
+ { "tod", 7, _137_qua__po_tod_a, 0, no_hashes },
+ { "tos", 7, _137_qua__po_tos_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}};
+static u3j_core _137_qua__bend_d[] =
+ { { "fun", 7, _137_qua__bend_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}};
+static u3j_core _137_qua__cold_d[] =
+ { { "fun", 7, _137_qua__cold_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}};
+static u3j_core _137_qua__cook_d[] =
+ { { "fun", 7, _137_qua__cook_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}};
+static u3j_core _137_qua__comp_d[] =
+ { { "fun", 7, _137_qua__comp_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}};
+static u3j_core _137_qua__easy_d[] =
+ { { "fun", 7, _137_qua__easy_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}};
+static u3j_core _137_qua__glue_d[] =
+ { { "fun", 7, _137_qua__glue_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}};
+static u3j_core _137_qua__here_d[] =
+ { { "fun", 7, _137_qua__here_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}};
+static u3j_core _137_qua__just_d[] =
+ { { "fun", 7, _137_qua__just_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}};
+static u3j_core _137_qua__mask_d[] =
+ { { "fun", 7, _137_qua__mask_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}};
+static u3j_core _137_qua__shim_d[] =
+ { { "fun", 7, _137_qua__shim_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}};
+static u3j_core _137_qua__stag_d[] =
+ { { "fun", 7, _137_qua__stag_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}};
+static u3j_core _137_qua__stew_d[] =
+ { { "fun", 31, _137_qua__stew_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}};
+static u3j_core _137_qua__stir_d[] =
+ { { "fun", 7, _137_qua__stir_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_qua_pfix_a[] = {{".2", u3we_pfix}, {}};
+
+static u3j_harm _137_qua_plug_a[] = {{".2", u3we_plug}, {}};
+static u3j_harm _137_qua_pose_a[] = {{".2", u3we_pose}, {}};
+
+static u3j_harm _137_qua_sfix_a[] = {{".2", u3we_sfix}, {}};
+
+static u3j_harm _137_qua_mink_a[] = {{".2", u3we_mink}, {}};
+static u3j_harm _137_qua_mole_a[] = {{".2", u3we_mole}, {}};
+static u3j_harm _137_qua_mule_a[] = {{".2", u3we_mule}, {}};
+
+
+static u3j_hood _137_qua_ho[] = {
+ { "mute", 0x2fbabe },
+ { "show", 24406 },
+ { "mure", 1374 },
+ {},
+};
+
+
+/* layer three
+ */
+static u3j_harm _137_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}};
+static u3j_harm _137_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}};
+static u3j_core _137_tri__cofl_d[] =
+ { { "drg", 7, _137_tri__cofl__drg_a, 0, no_hashes },
+ { "lug", 7, _137_tri__cofl__lug_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__rd_add_a[] = {{".2", u3wer_add}, {}};
+static u3j_harm _137_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}};
+static u3j_harm _137_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}};
+static u3j_harm _137_tri__rd_div_a[] = {{".2", u3wer_div}, {}};
+static u3j_harm _137_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}};
+static u3j_harm _137_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}};
+static u3j_harm _137_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}};
+static u3j_harm _137_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}};
+static u3j_harm _137_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}};
+static u3j_harm _137_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}};
+static u3j_harm _137_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}};
+static u3j_core _137_tri__rd_d[] =
+ { { "add", 7, _137_tri__rd_add_a, 0, no_hashes },
+ { "sub", 7, _137_tri__rd_sub_a, 0, no_hashes },
+ { "mul", 7, _137_tri__rd_mul_a, 0, no_hashes },
+ { "div", 7, _137_tri__rd_div_a, 0, no_hashes },
+ { "sqt", 7, _137_tri__rd_sqt_a, 0, no_hashes },
+ { "fma", 7, _137_tri__rd_fma_a, 0, no_hashes },
+ { "lth", 7, _137_tri__rd_lth_a, 0, no_hashes },
+ { "lte", 7, _137_tri__rd_lte_a, 0, no_hashes },
+ { "equ", 7, _137_tri__rd_equ_a, 0, no_hashes },
+ { "gte", 7, _137_tri__rd_gte_a, 0, no_hashes },
+ { "gth", 7, _137_tri__rd_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__rs_add_a[] = {{".2", u3wet_add}, {}};
+static u3j_harm _137_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}};
+static u3j_harm _137_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}};
+static u3j_harm _137_tri__rs_div_a[] = {{".2", u3wet_div}, {}};
+static u3j_harm _137_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}};
+static u3j_harm _137_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}};
+static u3j_harm _137_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}};
+static u3j_harm _137_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}};
+static u3j_harm _137_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}};
+static u3j_harm _137_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}};
+static u3j_harm _137_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}};
+static u3j_core _137_tri__rs_d[] =
+ { { "add", 7, _137_tri__rs_add_a, 0, no_hashes },
+ { "sub", 7, _137_tri__rs_sub_a, 0, no_hashes },
+ { "mul", 7, _137_tri__rs_mul_a, 0, no_hashes },
+ { "div", 7, _137_tri__rs_div_a, 0, no_hashes },
+ { "sqt", 7, _137_tri__rs_sqt_a, 0, no_hashes },
+ { "fma", 7, _137_tri__rs_fma_a, 0, no_hashes },
+ { "lth", 7, _137_tri__rs_lth_a, 0, no_hashes },
+ { "lte", 7, _137_tri__rs_lte_a, 0, no_hashes },
+ { "equ", 7, _137_tri__rs_equ_a, 0, no_hashes },
+ { "gte", 7, _137_tri__rs_gte_a, 0, no_hashes },
+ { "gth", 7, _137_tri__rs_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__rq_add_a[] = {{".2", u3weq_add}, {}};
+static u3j_harm _137_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}};
+static u3j_harm _137_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}};
+static u3j_harm _137_tri__rq_div_a[] = {{".2", u3weq_div}, {}};
+static u3j_harm _137_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}};
+static u3j_harm _137_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}};
+static u3j_harm _137_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}};
+static u3j_harm _137_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}};
+static u3j_harm _137_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}};
+static u3j_harm _137_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}};
+static u3j_harm _137_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}};
+static u3j_core _137_tri__rq_d[] =
+ { { "add", 7, _137_tri__rq_add_a, 0, no_hashes },
+ { "sub", 7, _137_tri__rq_sub_a, 0, no_hashes },
+ { "mul", 7, _137_tri__rq_mul_a, 0, no_hashes },
+ { "div", 7, _137_tri__rq_div_a, 0, no_hashes },
+ { "sqt", 7, _137_tri__rq_sqt_a, 0, no_hashes },
+ { "fma", 7, _137_tri__rq_fma_a, 0, no_hashes },
+ { "lth", 7, _137_tri__rq_lth_a, 0, no_hashes },
+ { "lte", 7, _137_tri__rq_lte_a, 0, no_hashes },
+ { "equ", 7, _137_tri__rq_equ_a, 0, no_hashes },
+ { "gte", 7, _137_tri__rq_gte_a, 0, no_hashes },
+ { "gth", 7, _137_tri__rq_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__rh_add_a[] = {{".2", u3wes_add}, {}};
+static u3j_harm _137_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}};
+static u3j_harm _137_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}};
+static u3j_harm _137_tri__rh_div_a[] = {{".2", u3wes_div}, {}};
+static u3j_harm _137_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}};
+static u3j_harm _137_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}};
+static u3j_harm _137_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}};
+static u3j_harm _137_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}};
+static u3j_harm _137_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}};
+static u3j_harm _137_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}};
+static u3j_harm _137_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}};
+static u3j_core _137_tri__rh_d[] =
+ { { "add", 7, _137_tri__rh_add_a, 0, no_hashes },
+ { "sub", 7, _137_tri__rh_sub_a, 0, no_hashes },
+ { "mul", 7, _137_tri__rh_mul_a, 0, no_hashes },
+ { "div", 7, _137_tri__rh_div_a, 0, no_hashes },
+ { "sqt", 7, _137_tri__rh_sqt_a, 0, no_hashes },
+ { "fma", 7, _137_tri__rh_fma_a, 0, no_hashes },
+ { "lth", 7, _137_tri__rh_lth_a, 0, no_hashes },
+ { "lte", 7, _137_tri__rh_lte_a, 0, no_hashes },
+ { "equ", 7, _137_tri__rh_equ_a, 0, no_hashes },
+ { "gte", 7, _137_tri__rh_gte_a, 0, no_hashes },
+ { "gth", 7, _137_tri__rh_gth_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__og_raw_a[] = {{".2", u3weo_raw}, {}};
+static u3j_core _137_tri__og_d[] =
+ { { "raw", 7, _137_tri__og_raw_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}};
+static u3j_core _137_tri__sha_d[] =
+ { { "sha1", 7, _137_tri__sha_sha1_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_tri_shax_a[] = {{".2", u3we_shax}, {}};
+static u3j_harm _137_tri_shay_a[] = {{".2", u3we_shay}, {}};
+static u3j_harm _137_tri_shas_a[] = {{".2", u3we_shas}, {}};
+static u3j_harm _137_tri_shal_a[] = {{".2", u3we_shal}, {}};
+
+static u3j_harm _137_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}};
+static u3j_harm _137_ob_fein_a[] = {{".2", u3we_fein_ob}, {}};
+static u3j_core _137_ob_d[] = {
+ { "fein", 7, _137_ob_fein_a, 0, no_hashes },
+ { "fynd", 7, _137_ob_fynd_a, 0, no_hashes },
+ {}
+};
+static u3j_hood _137_ob_ho[] = {
+ { "fein", 42 },
+ { "fynd", 20 },
+ {},
+};
+
+
+static u3j_hood _137_tri_ho[] = {
+ { "ob", 20 },
+ { "yore", 5462 },
+ { "year", 44975 },
+ {},
+};
+
+
+/* layer two
+ */
+static u3j_harm _137_two_find_a[] = {{".2", u3wb_find, c3y}, {}};
+static u3j_harm _137_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}};
+static u3j_harm _137_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}};
+static u3j_harm _137_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}};
+static u3j_harm _137_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}};
+static u3j_harm _137_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}};
+static u3j_harm _137_two_need_a[] = {{".2", u3wb_need, c3y}, {}};
+static u3j_harm _137_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}};
+static u3j_harm _137_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}};
+static u3j_harm _137_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}};
+static u3j_harm _137_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}};
+static u3j_harm _137_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}};
+static u3j_harm _137_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}};
+static u3j_harm _137_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}};
+static u3j_harm _137_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}};
+static u3j_harm _137_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}};
+static u3j_harm _137_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}};
+static u3j_harm _137_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}};
+static u3j_harm _137_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}};
+static u3j_harm _137_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}};
+static u3j_harm _137_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}};
+
+static u3j_harm _137_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}};
+static u3j_harm _137_two_can_a[] = {{".2", u3wc_can, c3y}, {}};
+static u3j_harm _137_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}};
+static u3j_harm _137_two_con_a[] = {{".2", u3wc_con, c3y}, {}};
+static u3j_harm _137_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}};
+static u3j_harm _137_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}};
+static u3j_harm _137_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}};
+static u3j_harm _137_two_end_a[] = {{".2", u3wc_end, c3y}, {}};
+static u3j_harm _137_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}};
+static u3j_harm _137_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}};
+static u3j_harm _137_two_met_a[] = {{".2", u3wc_met, c3y}, {}};
+static u3j_harm _137_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}};
+static u3j_harm _137_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}};
+static u3j_harm _137_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}};
+static u3j_harm _137_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}};
+static u3j_harm _137_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}};
+static u3j_harm _137_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}};
+static u3j_harm _137_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}};
+static u3j_harm _137_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}};
+static u3j_harm _137_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}};
+static u3j_harm _137_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}};
+static u3j_harm _137_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}};
+static u3j_harm _137_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}};
+static u3j_harm _137_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}};
+
+static u3j_harm _137_two__in_bif_a[] = {{".2", u3wdi_bif}, {}};
+static u3j_harm _137_two__in_del_a[] = {{".2", u3wdi_del}, {}};
+static u3j_harm _137_two__in_dif_a[] = {{".2", u3wdi_dif}, {}};
+static u3j_harm _137_two__in_gas_a[] = {{".2", u3wdi_gas}, {}};
+static u3j_harm _137_two__in_has_a[] = {{".2", u3wdi_has}, {}};
+static u3j_harm _137_two__in_int_a[] = {{".2", u3wdi_int}, {}};
+static u3j_harm _137_two__in_put_a[] = {{".2", u3wdi_put}, {}};
+static u3j_harm _137_two__in_rep_a[] = {{".2", u3wdi_rep}, {}};
+static u3j_harm _137_two__in_run_a[] = {{".2", u3wdi_run}, {}};
+static u3j_harm _137_two__in_tap_a[] = {{".2", u3wdi_tap}, {}};
+static u3j_harm _137_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}};
+static u3j_harm _137_two__in_uni_a[] = {{".2", u3wdi_uni}, {}};
+
+static u3j_harm _137_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}};
+static u3j_harm _137_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}};
+static u3j_harm _137_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}};
+
+static u3j_harm _137_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}};
+static u3j_harm _137_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}};
+static u3j_harm _137_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}};
+static u3j_harm _137_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}};
+static u3j_harm _137_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}};
+static u3j_harm _137_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}};
+static u3j_harm _137_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}};
+static u3j_harm _137_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}};
+static u3j_harm _137_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}};
+static u3j_harm _137_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}};
+static u3j_harm _137_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}};
+static u3j_harm _137_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}};
+static u3j_harm _137_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}};
+static u3j_harm _137_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}};
+static u3j_harm _137_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}};
+
+static u3j_harm _137_two_cue_a[] = {{".2", u3we_cue}, {}};
+static u3j_harm _137_two_jam_a[] = {{".2", u3we_jam}, {}};
+static u3j_harm _137_two_mat_a[] = {{".2", u3we_mat}, {}};
+static u3j_harm _137_two_rub_a[] = {{".2", u3we_rub}, {}};
+
+
+
+/* layer one
+ */
+static u3j_harm _137_one_add_a[] = {{".2", u3wa_add, c3y}, {}};
+static u3j_harm _137_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}};
+static u3j_harm _137_one_div_a[] = {{".2", u3wa_div, c3y}, {}};
+static u3j_harm _137_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}};
+static u3j_harm _137_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}};
+static u3j_harm _137_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}};
+static u3j_harm _137_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}};
+static u3j_harm _137_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}};
+static u3j_harm _137_one_max_a[] = {{".2", u3wa_max, c3y}, {}};
+static u3j_harm _137_one_min_a[] = {{".2", u3wa_min, c3y}, {}};
+static u3j_harm _137_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}};
+static u3j_harm _137_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}};
+static u3j_harm _137_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}};
+
+static u3j_harm _137_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}};
+static u3j_harm _137_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}};
+static u3j_harm _137_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}};
+
+static u3j_harm _137_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}};
+static u3j_harm _137_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}};
+
+static u3j_core _137_lull_plot_d[] =
+ { { "fax", 7, _137_lull_plot_fax_a, 0, no_hashes },
+ { "met", 7, _137_lull_plot_met_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _137_lull_d[] =
+ { { "plot", 31, 0, _137_lull_plot_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}};
+static u3j_harm _137_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}};
+static u3j_harm _137_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}};
+
+static u3j_core _137_hex_blake3_d[] =
+ { { "hash", 7, _137_hex_blake3_hash_a, 0, no_hashes },
+ { "chunk-output", 7, _137_hex_blake3_chunk_output_a, 0, no_hashes },
+ {}
+ };
+
+
+static u3j_core _137_hex_blake3_impl_d[] =
+ { { "compress", 7, _137_hex_blake3_compress_a, 0, no_hashes },
+ { "blake3", 7, 0, _137_hex_blake3_d, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}};
+
+static u3j_core _137_hex_blake_d[] =
+ { { "blake2b", 7, _137_hex_blake2b_a, 0, no_hashes },
+ { "blake3-impl", 7, 0, _137_hex_blake3_impl_d, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _137_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}};
+static u3j_harm _137_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}};
+static u3j_core _137_hex_chacha_d[] =
+ { { "crypt", 7, _137_hex_chacha_crypt_a, 0, no_hashes },
+ { "xchacha", 7, _137_hex_chacha_xchacha_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_hex_json_de_a[] = {{".2", u3we_json_de}, {}};
+static u3j_harm _137_hex_json_en_a[] = {{".2", u3we_json_en}, {}};
+static u3j_core _137_hex_json_d[] =
+ { { "de", 15, _137_hex_json_de_a, 0, no_hashes },
+ { "en", 15, _137_hex_json_en_a, 0, no_hashes },
+ {}
+ };
+
+/* /lib jets in non core
+*/
+static u3j_harm _137_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}};
+static u3j_harm _137_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}};
+static u3j_harm _137_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}};
+static u3j_harm _137_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}};
+static u3j_harm _137_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}};
+static u3j_harm _137_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}};
+static u3j_harm _137_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}};
+static u3j_harm _137_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}};
+static u3j_harm _137_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}};
+static u3j_harm _137_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}};
+static u3j_harm _137_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}};
+static u3j_harm _137_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}};
+static u3j_harm _137_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}};
+static u3j_harm _137_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}};
+static u3j_harm _137_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}};
+static u3j_harm _137_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}};
+static u3j_harm _137_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}};
+static u3j_harm _137_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}};
+static u3j_harm _137_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}};
+static u3j_harm _137_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}};
+static u3j_harm _137_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}};
+static u3j_harm _137_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}};
+static u3j_harm _137_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}};
+static u3j_harm _137_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}};
+static u3j_harm _137_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}};
+static u3j_harm _137_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}};
+static u3j_harm _137_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}};
+static u3j_harm _137_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}};
+
+static u3j_core _137_non__la_core_d[] =
+ { { "add-rays", 7, _137_non__lagoon_add_a, 0, no_hashes },
+ { "sub-rays", 7, _137_non__lagoon_sub_a, 0, no_hashes },
+ { "mul-rays", 7, _137_non__lagoon_mul_a, 0, no_hashes },
+ { "div-rays", 7, _137_non__lagoon_div_a, 0, no_hashes },
+ { "mod-rays", 7, _137_non__lagoon_mod_a, 0, no_hashes },
+ { "add-scal", 7, _137_non__lagoon_adds_a, 0, no_hashes },
+ { "sub-scal", 7, _137_non__lagoon_subs_a, 0, no_hashes },
+ { "mul-scal", 7, _137_non__lagoon_muls_a, 0, no_hashes },
+ { "div-scal", 7, _137_non__lagoon_divs_a, 0, no_hashes },
+ { "mod-scal", 7, _137_non__lagoon_mods_a, 0, no_hashes },
+ { "dot", 7, _137_non__lagoon_dot_a, 0, no_hashes },
+ { "transpose",7, _137_non__lagoon_trans_a, 0, no_hashes },
+ { "cumsum", 7, _137_non__lagoon_cumsum_a, 0, no_hashes },
+ { "argmin", 7, _137_non__lagoon_argmin_a, 0, no_hashes },
+ { "argmax", 7, _137_non__lagoon_argmax_a, 0, no_hashes },
+ { "ravel", 7, _137_non__lagoon_ravel_a, 0, no_hashes },
+ { "min", 7, _137_non__lagoon_min_a, 0, no_hashes },
+ { "max", 7, _137_non__lagoon_max_a, 0, no_hashes },
+ { "linspace", 7, _137_non__lagoon_linspace_a, 0, no_hashes },
+ { "range", 7, _137_non__lagoon_range_a, 0, no_hashes },
+ { "abs", 7, _137_non__lagoon_abs_a, 0, no_hashes },
+ { "gth", 7, _137_non__lagoon_gth_a, 0, no_hashes },
+ { "gte", 7, _137_non__lagoon_gte_a, 0, no_hashes },
+ { "lth", 7, _137_non__lagoon_lth_a, 0, no_hashes },
+ { "lte", 7, _137_non__lagoon_lte_a, 0, no_hashes },
+ { "diag", 7, _137_non__lagoon_diag_a, 0, no_hashes },
+ { "trace", 7, _137_non__lagoon_trace_a,0, no_hashes },
+ { "mmul", 7, _137_non__lagoon_mmul_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _137_non_d[] =
+ { { "lagoon", 7, 0, _137_non__la_core_d, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _137_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}};
+
+static u3j_harm _137_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}};
+
+static u3j_core _137_hex_lia_run_once_d[] = {
+ { "run-once-inner-v0", 15, _137_hex_lia_run_once_inner_a, 0, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_lia_monad_d[] = {
+ { "run-v1", 7, _137_hex_lia_run_v1_a, 0, no_hashes },
+ { "run-once-v0", 7, 0, _137_hex_lia_run_once_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_engine_d[] = {
+ { "monad-v0", 3, 0, _137_hex_lia_monad_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_op_def_d[] = {
+ { "wasm-engine-v0", 3, 0, _137_hex_wasm_engine_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_validator_d[] = {
+ { "wasm-op-def-v0", 3, 0, _137_hex_wasm_op_def_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_parser_d[] = {
+ { "validator-v0", 3, 0, _137_hex_wasm_validator_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_lia_sur_d[] = {
+ { "wasm-parser-v0", 3, 0, _137_hex_wasm_parser_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_engine_sur_d[] = {
+ { "monad-sur-v1", 3, 0, _137_hex_lia_sur_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_wasm_sur_d[] = {
+ { "engine-sur-v0", 3, 0, _137_hex_wasm_engine_sur_d, no_hashes },
+ {}
+};
+
+static u3j_core _137_hex_d[] =
+ { { "non", 7, 0, _137_non_d, no_hashes },
+
+ { "lull", 3, 0, _137_lull_d, no_hashes },
+
+ { "lore", 63, _137_hex_lore_a, 0, no_hashes },
+
+ { "leer", 63, _137_hex_leer_a, 0, no_hashes },
+ { "loss", 63, _137_hex_loss_a, 0, no_hashes },
+ { "lune", 127, _137_hex_lune_a, 0, no_hashes },
+
+ { "crc", 31, 0, _137_hex__crc_d, no_hashes },
+
+ { "coed", 63, 0, _137_hex_coed_d, no_hashes },
+ { "aes", 31, 0, _137_hex_aes_d, no_hashes },
+
+ { "hmac", 63, 0, _137_hex_hmac_d, no_hashes },
+ { "argon", 31, 0, _137_hex_argon_d, no_hashes },
+ { "blake", 31, 0, _137_hex_blake_d, no_hashes },
+ { "chacha", 31, 0, _137_hex_chacha_d, no_hashes },
+ { "kecc", 31, 0, _137_hex_kecc_d, no_hashes },
+ { "ripemd", 31, 0, _137_hex_ripe_d, no_hashes },
+ { "scr", 31, 0, _137_hex_scr_d, no_hashes },
+ { "secp", 6, 0, _137_hex_secp_d, no_hashes },
+ { "mimes", 31, 0, _137_hex_mimes_d, no_hashes },
+ { "json", 31, 0, _137_hex_json_d, no_hashes },
+ { "wasm-sur-v0", 3, 0, _137_hex_wasm_sur_d, no_hashes },
+ {}
+ };
+
+static u3j_core _137_pen_d[] =
+ { { "hex", 7, 0, _137_hex_d, no_hashes },
+
+ { "cell", 7, _137_pen_cell_a, 0, no_hashes },
+ { "comb", 7, _137_pen_comb_a, 0, no_hashes },
+ { "cons", 7, _137_pen_cons_a, 0, no_hashes },
+ { "core", 7, _137_pen_core_a, 0, no_hashes },
+ { "face", 7, _137_pen_face_a, 0, no_hashes },
+ { "fitz", 7, _137_pen_fitz_a, 0, no_hashes },
+ { "fork", 7, _137_pen_fork_a, 0, no_hashes },
+ { "look", 7, _137_pen_look_a, 0, no_hashes },
+ { "loot", 7, _137_pen_loot_a, 0, no_hashes },
+ { "ut", 15, 0, _137_pen__ut_d, no_hashes, _137_pen__ut_ho },
+ {}
+ };
+
+static u3j_core _137_qua_d[] =
+ { { "pen", 3, 0, _137_pen_d, no_hashes, _137_pen_ho },
+
+ { "po", 7, 0, _137_qua__po_d, no_hashes },
+
+ { "trip", 7, _137_qua_trip_a, 0, no_hashes },
+
+ { "bend", 7, 0, _137_qua__bend_d, no_hashes },
+ { "cold", 7, 0, _137_qua__cold_d, no_hashes },
+ { "comp", 7, 0, _137_qua__comp_d, no_hashes },
+ { "cook", 7, 0, _137_qua__cook_d, no_hashes },
+ { "easy", 7, 0, _137_qua__easy_d, no_hashes },
+ { "glue", 7, 0, _137_qua__glue_d, no_hashes },
+ { "here", 7, 0, _137_qua__here_d, no_hashes },
+ { "just", 7, 0, _137_qua__just_d, no_hashes },
+ { "mask", 7, 0, _137_qua__mask_d, no_hashes },
+ { "shim", 7, 0, _137_qua__shim_d, no_hashes },
+ { "stag", 7, 0, _137_qua__stag_d, no_hashes },
+ { "stew", 7, 0, _137_qua__stew_d, no_hashes },
+ { "stir", 7, 0, _137_qua__stir_d, no_hashes },
+
+ { "pfix", 7, _137_qua_pfix_a, 0, no_hashes },
+ { "plug", 7, _137_qua_plug_a, 0, no_hashes },
+ { "pose", 7, _137_qua_pose_a, 0, no_hashes },
+ { "sfix", 7, _137_qua_sfix_a, 0, no_hashes },
+
+ { "mink", 7, _137_qua_mink_a, 0, no_hashes },
+ { "mole", 7, _137_qua_mole_a, 0, no_hashes },
+ { "mule", 7, _137_qua_mule_a, 0, no_hashes },
+
+ { "scot", 7, _137_qua_scot_a, 0, no_hashes },
+ { "scow", 7, _137_qua_scow_a, 0, no_hashes },
+ { "slaw", 7, _137_qua_slaw_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _137_tri_d[] =
+ { { "qua", 3, 0, _137_qua_d, no_hashes, _137_qua_ho },
+
+ { "cofl", 7, 0, _137_tri__cofl_d, no_hashes },
+ { "rd", 7, 0, _137_tri__rd_d, no_hashes },
+ { "rs", 7, 0, _137_tri__rs_d, no_hashes },
+ { "rq", 7, 0, _137_tri__rq_d, no_hashes },
+ { "rh", 7, 0, _137_tri__rh_d, no_hashes },
+ { "og", 7, 0, _137_tri__og_d, no_hashes },
+
+ { "sha", 7, 0, _137_tri__sha_d, no_hashes },
+ { "shax", 7, _137_tri_shax_a, 0, no_hashes },
+ { "shay", 7, _137_tri_shay_a, 0, no_hashes },
+ { "shas", 7, _137_tri_shas_a, 0, no_hashes },
+ { "shal", 7, _137_tri_shal_a, 0, no_hashes },
+
+ { "ob", 3, 0, _137_ob_d, no_hashes, _137_ob_ho },
+ {}
+ };
+
+static u3j_harm _137_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}};
+static u3j_harm _137_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}};
+static u3j_harm _137_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}};
+
+static u3j_harm _137_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}};
+static u3j_core _137_two__hew_d[] =
+ { { "fun", 15, _137_two__hew_fun_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}};
+
+static u3j_core _137_two__by_d[] =
+ { { "all", 7, _137_two__by_all_a, 0, no_hashes },
+ { "any", 7, _137_two__by_any_a, 0, no_hashes },
+ { "apt", 7, _137_two__by_apt_a, 0, no_hashes },
+ { "bif", 7, _137_two__by_bif_a, 0, no_hashes },
+ { "del", 7, _137_two__by_del_a, 0, no_hashes },
+ { "dif", 7, _137_two__by_dif_a, 0, no_hashes },
+ { "gas", 7, _137_two__by_gas_a, 0, no_hashes },
+ { "get", 7, _137_two__by_get_a, 0, no_hashes },
+ { "has", 7, _137_two__by_has_a, 0, no_hashes },
+ { "int", 7, _137_two__by_int_a, 0, no_hashes },
+ { "jab", 7, _137_two__by_jab_a, 0, no_hashes },
+ { "key", 7, _137_two__by_key_a, 0, no_hashes },
+ { "put", 7, _137_two__by_put_a, 0, no_hashes },
+ { "rep", 7, _137_two__by_rep_a, 0, no_hashes },
+ { "run", 7, _137_two__by_run_a, 0, no_hashes },
+ { "tap", 7, _137_two__by_tap_a, 0, no_hashes },
+ { "uni", 7, _137_two__by_uni_a, 0, no_hashes },
+ { "urn", 7, _137_two__by_urn_a, 0, no_hashes },
+ { "wyt", 3, _137_two__by_wyt_a, 0, no_hashes },
+ {}
+ };
+
+
+static u3j_harm _137_two__in_apt_a[] = {{".2", u3wdi_apt}, {}};
+
+static u3j_core _137_two__in_d[] =
+ { { "apt", 7, _137_two__in_apt_a, 0, no_hashes },
+ { "bif", 7, _137_two__in_bif_a, 0, no_hashes },
+ { "del", 7, _137_two__in_del_a, 0, no_hashes },
+ { "dif", 7, _137_two__in_dif_a, 0, no_hashes },
+ { "gas", 7, _137_two__in_gas_a, 0, no_hashes },
+ { "has", 7, _137_two__in_has_a, 0, no_hashes },
+ { "int", 7, _137_two__in_int_a, 0, no_hashes },
+ { "put", 7, _137_two__in_put_a, 0, no_hashes },
+ { "rep", 7, _137_two__in_rep_a, 0, no_hashes },
+ { "run", 7, _137_two__in_run_a, 0, no_hashes },
+ { "tap", 7, _137_two__in_tap_a, 0, no_hashes },
+ { "uni", 7, _137_two__in_uni_a, 0, no_hashes },
+ { "wyt", 3, _137_two__in_wyt_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_harm _137_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}};
+
+static u3j_harm _137_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}};
+static u3j_harm _137_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}};
+
+static u3j_core _137_two_d[] =
+ { { "tri", 3, 0, _137_tri_d, no_hashes, _137_tri_ho },
+
+ { "find", 7, _137_two_find_a, 0, no_hashes },
+ { "flop", 7, _137_two_flop_a, 0, no_hashes },
+ { "lent", 7, _137_two_lent_a, 0, no_hashes },
+ { "levy", 7, _137_two_levy_a, 0, no_hashes },
+ { "lien", 7, _137_two_lien_a, 0, no_hashes },
+ { "murn", 7, _137_two_murn_a, 0, no_hashes },
+ { "need", 7, _137_two_need_a, 0, no_hashes },
+ { "mate", 7, _137_two_mate_a, 0, no_hashes },
+ { "reap", 7, _137_two_reap_a, 0, no_hashes },
+ { "reel", 7, _137_two_reel_a, 0, no_hashes },
+ { "roll", 7, _137_two_roll_a, 0, no_hashes },
+ { "skid", 7, _137_two_skid_a, 0, no_hashes },
+ { "skim", 7, _137_two_skim_a, 0, no_hashes },
+ { "skip", 7, _137_two_skip_a, 0, no_hashes },
+ { "scag", 7, _137_two_scag_a, 0, no_hashes },
+ { "slag", 7, _137_two_slag_a, 0, no_hashes },
+ { "snag", 7, _137_two_snag_a, 0, no_hashes },
+ { "sort", 7, _137_two_sort_a, 0, no_hashes },
+ { "turn", 7, _137_two_turn_a, 0, no_hashes },
+ { "weld", 7, _137_two_weld_a, 0, no_hashes },
+ { "welp", 7, _137_two_welp_a, 0, no_hashes },
+ { "zing", 7, _137_two_zing_a, 0, no_hashes },
+
+ { "bex", 7, _137_two_bex_a, 0, no_hashes },
+ { "cat", 7, _137_two_cat_a, 0, no_hashes },
+ { "can", 7, _137_two_can_a, 0, no_hashes },
+ { "clz", 7, _137_two_clz_a, 0, no_hashes },
+ { "con", 7, _137_two_con_a, 0, no_hashes },
+ { "ctz", 7, _137_two_ctz_a, 0, no_hashes },
+ { "cue", 7, _137_two_cue_a, 0, no_hashes },
+ { "cut", 7, _137_two_cut_a, 0, no_hashes },
+ { "dis", 7, _137_two_dis_a, 0, no_hashes },
+ { "dor", 7, _137_two_dor_a, 0, no_hashes },
+ { "end", 7, _137_two_end_a, 0, no_hashes },
+ { "gor", 7, _137_two_gor_a, 0, no_hashes },
+ { "ham", 7, _137_two_ham_a, 0, no_hashes },
+ { "hew", 7, 0, _137_two__hew_d, no_hashes },
+ { "jam", 7, _137_two_jam_a, 0, no_hashes },
+ { "lsh", 7, _137_two_lsh_a, 0, no_hashes },
+ { "mat", 7, _137_two_mat_a, 0, no_hashes },
+ { "met", 7, _137_two_met_a, 0, no_hashes },
+ { "mix", 7, _137_two_mix_a, 0, no_hashes },
+ { "mor", 7, _137_two_mor_a, 0, no_hashes },
+ { "mug", 7, _137_two_mug_a, 0, no_hashes },
+ { "muk", 59, _137_two_muk_a, 0, no_hashes },
+ { "rap", 7, _137_two_rap_a, 0, no_hashes },
+ { "rep", 7, _137_two_rep_a, 0, no_hashes },
+ { "rev", 7, _137_two_rev_a, 0, no_hashes },
+ { "rig", 7, _137_two_rig_a, 0, no_hashes },
+ { "rip", 7, _137_two_rip_a, 0, no_hashes },
+ { "rsh", 7, _137_two_rsh_a, 0, no_hashes },
+ { "swp", 7, _137_two_swp_a, 0, no_hashes },
+ { "rub", 7, _137_two_rub_a, 0, no_hashes },
+ { "pow", 7, _137_two_pow_a, 0, no_hashes },
+ { "sew", 7, _137_two_sew_a, 0, no_hashes },
+ { "sqt", 7, _137_two_sqt_a, 0, no_hashes },
+ { "xeb", 7, _137_two_xeb_a, 0, no_hashes },
+
+ { "by", 7, 0, _137_two__by_d, no_hashes },
+ { "in", 7, 0, _137_two__in_d, no_hashes },
+ {}
+ };
+
+static u3j_core _137_one_d[] =
+ { { "two", 3, 0, _137_two_d, no_hashes },
+
+ { "add", 7, _137_one_add_a, 0, no_hashes },
+ { "dec", 7, _137_one_dec_a, 0, no_hashes },
+ { "div", 7, _137_one_div_a, 0, no_hashes },
+ { "dvr", 7, _137_one_dvr_a, 0, no_hashes },
+ { "gte", 7, _137_one_gte_a, 0, no_hashes },
+ { "gth", 7, _137_one_gth_a, 0, no_hashes },
+ { "lte", 7, _137_one_lte_a, 0, no_hashes },
+ { "lth", 7, _137_one_lth_a, 0, no_hashes },
+ { "max", 7, _137_one_max_a, 0, no_hashes },
+ { "min", 7, _137_one_min_a, 0, no_hashes },
+ { "mod", 7, _137_one_mod_a, 0, no_hashes },
+ { "mul", 7, _137_one_mul_a, 0, no_hashes },
+ { "sub", 7, _137_one_sub_a, 0, no_hashes },
+
+ { "cap", 7, _137_one_cap_a, 0, no_hashes },
+ { "mas", 7, _137_one_mas_a, 0, no_hashes },
+ { "peg", 7, _137_one_peg_a, 0, no_hashes },
+ {}
+ };
+
+u3j_core _k137_d[] =
+ { { "one", 3, 0, _137_one_d, no_hashes },
+ {}
+ };
+
diff --git a/vere/pkg/noun/jets/a/add.c b/vere/pkg/noun/jets/a/add.c
new file mode 100644
index 0000000..308d143
--- /dev/null
+++ b/vere/pkg/noun/jets/a/add.c
@@ -0,0 +1,61 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_add(u3_atom a,
+ u3_atom b)
+{
+ if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ c3_w c = a + b;
+
+ return u3i_word(c);
+ }
+ else if ( 0 == a ) {
+ return u3k(b);
+ }
+ else if ( 0 == b ) {
+ return u3k(a);
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ mpz_add(a_mp, a_mp, b_mp);
+ mpz_clear(b_mp);
+
+ return u3i_mp(a_mp);
+ }
+}
+
+u3_noun
+u3wa_add(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_add(a, b);
+ }
+}
+
+u3_noun
+u3ka_add(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qa_add(a, b);
+
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/dec.c b/vere/pkg/noun/jets/a/dec.c
new file mode 100644
index 0000000..02a8ba1
--- /dev/null
+++ b/vere/pkg/noun/jets/a/dec.c
@@ -0,0 +1,57 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_inc(u3_atom a)
+{
+ return u3i_vint(u3k(a));
+}
+
+u3_noun
+u3qa_dec(u3_atom a)
+{
+ if ( 0 == a ) {
+ return u3m_error("decrement-underflow");
+ }
+ else {
+ if ( _(u3a_is_cat(a)) ) {
+ return a - 1;
+ }
+ else {
+ mpz_t a_mp;
+
+ u3r_mp(a_mp, a);
+ mpz_sub_ui(a_mp, a_mp, 1);
+
+ return u3i_mp(a_mp);
+ }
+ }
+}
+
+u3_noun
+u3wa_dec(u3_noun cor)
+{
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_dec(a);
+ }
+}
+
+u3_noun
+u3ka_dec(u3_atom a)
+{
+ u3_noun b = u3qa_dec(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/a/div.c b/vere/pkg/noun/jets/a/div.c
new file mode 100644
index 0000000..74b33dd
--- /dev/null
+++ b/vere/pkg/noun/jets/a/div.c
@@ -0,0 +1,57 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_div(u3_atom a,
+ u3_atom b)
+{
+ if ( 0 == b ) {
+ return u3m_error("divide-by-zero");
+ }
+ else {
+ if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ return a / b;
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ mpz_tdiv_q(a_mp, a_mp, b_mp);
+ mpz_clear(b_mp);
+
+ return u3i_mp(a_mp);
+ }
+ }
+}
+
+u3_noun
+u3wa_div(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_div(a, b);
+ }
+}
+
+u3_noun
+u3ka_div(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qa_div(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/gte.c b/vere/pkg/noun/jets/a/gte.c
new file mode 100644
index 0000000..371727d
--- /dev/null
+++ b/vere/pkg/noun/jets/a/gte.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_gte(u3_atom a, u3_atom b)
+{
+ if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b))
+ {
+ return __( a >= b );
+ }
+
+ if (a == b) return c3y;
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return __( a_u->len_w > b_u->len_w );
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] > b_w[i_w]) return c3y;
+ if (a_w[i_w] < b_w[i_w]) return c3n;
+ }
+
+ return c3y;
+}
+
+u3_noun
+u3wa_gte(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_gte(a, b);
+ }
+}
diff --git a/vere/pkg/noun/jets/a/gth.c b/vere/pkg/noun/jets/a/gth.c
new file mode 100644
index 0000000..3863b94
--- /dev/null
+++ b/vere/pkg/noun/jets/a/gth.c
@@ -0,0 +1,60 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_gth(u3_atom a, u3_atom b)
+{
+ if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b))
+ {
+ return __( a > b );
+ }
+
+ if (a == b) return c3n;
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return __( a_u->len_w > b_u->len_w );
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] > b_w[i_w]) return c3y;
+ if (a_w[i_w] < b_w[i_w]) return c3n;
+ }
+
+ return c3n;
+}
+
+u3_noun
+u3wa_gth(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_gth(a, b);
+ }
+}
+
+u3_noun
+u3ka_gth(u3_noun a, u3_noun b)
+{
+ u3_noun c = u3qa_gth(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/lte.c b/vere/pkg/noun/jets/a/lte.c
new file mode 100644
index 0000000..0565212
--- /dev/null
+++ b/vere/pkg/noun/jets/a/lte.c
@@ -0,0 +1,60 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_lte(u3_atom a, u3_atom b)
+{
+ if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b))
+ {
+ return __( a <= b );
+ }
+
+ if (a == b) return c3y;
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return __( a_u->len_w < b_u->len_w );
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] < b_w[i_w]) return c3y;
+ if (a_w[i_w] > b_w[i_w]) return c3n;
+ }
+
+ return c3y;
+}
+
+u3_noun
+u3wa_lte(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_lte(a, b);
+ }
+}
+
+u3_noun
+u3ka_lte(u3_noun a, u3_noun b)
+{
+ u3_noun c = u3qa_lte(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/lth.c b/vere/pkg/noun/jets/a/lth.c
new file mode 100644
index 0000000..edf95b3
--- /dev/null
+++ b/vere/pkg/noun/jets/a/lth.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_lth(u3_atom a, u3_atom b)
+{
+ if (c3y == u3a_is_cat(a) || c3y == u3a_is_cat(b))
+ {
+ return __( a < b );
+ }
+
+ if (a == b) return c3n;
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return __( a_u->len_w < b_u->len_w );
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] < b_w[i_w]) return c3y;
+ if (a_w[i_w] > b_w[i_w]) return c3n;
+ }
+
+ return c3n;
+}
+
+u3_noun
+u3wa_lth(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_lth(a, b);
+ }
+}
diff --git a/vere/pkg/noun/jets/a/max.c b/vere/pkg/noun/jets/a/max.c
new file mode 100644
index 0000000..2646ec7
--- /dev/null
+++ b/vere/pkg/noun/jets/a/max.c
@@ -0,0 +1,60 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_max(u3_atom a, u3_atom b)
+{
+ if ( _(u3a_is_cat(a)) || _(u3a_is_cat(b)) )
+ {
+ return u3k(c3_max(a, b));
+ }
+
+ if (a == b) return u3k(a);
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return (a_u->len_w > b_u->len_w) ? u3k(a) : u3k(b);
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] > b_w[i_w]) return u3k(a);
+ if (a_w[i_w] < b_w[i_w]) return u3k(b);
+ }
+
+ return u3k(a);
+}
+
+u3_noun
+u3wa_max(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_max(a, b);
+ }
+}
+
+u3_noun
+u3ka_max(u3_noun a, u3_noun b)
+{
+ u3_noun c = u3qa_max(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/min.c b/vere/pkg/noun/jets/a/min.c
new file mode 100644
index 0000000..00a75e6
--- /dev/null
+++ b/vere/pkg/noun/jets/a/min.c
@@ -0,0 +1,62 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_min(u3_atom a, u3_atom b)
+{
+ if ( _(u3a_is_cat(a)) || _(u3a_is_cat(b)) )
+ {
+ // this will always return a direct atom, no refcount gain necessary
+ //
+ return c3_min(a, b);
+ }
+
+ if (a == b) return u3k(a);
+
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if (a_u->len_w != b_u->len_w)
+ {
+ return (a_u->len_w < b_u->len_w) ? u3k(a) : u3k(b);
+ }
+
+ c3_w* a_w = a_u->buf_w;
+ c3_w* b_w = b_u->buf_w;
+ for (c3_w i_w = a_u->len_w; i_w--;)
+ {
+ if (a_w[i_w] < b_w[i_w]) return u3k(a);
+ if (a_w[i_w] > b_w[i_w]) return u3k(b);
+ }
+
+ return u3k(a);
+}
+
+u3_noun
+u3wa_min(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0))
+ || (c3n == u3ud(b))
+ || (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_min(a, b);
+ }
+}
+
+u3_noun
+u3ka_min(u3_noun a, u3_noun b)
+{
+ u3_noun c = u3qa_min(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/mod.c b/vere/pkg/noun/jets/a/mod.c
new file mode 100644
index 0000000..1eb9aab
--- /dev/null
+++ b/vere/pkg/noun/jets/a/mod.c
@@ -0,0 +1,55 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_mod(u3_atom a,
+ u3_atom b)
+{
+ if ( 0 == b ) {
+ return u3m_error("divide-by-zero");
+ }
+ else if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ return a % b;
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ mpz_tdiv_r(a_mp, a_mp, b_mp);
+ mpz_clear(b_mp);
+
+ return u3i_mp(a_mp);
+ }
+}
+
+u3_noun
+u3wa_mod(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_mod(a, b);
+ }
+}
+
+u3_noun
+u3ka_mod(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qa_mod(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/mul.c b/vere/pkg/noun/jets/a/mul.c
new file mode 100644
index 0000000..aaba68c
--- /dev/null
+++ b/vere/pkg/noun/jets/a/mul.c
@@ -0,0 +1,58 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_mul(u3_atom a,
+ u3_atom b)
+{
+ if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ c3_d c = ((c3_d) a) * ((c3_d) b);
+
+ return u3i_chubs(1, &c);
+ }
+ else if ( 0 == a ) {
+ return 0;
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ mpz_mul(a_mp, a_mp, b_mp);
+ mpz_clear(b_mp);
+
+ return u3i_mp(a_mp);
+ }
+}
+
+u3_noun
+u3wa_mul(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_mul(a, b);
+ }
+}
+
+u3_noun
+u3ka_mul(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qa_mul(a, b);
+
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/a/sub.c b/vere/pkg/noun/jets/a/sub.c
new file mode 100644
index 0000000..321ba77
--- /dev/null
+++ b/vere/pkg/noun/jets/a/sub.c
@@ -0,0 +1,67 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qa_sub(u3_atom a,
+ u3_atom b)
+{
+ if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ if ( a < b ) {
+ return u3m_error("subtract-underflow");
+ }
+ else {
+ return (a - b);
+ }
+ }
+ else if ( 0 == b ) {
+ return u3k(a);
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ if ( mpz_cmp(a_mp, b_mp) < 0 ) {
+ mpz_clear(a_mp);
+ mpz_clear(b_mp);
+
+ return u3m_error("subtract-underflow");
+ }
+ mpz_sub(a_mp, a_mp, b_mp);
+ mpz_clear(b_mp);
+
+ return u3i_mp(a_mp);
+ }
+}
+
+u3_noun
+u3wa_sub(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return u3qa_sub(a, b);
+ }
+}
+
+u3_noun
+u3ka_sub(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qa_sub(a, b);
+
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/b/bind.c b/vere/pkg/noun/jets/b/bind.c
new file mode 100644
index 0000000..7f37a69
--- /dev/null
+++ b/vere/pkg/noun/jets/b/bind.c
@@ -0,0 +1,30 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_bind(u3_noun a,
+ u3_noun b)
+ {
+ if ( 0 == a ) {
+ return 0;
+ } else {
+ return u3nc(0, u3n_slam_on(u3k(b), u3k(u3t(a))));
+ }
+ }
+ u3_noun
+ u3wb_bind(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_bind(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/b/clap.c b/vere/pkg/noun/jets/b/clap.c
new file mode 100644
index 0000000..9cfb41a
--- /dev/null
+++ b/vere/pkg/noun/jets/b/clap.c
@@ -0,0 +1,36 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_clap(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+ {
+ if ( 0 == a ) {
+ return u3k(b);
+ }
+ else if ( 0 == b ) {
+ return u3k(a);
+ }
+ else {
+ return u3nc(0, u3n_slam_on(u3k(c), u3nc(u3k(u3t(a)), u3k(u3t(b)))));
+ }
+ }
+ u3_noun
+ u3wb_clap(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_6, &b,
+ u3x_sam_7, &c, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_clap(a, b, c);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/find.c b/vere/pkg/noun/jets/b/find.c
new file mode 100644
index 0000000..c0295d2
--- /dev/null
+++ b/vere/pkg/noun/jets/b/find.c
@@ -0,0 +1,50 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+STATIC_ASSERT( (UINT32_MAX > u3a_cells),
+ "list index precision" );
+
+u3_noun
+u3qb_find(u3_noun nedl, u3_noun hstk)
+{
+ if ( u3_nul != nedl ) {
+ c3_w i_w = 0;
+
+ while ( u3_nul != hstk ) {
+ u3_noun i_h, t_h = hstk;
+ u3_noun i_n, t_n = nedl;
+ u3x_cell(t_h, &i_h, &t_h);
+ u3x_cell(t_n, &i_n, &t_n);
+
+ while ( c3y == u3r_sing(i_n, i_h) ) {
+ if ( u3_nul == t_n ) {
+ return u3nc(u3_nul, u3i_word(i_w));
+ }
+ else if ( u3_nul == t_h ) {
+ break;
+ }
+ else {
+ u3x_cell(t_h, &i_h, &t_h);
+ u3x_cell(t_n, &i_n, &t_n);
+ }
+ }
+
+ hstk = u3t(hstk);
+ i_w++;
+ }
+ }
+
+ return u3_nul;
+}
+
+u3_noun
+u3wb_find(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_find(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/flop.c b/vere/pkg/noun/jets/b/flop.c
new file mode 100644
index 0000000..0574e4e
--- /dev/null
+++ b/vere/pkg/noun/jets/b/flop.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_flop(u3_noun a)
+{
+ u3_noun i, t = a, b = u3_nul;
+
+ while ( u3_nul != t ) {
+ u3x_cell(t, &i, &t);
+ b = u3nc(u3k(i), b);
+ }
+
+ return b;
+}
+
+u3_noun
+u3wb_flop(u3_noun cor)
+{
+ return u3qb_flop(u3x_at(u3x_sam, cor));
+}
+
+u3_noun
+u3kb_flop(u3_noun a)
+{
+ u3_noun b = u3qb_flop(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/b/lent.c b/vere/pkg/noun/jets/b/lent.c
new file mode 100644
index 0000000..aa3a701
--- /dev/null
+++ b/vere/pkg/noun/jets/b/lent.c
@@ -0,0 +1,37 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+STATIC_ASSERT( (UINT32_MAX > u3a_cells),
+ "length precision" );
+
+u3_noun
+u3qb_lent(u3_noun a)
+{
+ c3_w len_w = 0;
+
+ while ( u3_nul != a ) {
+ a = u3t(a);
+ len_w++;
+ }
+
+ return u3i_word(len_w);
+}
+
+u3_noun
+u3wb_lent(u3_noun cor)
+{
+ return u3qb_lent(u3x_at(u3x_sam, cor));
+}
+
+u3_noun
+u3kb_lent(u3_noun a)
+{
+ u3_noun b = u3qb_lent(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/b/levy.c b/vere/pkg/noun/jets/b/levy.c
new file mode 100644
index 0000000..39d6f39
--- /dev/null
+++ b/vere/pkg/noun/jets/b/levy.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qb_levy(u3_noun a,
+ u3_noun b)
+ {
+ u3_noun pro = c3y;
+ c3_o loz_o;
+
+ if ( u3_nul != a ) {
+ u3j_site sit_u;
+ u3_noun i, t;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ loz_o = u3x_loob(u3j_gate_slam(&sit_u, u3k(i)));
+ if ( c3n == loz_o ) {
+ pro = c3n;
+ break;
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ } while ( u3_nul != a );
+
+ u3z(a);
+ u3j_gate_lose(&sit_u);
+ }
+
+ return pro;
+ }
+
+ u3_noun
+ u3wb_levy(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_levy(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/lien.c b/vere/pkg/noun/jets/b/lien.c
new file mode 100644
index 0000000..2a9290a
--- /dev/null
+++ b/vere/pkg/noun/jets/b/lien.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qb_lien(u3_noun a,
+ u3_noun b)
+ {
+ u3_noun pro = c3n;
+ c3_o loz_o;
+
+ if ( u3_nul != a ) {
+ u3j_site sit_u;
+ u3_noun i, t;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ loz_o = u3x_loob(u3j_gate_slam(&sit_u, u3k(i)));
+ if ( c3y == loz_o ) {
+ pro = c3y;
+ break;
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ } while ( u3_nul != a );
+
+ u3z(a);
+ u3j_gate_lose(&sit_u);
+ }
+
+ return pro;
+ }
+
+ u3_noun
+ u3wb_lien(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_lien(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/mate.c b/vere/pkg/noun/jets/b/mate.c
new file mode 100644
index 0000000..f8dbd31
--- /dev/null
+++ b/vere/pkg/noun/jets/b/mate.c
@@ -0,0 +1,30 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_mate(u3_noun a,
+ u3_noun b)
+ {
+ if ( u3_nul == b ) {
+ return u3k(a);
+ } else if ( u3_nul == a ) {
+ return u3k(b);
+ } else if ( c3y == u3r_sing(u3t(a), u3t(b)) ) {
+ return u3k(a);
+ } else {
+ return u3m_error("mate");
+ }
+ }
+ u3_noun
+ u3wb_mate(u3_noun cor)
+ {
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_mate(a, b);
+ }
+
diff --git a/vere/pkg/noun/jets/b/murn.c b/vere/pkg/noun/jets/b/murn.c
new file mode 100644
index 0000000..dcb592b
--- /dev/null
+++ b/vere/pkg/noun/jets/b/murn.c
@@ -0,0 +1,54 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_murn(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ if ( u3_nul != a ) {
+ u3_noun* hed;
+ u3_noun* tel;
+ u3_noun res, i, t;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ res = u3j_gate_slam(&sit_u, u3k(i));
+
+ if ( u3_nul != res ) {
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(u3t(res));
+ lit = tel;
+ u3z(res);
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ }
+ while ( u3_nul != a );
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+}
+
+u3_noun
+u3wb_murn(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_murn(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/need.c b/vere/pkg/noun/jets/b/need.c
new file mode 100644
index 0000000..8723699
--- /dev/null
+++ b/vere/pkg/noun/jets/b/need.c
@@ -0,0 +1,30 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_need(u3_noun a)
+ {
+ if ( 0 == a ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3k(u3t(a));
+ }
+ }
+ u3_noun
+ u3wb_need(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( u3_none == (a = u3r_at(u3x_sam, cor)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_need(a);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/b/reap.c b/vere/pkg/noun/jets/b/reap.c
new file mode 100644
index 0000000..35dd055
--- /dev/null
+++ b/vere/pkg/noun/jets/b/reap.c
@@ -0,0 +1,41 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_reap(u3_atom a,
+ u3_noun b)
+ {
+ if ( !_(u3a_is_cat(a)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun acc = u3_nul;
+ c3_w i_w = a;
+
+ while ( i_w ) {
+ acc = u3nc(u3k(b), acc);
+ i_w--;
+ }
+
+ return acc;
+ }
+ }
+
+ u3_noun
+ u3wb_reap(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_reap(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/reel.c b/vere/pkg/noun/jets/b/reel.c
new file mode 100644
index 0000000..fe84f5a
--- /dev/null
+++ b/vere/pkg/noun/jets/b/reel.c
@@ -0,0 +1,52 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qb_reel(u3_noun a,
+ u3_noun b)
+ {
+ u3_noun pro = u3k(u3x_at(u3x_sam_3, b));
+
+ if ( u3_nul != a ) {
+ u3a_pile pil_u;
+ u3j_site sit_u;
+ u3_noun* top;
+ u3_noun i, t = a;
+
+ u3a_pile_prep(&pil_u, sizeof(u3_noun));
+
+ // push list onto road stack
+ //
+ do {
+ u3x_cell(t, &i, &t);
+ top = u3a_push(&pil_u);
+ *top = u3k(i);
+ } while ( u3_nul != t );
+
+ u3j_gate_prep(&sit_u, u3k(b));
+
+ while ( c3n == u3a_pile_done(&pil_u) ) {
+ pro = u3j_gate_slam(&sit_u, u3nc(*top, pro));
+ top = u3a_pop(&pil_u);
+ }
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ return pro;
+ }
+ u3_noun
+ u3wb_reel(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_reel(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/roll.c b/vere/pkg/noun/jets/b/roll.c
new file mode 100644
index 0000000..66a4726
--- /dev/null
+++ b/vere/pkg/noun/jets/b/roll.c
@@ -0,0 +1,44 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qb_roll(u3_noun a,
+ u3_noun b)
+ {
+ u3_noun pro = u3k(u3x_at(u3x_sam_3, b));
+
+ if ( u3_nul != a ) {
+ u3j_site sit_u;
+ u3_noun i, t;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ pro = u3j_gate_slam(&sit_u, u3nc(u3k(i), pro));
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ } while ( u3_nul != a );
+ u3j_gate_lose(&sit_u);
+ }
+
+ return pro;
+ }
+ u3_noun
+ u3wb_roll(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_roll(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/b/scag.c b/vere/pkg/noun/jets/b/scag.c
new file mode 100644
index 0000000..d13dd46
--- /dev/null
+++ b/vere/pkg/noun/jets/b/scag.c
@@ -0,0 +1,53 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_scag(u3_atom a, u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3_nul;
+ }
+ else if ( !_(u3a_is_cat(a)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ {
+ c3_w len_w = (c3_w)a;
+ u3_noun* hed;
+ u3_noun* tel;
+ u3_noun i, t = b;
+
+ while ( len_w-- && (u3_nul != t) ) {
+ u3x_cell(t, &i, &t);
+
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ lit = tel;
+ }
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+ }
+}
+
+u3_noun
+u3wb_scag(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+
+ if ( (c3n == u3ud(a)) && (u3_nul != b) ) {
+ return u3m_bail(c3__exit);
+ }
+
+ return u3qb_scag(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/skid.c b/vere/pkg/noun/jets/b/skid.c
new file mode 100644
index 0000000..8d0d7ef
--- /dev/null
+++ b/vere/pkg/noun/jets/b/skid.c
@@ -0,0 +1,62 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_skid(u3_noun a, u3_noun b)
+{
+ u3_noun l, r;
+ u3_noun* lef = &l;
+ u3_noun* rig = &r;
+
+ if ( u3_nul != a) {
+ u3_noun i, t;
+ u3_noun* hed;
+ u3_noun* tel;
+ u3j_site sit_u;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ switch ( u3j_gate_slam(&sit_u, u3k(i)) ) {
+ case c3y: {
+ *lef = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ lef = tel;
+ } break;
+
+ case c3n: {
+ *rig = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ rig = tel;
+ } break;
+
+ default: u3m_bail(c3__exit);
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ }
+ while ( u3_nul != a );
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ *lef = u3_nul;
+ *rig = u3_nul;
+
+ return u3nc(l, r);
+}
+
+u3_noun
+u3wb_skid(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_skid(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/skim.c b/vere/pkg/noun/jets/b/skim.c
new file mode 100644
index 0000000..b0f2255
--- /dev/null
+++ b/vere/pkg/noun/jets/b/skim.c
@@ -0,0 +1,56 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_skim(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ if ( u3_nul != a) {
+ u3_noun i, t;
+ u3_noun* hed;
+ u3_noun* tel;
+ u3j_site sit_u;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ switch ( u3j_gate_slam(&sit_u, u3k(i)) ) {
+ case c3y: {
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ lit = tel;
+ } break;
+
+ case c3n: break;
+
+ default: u3m_bail(c3__exit);
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ }
+ while ( u3_nul != a );
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+}
+
+u3_noun
+u3wb_skim(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_skim(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/skip.c b/vere/pkg/noun/jets/b/skip.c
new file mode 100644
index 0000000..67f537d
--- /dev/null
+++ b/vere/pkg/noun/jets/b/skip.c
@@ -0,0 +1,56 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_skip(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ if ( u3_nul != a) {
+ u3_noun i, t;
+ u3_noun* hed;
+ u3_noun* tel;
+ u3j_site sit_u;
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ switch ( u3j_gate_slam(&sit_u, u3k(i)) ) {
+ case c3y: break;
+
+ case c3n: {
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ lit = tel;
+ } break;
+
+ default: u3m_bail(c3__exit);
+ }
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ }
+ while ( u3_nul != a );
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+}
+
+u3_noun
+u3wb_skip(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_skip(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/slag.c b/vere/pkg/noun/jets/b/slag.c
new file mode 100644
index 0000000..fad88b0
--- /dev/null
+++ b/vere/pkg/noun/jets/b/slag.c
@@ -0,0 +1,43 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_slag(u3_atom a, u3_noun b)
+ {
+ if ( u3_nul == b ) {
+ return u3_nul;
+ }
+ else if ( !_(u3a_is_cat(a)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_w len_w = a;
+
+ while ( len_w ) {
+ if ( c3n == u3du(b) ) {
+ return u3_nul;
+ }
+ b = u3t(b);
+ len_w--;
+ }
+ return u3k(b);
+ }
+ }
+ u3_noun
+ u3wb_slag(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a) && u3_nul != b) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_slag(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/snag.c b/vere/pkg/noun/jets/b/snag.c
new file mode 100644
index 0000000..4b6dad8
--- /dev/null
+++ b/vere/pkg/noun/jets/b/snag.c
@@ -0,0 +1,44 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qb_snag(u3_atom a,
+ u3_noun b)
+ {
+ if ( !_(u3a_is_cat(a)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_w len_w = a;
+
+ while ( len_w ) {
+ if ( c3n == u3du(b) ) {
+ return u3m_bail(c3__exit);
+ }
+ b = u3t(b);
+ len_w--;
+ }
+ if ( c3n == u3du(b) ) {
+ return u3m_bail(c3__exit);
+ }
+ return u3k(u3h(b));
+ }
+ }
+ u3_noun
+ u3wb_snag(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qb_snag(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/b/sort.c b/vere/pkg/noun/jets/b/sort.c
new file mode 100644
index 0000000..ea5507c
--- /dev/null
+++ b/vere/pkg/noun/jets/b/sort.c
@@ -0,0 +1,125 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+static_assert( (UINT32_MAX > u3a_cells),
+ "length precision" );
+
+static_assert(
+ (UINT32_MAX < (SIZE_MAX / (2 * sizeof(u3_noun)))),
+ "len_w * sizeof u3_noun overflow"
+);
+
+static void
+_merge_sort(u3_noun* restrict arr_u,
+ u3_noun* restrict tmp_u,
+ c3_w lef_w,
+ c3_w rit_w,
+ u3j_site* sit_u)
+{
+ if ( lef_w >= rit_w ) return;
+ c3_w mid_w = (lef_w + rit_w) / 2;
+ if (mid_w < lef_w)
+ {
+ // addition wrapped around
+ //
+ u3m_bail(c3__fail);
+ }
+ _merge_sort(arr_u, tmp_u, lef_w, mid_w, sit_u);
+ _merge_sort(arr_u, tmp_u, mid_w + 1, rit_w, sit_u);
+
+ c3_w i_w = lef_w, j_w = mid_w + 1, k_w = lef_w;
+ while (i_w <= mid_w && j_w <= rit_w)
+ {
+ // reversed comparison to mimick order reversal of pivot
+ // and compared element in Hoon
+ //
+ u3_noun sam = u3nc(u3k(arr_u[j_w]), u3k(arr_u[i_w]));
+ c3_o hoz_o = u3x_loob(u3j_gate_slam(sit_u, sam));
+ if ( c3n == hoz_o )
+ tmp_u[k_w++] = arr_u[i_w++];
+ else
+ tmp_u[k_w++] = arr_u[j_w++];
+ }
+
+ while (i_w <= mid_w) tmp_u[k_w++] = arr_u[i_w++];
+ while (j_w <= rit_w) tmp_u[k_w++] = arr_u[j_w++];
+
+ for (i_w = lef_w; i_w <= rit_w; i_w++)
+ {
+ arr_u[i_w] = tmp_u[i_w];
+ }
+}
+
+// RETAINS list, transfers product
+//
+static u3_noun
+_sort(u3j_site* sit_u, u3_noun list)
+{
+ if (u3_nul == list) return u3_nul;
+
+ c3_w len_w = 1;
+ {
+ u3_noun t = u3t(list);
+ while (u3_nul != t)
+ {
+ ++len_w; t = u3t(t);
+ }
+ }
+
+ if (1 == len_w) return u3k(list);
+ u3_noun* arr_u = u3a_malloc(sizeof(u3_noun) * len_w * 2);
+ u3_noun* tmp_u = arr_u + len_w;
+ for (c3_w i_w = 0; i_w < len_w; i_w++)
+ {
+ // inlined u3r_cell without any checks
+ // since the list was already validated and measured
+ //
+ u3a_cell* cel_u = u3a_to_ptr(list);
+ arr_u[i_w] = u3k(cel_u->hed);
+ list = cel_u->tel;
+ }
+
+ _merge_sort(arr_u, tmp_u, 0, len_w - 1, sit_u);
+
+ u3_noun pro = u3_nul;
+ for (c3_w i_w = len_w; i_w--;)
+ {
+ pro = u3nc(arr_u[i_w], pro);
+ }
+
+ u3a_free(arr_u);
+
+ return pro;
+}
+
+u3_noun
+u3qb_sort(u3_noun a,
+ u3_noun b)
+{
+ u3_noun pro;
+ u3j_site sit_u;
+ u3j_gate_prep(&sit_u, u3k(b));
+ pro = _sort(&sit_u, a);
+ u3j_gate_lose(&sit_u);
+ return pro;
+}
+
+u3_noun
+u3wb_sort(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else
+ {
+ return u3qb_sort(a, b);
+ }
+}
diff --git a/vere/pkg/noun/jets/b/turn.c b/vere/pkg/noun/jets/b/turn.c
new file mode 100644
index 0000000..e5ee5f7
--- /dev/null
+++ b/vere/pkg/noun/jets/b/turn.c
@@ -0,0 +1,49 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_turn(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ if ( u3_nul != a ) {
+ u3_noun* hed;
+ u3_noun* tel;
+ u3_noun i, t;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ u3k(a);
+
+ do {
+ i = u3h(a);
+
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3j_gate_slam(&sit_u, u3k(i));
+ lit = tel;
+
+ t = u3k(u3t(a));
+ u3z(a), a = t;
+ }
+ while ( u3_nul != a );
+
+ u3j_gate_lose(&sit_u);
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+}
+
+u3_noun
+u3wb_turn(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_turn(a, b);
+}
diff --git a/vere/pkg/noun/jets/b/weld.c b/vere/pkg/noun/jets/b/weld.c
new file mode 100644
index 0000000..d50fa1c
--- /dev/null
+++ b/vere/pkg/noun/jets/b/weld.c
@@ -0,0 +1,48 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_weld(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ {
+ u3_noun* hed;
+ u3_noun* tel;
+ u3_noun i, t = a;
+
+ while ( u3_nul != t ) {
+ u3x_cell(t, &i, &t);
+
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(i);
+ lit = tel;
+ }
+ }
+
+ *lit = u3k(b);
+
+ return pro;
+}
+
+u3_noun
+u3wb_weld(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qb_weld(a, b);
+}
+
+u3_noun
+u3kb_weld(u3_noun a, u3_noun b)
+{
+ u3_noun c = u3qb_weld(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/b/zing.c b/vere/pkg/noun/jets/b/zing.c
new file mode 100644
index 0000000..1172d5e
--- /dev/null
+++ b/vere/pkg/noun/jets/b/zing.c
@@ -0,0 +1,47 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qb_zing(u3_noun a)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ if ( u3_nul == a ) {
+ *lit = u3_nul;
+ }
+ else {
+ u3_noun i, t = a;
+ u3x_cell(t, &i, &t);
+
+ while ( u3_nul != t ) {
+ u3_noun* hed;
+ u3_noun* tel;
+ u3_noun i_i, t_i = i;
+
+ while ( u3_nul != t_i ) {
+ u3x_cell(t_i, &i_i, &t_i);
+
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = u3k(i_i);
+ lit = tel;
+ }
+
+ u3x_cell(t, &i, &t);
+ }
+
+ *lit = u3k(i);
+ }
+
+ return pro;
+}
+
+u3_noun
+u3wb_zing(u3_noun cor)
+{
+ return u3qb_zing(u3x_at(u3x_sam, cor));
+}
diff --git a/vere/pkg/noun/jets/c/aor.c b/vere/pkg/noun/jets/c/aor.c
new file mode 100644
index 0000000..248661e
--- /dev/null
+++ b/vere/pkg/noun/jets/c/aor.c
@@ -0,0 +1,69 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qc_aor(u3_noun a,
+ u3_noun b)
+ {
+ while ( 1 ) {
+ if ( c3y == u3r_sing(a, b) ) return c3y;
+ if ( c3n == u3ud(a) ) {
+ if ( c3y == u3ud(b) ) return c3n;
+ if ( c3y == u3r_sing(u3h(a), u3h(b)) ) {
+ a = u3t(a);
+ b = u3t(b);
+ }
+ else {
+ a = u3h(a);
+ b = u3h(b);
+ }
+ }
+ else {
+ if ( c3n == u3ud(b) ) return c3y;
+ {
+ c3_w len_a_w = u3r_met(3, a);
+ c3_w len_b_w = u3r_met(3, b);;
+ c3_y *buf_a_y, *buf_b_y;
+ c3_y cut_a_y, cut_b_y;
+ if ( c3y == u3a_is_cat(a) ) {
+ buf_a_y = (c3_y*)&a;
+ }
+ else {
+ u3a_atom* a_u = u3a_to_ptr(a);
+ buf_a_y = (c3_y*)(a_u->buf_w);
+ }
+ if ( c3y == u3a_is_cat(b) ) {
+ buf_b_y = (c3_y*)&b;
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+ buf_b_y = (c3_y*)(b_u->buf_w);
+ }
+ c3_w len_min_w = c3_min(len_a_w, len_b_w);
+ for (c3_w i_w = 0; i_w < len_min_w; i_w++) {
+ cut_a_y = buf_a_y[i_w];
+ cut_b_y = buf_b_y[i_w];
+ if ( cut_a_y != cut_b_y ) return __(cut_a_y < cut_b_y);
+ }
+ return __(len_a_w < len_b_w);
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wc_aor(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_aor(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/bex.c b/vere/pkg/noun/jets/c/bex.c
new file mode 100644
index 0000000..497ebfd
--- /dev/null
+++ b/vere/pkg/noun/jets/c/bex.c
@@ -0,0 +1,55 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_bex(u3_atom a)
+{
+ c3_d a_d;
+ u3i_slab sab_u;
+
+ if ( a < 31 ) {
+ return 1U << a;
+ }
+
+ if ( c3y == u3a_is_cat(a) ) {
+ a_d = a;
+ }
+ else {
+ if ( c3n == u3r_safe_chub(a, &a_d) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ // We don't currently support atoms 2GB or larger (fails while
+ // mugging). The extra term of 16 is experimentally determined.
+ if ( a_d >= ((c3_d)1 << (c3_d)34) - 16 ) {
+ u3l_log("bex: overflow");
+ return u3m_bail(c3__fail);
+ }
+ }
+
+ u3i_slab_init(&sab_u, 0, a_d + 1);
+
+ sab_u.buf_w[a_d >> 5] = 1U << (a_d & 31);
+
+ return u3i_slab_moot(&sab_u);
+}
+
+u3_noun
+u3kc_bex(u3_atom a)
+{
+ u3_noun b = u3qc_bex(a);
+ u3z(a);
+ return b;
+}
+
+u3_noun
+u3wc_bex(u3_noun cor)
+{
+ u3_noun a = u3x_at(u3x_sam, cor);
+ return u3qc_bex(u3x_atom(a));
+}
diff --git a/vere/pkg/noun/jets/c/c0n.c b/vere/pkg/noun/jets/c/c0n.c
new file mode 100644
index 0000000..a6fee5b
--- /dev/null
+++ b/vere/pkg/noun/jets/c/c0n.c
@@ -0,0 +1,55 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_con(u3_atom a,
+ u3_atom b)
+ {
+ c3_w lna_w = u3r_met(5, a);
+ c3_w lnb_w = u3r_met(5, b);
+
+ if ( (lna_w == 0) && (lnb_w == 0) ) {
+ return 0;
+ }
+ else {
+ c3_w len_w = c3_max(lna_w, lnb_w);
+ c3_w i_w;
+ u3i_slab sab_u;
+ u3i_slab_from(&sab_u, a, 5, len_w);
+
+ for ( i_w = 0; i_w < lnb_w; i_w++ ) {
+ sab_u.buf_w[i_w] |= u3r_word(i_w, b);
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ u3_noun
+ u3wc_con(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_con(a, b);
+ }
+ }
+
+u3_noun
+u3kc_con(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qc_con(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/c/can.c b/vere/pkg/noun/jets/c/can.c
new file mode 100644
index 0000000..ca6d97a
--- /dev/null
+++ b/vere/pkg/noun/jets/c/can.c
@@ -0,0 +1,85 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_can(u3_atom a,
+ u3_noun b)
+ {
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w tot_w = 0;
+ u3i_slab sab_u;
+
+ /* Measure and validate the slab required.
+ */
+ {
+ u3_noun cab = b;
+
+ while ( 1 ) {
+ u3_noun i_cab, pi_cab, qi_cab;
+
+ if ( 0 == cab ) {
+ break;
+ }
+ if ( c3n == u3du(cab) ) return u3m_bail(c3__fail);
+ i_cab = u3h(cab);
+ if ( c3n == u3du(i_cab) ) return u3m_bail(c3__fail);
+ pi_cab = u3h(i_cab);
+ qi_cab = u3t(i_cab);
+ if ( c3n == u3a_is_cat(pi_cab) ) return u3m_bail(c3__fail);
+ if ( c3n == u3ud(qi_cab) ) return u3m_bail(c3__fail);
+ if ( (tot_w + pi_cab) < tot_w ) return u3m_bail(c3__fail);
+
+ tot_w += pi_cab;
+ cab = u3t(cab);
+ }
+
+ if ( 0 == tot_w ) {
+ return 0;
+ }
+
+ u3i_slab_init(&sab_u, a_g, tot_w);
+ }
+
+ /* Chop the list atoms in.
+ */
+ {
+ u3_noun cab = b;
+ c3_w pos_w = 0;
+
+ while ( 0 != cab ) {
+ u3_noun i_cab = u3h(cab);
+ u3_atom pi_cab = u3h(i_cab);
+ u3_atom qi_cab = u3t(i_cab);
+
+ u3r_chop(a_g, 0, pi_cab, pos_w, sab_u.buf_w, qi_cab);
+ pos_w += pi_cab;
+ cab = u3t(cab);
+ }
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ u3_noun
+ u3wc_can(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qc_can(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/cap.c b/vere/pkg/noun/jets/c/cap.c
new file mode 100644
index 0000000..95bef1f
--- /dev/null
+++ b/vere/pkg/noun/jets/c/cap.c
@@ -0,0 +1,25 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_cap(u3_atom a)
+{
+ c3_w met_w = u3r_met(0, a);
+
+ if ( 2 > met_w ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return 2 + u3r_bit((met_w - 2), a);
+ }
+}
+
+u3_noun
+u3wc_cap(u3_noun cor)
+{
+ return u3qc_cap(u3x_atom(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/c/cat.c b/vere/pkg/noun/jets/c/cat.c
new file mode 100644
index 0000000..f3c4d2d
--- /dev/null
+++ b/vere/pkg/noun/jets/c/cat.c
@@ -0,0 +1,54 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_cat(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+ {
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w lew_w = u3r_met(a_g, b);
+ c3_w ler_w = u3r_met(a_g, c);
+ c3_w all_w = (lew_w + ler_w);
+
+ if ( 0 == all_w ) {
+ return 0;
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_from(&sab_u, b, a_g, all_w);
+
+ u3r_chop(a_g, 0, ler_w, lew_w, sab_u.buf_w, c);
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ }
+
+ u3_noun
+ u3wc_cat(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_6, &b,
+ u3x_sam_7, &c, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_cat(a, b, c);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/clz.c b/vere/pkg/noun/jets/c/clz.c
new file mode 100644
index 0000000..f8da45a
--- /dev/null
+++ b/vere/pkg/noun/jets/c/clz.c
@@ -0,0 +1,75 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_atom
+u3qc_clz(u3_atom boq, u3_atom sep, u3_atom a)
+{
+ if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ if ( !_(u3a_is_cat(sep)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_g boq_g = boq;
+ c3_w sep_w = sep;
+ c3_w tot_w = sep_w << boq_g;
+
+ if ( (tot_w >> boq_g) != sep_w ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w met_w = u3r_met(0, a);
+
+ if ( met_w <= tot_w ) {
+ tot_w -= met_w;
+ return u3i_word(tot_w);
+ }
+ else {
+ c3_w wid_w = tot_w >> 5;
+ c3_w bit_w = tot_w & 31;
+ c3_w wor_w;
+
+ if ( bit_w ) {
+ wor_w = u3r_word(wid_w, a);
+ wor_w &= (1 << bit_w) - 1;
+
+ if ( wor_w ) {
+ return bit_w - (32 - c3_lz_w(wor_w));
+ }
+ }
+
+ while ( wid_w-- ) {
+ wor_w = u3r_word(wid_w, a);
+
+ if ( wor_w ) {
+ bit_w += c3_lz_w(wor_w);
+ break;
+ }
+
+ bit_w += 32;
+ }
+
+ return u3i_word(bit_w);
+ }
+}
+
+u3_noun
+u3wc_clz(u3_noun cor)
+{
+ u3_atom boq, sep, vat;
+ {
+ u3_noun sam = u3h(u3t(cor));
+ u3_noun bit = u3h(sam);
+
+ u3x_bite(bit, &boq, &sep);
+ vat = u3x_atom(u3t(sam));
+ }
+
+ return u3qc_clz(boq, sep, vat);
+}
diff --git a/vere/pkg/noun/jets/c/ctz.c b/vere/pkg/noun/jets/c/ctz.c
new file mode 100644
index 0000000..ff74e24
--- /dev/null
+++ b/vere/pkg/noun/jets/c/ctz.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_atom
+u3qc_ctz(u3_atom a)
+{
+ c3_w wor_w, i_w = 0;
+
+ if ( 0 == a ) {
+ return 0;
+ }
+
+ do {
+ wor_w = u3r_word(i_w++, a);
+ }
+ while ( !wor_w );
+
+ {
+ c3_w bit_d = i_w - 1;
+ bit_d *= 32;
+ bit_d += c3_tz_w(wor_w);
+ return u3i_chub(bit_d);
+ }
+}
+
+u3_noun
+u3wc_ctz(u3_noun cor)
+{
+ return u3qc_ctz(u3x_atom(u3h(u3t(cor))));
+}
diff --git a/vere/pkg/noun/jets/c/cut.c b/vere/pkg/noun/jets/c/cut.c
new file mode 100644
index 0000000..43ed8c4
--- /dev/null
+++ b/vere/pkg/noun/jets/c/cut.c
@@ -0,0 +1,68 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_cut(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom d)
+ {
+ c3_w b_w, c_w;
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ if ( !_(u3r_safe_word(b, &b_w)) ) {
+ return u3m_bail(c3__fail);
+ }
+ if ( !_(u3r_safe_word(c, &c_w)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ {
+ c3_g a_g = a;
+ c3_w len_w = u3r_met(a_g, d);
+
+ if ( (0 == c_w) || (b_w >= len_w) ) {
+ return 0;
+ }
+ if ( b_w + c_w > len_w ) {
+ c_w = (len_w - b_w);
+ }
+ if ( (b_w == 0) && (c_w == len_w) ) {
+ return u3k(d);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, c_w);
+
+ u3r_chop(a_g, b_w, c_w, 0, sab_u.buf_w, d);
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ }
+ u3_noun
+ u3wc_cut(u3_noun cor)
+ {
+ u3_noun a, b, c, d;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_12, &b,
+ u3x_sam_13, &c,
+ u3x_sam_7, &d, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) ||
+ (c3n == u3ud(d)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_cut(a, b, c, d);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/dis.c b/vere/pkg/noun/jets/c/dis.c
new file mode 100644
index 0000000..8c41a36
--- /dev/null
+++ b/vere/pkg/noun/jets/c/dis.c
@@ -0,0 +1,46 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_dis(u3_atom a,
+ u3_atom b)
+ {
+ c3_w lna_w = u3r_met(5, a);
+ c3_w lnb_w = u3r_met(5, b);
+
+ if ( (lna_w == 0) && (lnb_w == 0) ) {
+ return 0;
+ }
+ else {
+ c3_w len_w = c3_max(lna_w, lnb_w);
+ c3_w i_w;
+ u3i_slab sab_u;
+ u3i_slab_from(&sab_u, a, 5, len_w);
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ sab_u.buf_w[i_w] &= u3r_word(i_w, b);
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ u3_noun
+ u3wc_dis(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_dis(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/dor.c b/vere/pkg/noun/jets/c/dor.c
new file mode 100644
index 0000000..0c1e220
--- /dev/null
+++ b/vere/pkg/noun/jets/c/dor.c
@@ -0,0 +1,49 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_dor(u3_noun a,
+ u3_noun b)
+ {
+ if ( c3y == u3r_sing(a, b) ) {
+ return c3y;
+ }
+ else {
+ if ( c3y == u3ud(a) ) {
+ if ( c3y == u3ud(b) ) {
+ return u3qa_lth(a, b);
+ }
+ else {
+ return c3y;
+ }
+ }
+ else {
+ if ( c3y == u3ud(b) ) {
+ return c3n;
+ }
+ else {
+ if ( c3y == u3r_sing(u3h(a), u3h(b)) ) {
+ return u3qc_dor(u3t(a), u3t(b));
+ }
+ else return u3qc_dor(u3h(a), u3h(b));
+ }
+ }
+ }
+ }
+ u3_noun
+ u3wc_dor(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_dor(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/dvr.c b/vere/pkg/noun/jets/c/dvr.c
new file mode 100644
index 0000000..d822bf3
--- /dev/null
+++ b/vere/pkg/noun/jets/c/dvr.c
@@ -0,0 +1,46 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_dvr(u3_atom a,
+ u3_atom b)
+ {
+ if ( 0 == b ) {
+ return u3m_error("divide-by-zero");
+ }
+ else {
+ if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) {
+ return u3nc(a / b, a % b);
+ }
+ else {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ u3r_mp(b_mp, b);
+
+ mpz_tdiv_qr(a_mp, b_mp, a_mp, b_mp);
+
+ return u3nc(u3i_mp(a_mp), u3i_mp(b_mp));
+ }
+ }
+ }
+ u3_noun
+ u3wc_dvr(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qc_dvr(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/end.c b/vere/pkg/noun/jets/c/end.c
new file mode 100644
index 0000000..94618ad
--- /dev/null
+++ b/vere/pkg/noun/jets/c/end.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_end(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+{
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else if ( !_(u3a_is_cat(b)) ) {
+ return u3k(c);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w b_w = b;
+ c3_w len_w = u3r_met(a_g, c);
+
+ if ( 0 == b_w ) {
+ return 0;
+ }
+ else if ( b_w >= len_w ) {
+ return u3k(c);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, b_w);
+
+ u3r_chop(a_g, 0, b_w, 0, sab_u.buf_w, c);
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+}
+
+u3_noun
+u3wc_end(u3_noun cor)
+{
+ u3_atom bloq, step;
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0);
+ u3x_bite(a, &bloq, &step);
+
+ return u3qc_end(bloq, step, u3x_atom(b));
+}
diff --git a/vere/pkg/noun/jets/c/gor.c b/vere/pkg/noun/jets/c/gor.c
new file mode 100644
index 0000000..91c2d98
--- /dev/null
+++ b/vere/pkg/noun/jets/c/gor.c
@@ -0,0 +1,32 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_gor(u3_noun a,
+ u3_noun b)
+ {
+ c3_w c_w = u3r_mug(a);
+ c3_w d_w = u3r_mug(b);
+
+ if ( c_w == d_w ) {
+ return u3qc_dor(a, b);
+ }
+ else return (c_w < d_w) ? c3y : c3n;
+ }
+ u3_noun
+ u3wc_gor(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_gor(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/ham.c b/vere/pkg/noun/jets/c/ham.c
new file mode 100644
index 0000000..776cf0c
--- /dev/null
+++ b/vere/pkg/noun/jets/c/ham.c
@@ -0,0 +1,27 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_atom
+u3qc_ham(u3_atom a)
+{
+ c3_w len_w = u3r_met(5, a);
+ c3_d pop_d = 0;
+ c3_w wor_w;
+
+ for ( c3_w i_w = 0; i_w < len_w; i_w++ ) {
+ wor_w = u3r_word(i_w, a);
+ pop_d += c3_pc_w(wor_w);
+ }
+
+ return u3i_chub(pop_d);
+}
+
+u3_noun
+u3wc_ham(u3_noun cor)
+{
+ return u3qc_ham(u3x_atom(u3h(u3t(cor))));
+}
diff --git a/vere/pkg/noun/jets/c/hew.c b/vere/pkg/noun/jets/c/hew.c
new file mode 100644
index 0000000..be6b7a7
--- /dev/null
+++ b/vere/pkg/noun/jets/c/hew.c
@@ -0,0 +1,87 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static c3_w
+_hew_in(c3_g a_g,
+ c3_w pos_w,
+ u3_atom vat,
+ u3_noun sam,
+ u3_noun* out)
+{
+ u3_noun h, t, *l, *r;
+
+ while ( c3y == u3r_cell(sam, &h, &t) ) {
+ *out = u3i_defcons(&l, &r);
+ pos_w = _hew_in(a_g, pos_w, vat, h, l);
+ sam = t;
+ out = r;
+ }
+
+ if ( !_(u3a_is_cat(sam)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ if ( !sam ) {
+ *out = 0;
+ return pos_w;
+ }
+ else {
+ c3_w wid_w = (c3_w)sam;
+ c3_w new_w = pos_w + wid_w;
+ u3i_slab sab_u;
+
+ if ( new_w < pos_w ) {
+ return u3m_bail(c3__fail);
+ }
+
+ u3i_slab_init(&sab_u, a_g, wid_w);
+ u3r_chop(a_g, pos_w, wid_w, 0, sab_u.buf_w, vat);
+
+ *out = u3i_slab_mint(&sab_u);
+ return new_w;
+ }
+}
+
+u3_noun
+u3qc_hew(u3_atom boq,
+ u3_atom sep,
+ u3_atom vat,
+ u3_noun sam)
+{
+ if ( !_(u3a_is_cat(boq)) || (boq >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ if ( !_(u3a_is_cat(sep)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ u3_noun pro;
+ c3_w pos_w = _hew_in((c3_g)boq, (c3_w)sep, vat, sam, &pro);
+ return u3nt(pro, boq, u3i_word(pos_w));
+}
+
+u3_noun
+u3wc_hew(u3_noun cor)
+{
+ u3_atom boq, sep, vat;
+ u3_noun sam;
+ {
+ u3_noun pay = u3t(cor);
+ u3_noun con = u3t(pay);
+ u3_noun gat = u3t(con); // outer gate
+ u3_noun cam = u3h(u3t(gat)); // outer sample
+ u3_noun d = u3h(con);
+
+ boq = u3x_atom(u3h(d));
+ sep = u3x_atom(u3t(d));
+ vat = u3x_atom(u3t(cam));
+ sam = u3h(pay);
+ }
+
+ return u3qc_hew(boq, sep, vat, sam);
+}
diff --git a/vere/pkg/noun/jets/c/lsh.c b/vere/pkg/noun/jets/c/lsh.c
new file mode 100644
index 0000000..09a97e6
--- /dev/null
+++ b/vere/pkg/noun/jets/c/lsh.c
@@ -0,0 +1,63 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_lsh(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+{
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else if ( !_(u3a_is_cat(b)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w b_w = b;
+ c3_w len_w = u3r_met(a_g, c);
+
+ if ( 0 == len_w ) {
+ return 0;
+ }
+ else if ( (b_w + len_w) < len_w ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, (b_w + len_w));
+
+ u3r_chop(a_g, 0, len_w, b_w, sab_u.buf_w, c);
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+}
+
+u3_noun
+u3wc_lsh(u3_noun cor)
+{
+ u3_atom bloq, step;
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0);
+ u3x_bite(a, &bloq, &step);
+
+ return u3qc_lsh(bloq, step, u3x_atom(b));
+}
+
+u3_noun
+u3kc_lsh(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+{
+ u3_noun d = u3qc_lsh(a, b, c);
+
+ u3z(a); u3z(b); u3z(c);
+ return d;
+}
diff --git a/vere/pkg/noun/jets/c/mas.c b/vere/pkg/noun/jets/c/mas.c
new file mode 100644
index 0000000..b0be6e1
--- /dev/null
+++ b/vere/pkg/noun/jets/c/mas.c
@@ -0,0 +1,48 @@
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_mas(u3_atom a)
+{
+ c3_w b_w;
+
+ if ( c3y == u3a_is_cat(a) ) {
+ b_w = c3_bits_word(a);
+
+ if ( 2 > b_w ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ a &= ~((c3_w)1 << (b_w - 1));
+ a |= ((c3_w)1 << (b_w - 2));
+ return a;
+ }
+ }
+ else {
+ b_w = u3r_met(0, a);
+
+ if ( 64 > b_w ) {
+ c3_d a_d = u3r_chub(0, a);
+ a_d &= ~((c3_d)1 << (b_w - 1));
+ a_d |= ((c3_d)1 << (b_w - 2));
+ return u3i_chub(a_d);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_from(&sab_u, a, 0, b_w - 1);
+
+ b_w -= 2;
+ sab_u.buf_w[(b_w >> 5)] |= ((c3_w)1 << (b_w & 31));
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+}
+
+u3_noun
+u3wc_mas(u3_noun cor)
+{
+ return u3qc_mas(u3x_atom(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/c/met.c b/vere/pkg/noun/jets/c/met.c
new file mode 100644
index 0000000..5f3a6a6
--- /dev/null
+++ b/vere/pkg/noun/jets/c/met.c
@@ -0,0 +1,42 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_met(u3_atom a,
+ u3_atom b)
+ {
+ if ( 0 == b ) {
+ return 0;
+ }
+ else if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);;
+ }
+ else {
+ c3_w met_w = u3r_met(a, b);
+
+ if ( !_(u3a_is_cat(met_w)) ) {
+ return u3i_words(1, &met_w);
+ }
+ else return met_w;
+ }
+ }
+ u3_noun
+ u3wc_met(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(a) && 0 != b) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_met(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/mix.c b/vere/pkg/noun/jets/c/mix.c
new file mode 100644
index 0000000..b497c3f
--- /dev/null
+++ b/vere/pkg/noun/jets/c/mix.c
@@ -0,0 +1,56 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_mix(u3_atom a,
+ u3_atom b)
+ {
+ c3_w lna_w = u3r_met(5, a);
+ c3_w lnb_w = u3r_met(5, b);
+
+ if ( (lna_w == 0) && (lnb_w == 0) ) {
+ return 0;
+ }
+ else {
+ c3_w len_w = c3_max(lna_w, lnb_w);
+ c3_w i_w;
+ u3i_slab sab_u;
+ u3i_slab_from(&sab_u, a, 5, len_w);
+
+ // XX use u3r_chop for XOR?
+ //
+ for ( i_w = 0; i_w < lnb_w; i_w++ ) {
+ sab_u.buf_w[i_w] ^= u3r_word(i_w, b);
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ u3_noun
+ u3wc_mix(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_mix(a, b);
+ }
+ }
+ u3_noun
+ u3kc_mix(u3_atom a,
+ u3_atom b)
+ {
+ u3_noun res = u3qc_mix(a, b);
+ u3z(a); u3z(b);
+ return res;
+ }
diff --git a/vere/pkg/noun/jets/c/mor.c b/vere/pkg/noun/jets/c/mor.c
new file mode 100644
index 0000000..97ba141
--- /dev/null
+++ b/vere/pkg/noun/jets/c/mor.c
@@ -0,0 +1,31 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_mor(u3_noun a,
+ u3_noun b)
+ {
+ c3_w c_w = u3r_mug(u3r_mug(a));
+ c3_w d_w = u3r_mug(u3r_mug(b));
+
+ if ( c_w == d_w ) {
+ return u3qc_dor(a, b);
+ }
+ else return (c_w < d_w) ? c3y : c3n;
+ }
+ u3_noun
+ u3wc_mor(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_mor(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/c/mug.c b/vere/pkg/noun/jets/c/mug.c
new file mode 100644
index 0000000..ec6e483
--- /dev/null
+++ b/vere/pkg/noun/jets/c/mug.c
@@ -0,0 +1,19 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3wc_mug(u3_noun cor)
+ {
+ u3_noun sam;
+
+ if ( u3_none == (sam = u3r_at(u3x_sam, cor)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3r_mug(sam);
+ }
+ }
diff --git a/vere/pkg/noun/jets/c/muk.c b/vere/pkg/noun/jets/c/muk.c
new file mode 100644
index 0000000..0846ed7
--- /dev/null
+++ b/vere/pkg/noun/jets/c/muk.c
@@ -0,0 +1,76 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "murmur3.h"
+
+u3_noun
+u3qc_muk(u3_atom sed,
+ u3_atom len,
+ u3_atom key)
+{
+ if ( c3n == u3a_is_cat(len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_w len_w = (c3_w)len;
+ c3_w key_w = u3r_met(3, key);
+
+ // NB: this condition is implicit in the pad subtraction
+ //
+ if ( key_w > len_w ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_w sed_w = u3r_word(0, sed);
+ c3_o loc_o = c3n;
+ c3_y* key_y = 0;
+ c3_w out_w;
+
+ // if we're hashing more bytes than we have, allocate and copy
+ // to ensure trailing null bytes
+ //
+ if ( len_w > key_w ) {
+ loc_o = c3y;
+ key_y = u3a_calloc(sizeof(c3_y), len_w);
+ u3r_bytes(0, len_w, key_y, key);
+ }
+ else if ( len_w > 0 ) {
+ // XX assumes little-endian
+ //
+ key_y = ( c3y == u3a_is_cat(key) )
+ ? (c3_y*)&key
+ : (c3_y*)((u3a_atom*)u3a_to_ptr(key))->buf_w;
+ }
+
+ MurmurHash3_x86_32(key_y, len_w, sed_w, &out_w);
+
+ if ( c3y == loc_o ) {
+ u3a_free(key_y);
+ }
+
+ return u3i_words(1, &out_w);
+ }
+ }
+}
+
+u3_noun
+u3wc_muk(u3_noun cor)
+{
+ u3_noun sed, len, key;
+ u3x_mean(cor, u3x_sam_2, &sed,
+ u3x_sam_6, &len,
+ u3x_sam_7, &key, 0);
+
+ if ( (c3n == u3ud(sed))
+ || (c3n == u3ud(len))
+ || (c3n == u3ud(key)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qc_muk(sed, len, key);
+ }
+}
diff --git a/vere/pkg/noun/jets/c/peg.c b/vere/pkg/noun/jets/c/peg.c
new file mode 100644
index 0000000..a700752
--- /dev/null
+++ b/vere/pkg/noun/jets/c/peg.c
@@ -0,0 +1,66 @@
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_peg(u3_atom a, u3_atom b)
+{
+ if ( (0 == a) || (0 == b) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( 1 == b ) {
+ return u3k(a);
+ }
+
+ c3_d a_d, b_d;
+ c3_w c_w;
+
+ if ( (c3y == u3a_is_cat(a)) && (c3y == u3a_is_cat(b)) ) {
+ c_w = c3_bits_word(b) - 1;
+ a_d = a;
+ b_d = b;
+ }
+ else {
+ c3_w d_w = u3r_met(0, a);
+ c3_d e_d;
+
+ c_w = u3r_met(0, b) - 1;
+ e_d = (c3_d)c_w + d_w;
+
+ if ( 64 <= e_d ) {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, 0, e_d);
+
+ u3r_chop(0, 0, c_w, 0, sab_u.buf_w, b);
+ u3r_chop(0, 0, d_w, c_w, sab_u.buf_w, a);
+
+ return u3i_slab_moot(&sab_u);
+ }
+
+ a_d = u3r_chub(0, a);
+ b_d = u3r_chub(0, b);
+ }
+
+ b_d &= ((c3_d)1 << c_w) - 1;
+ a_d <<= c_w;
+ a_d ^= b_d;
+
+ return u3i_chub(a_d);
+}
+
+u3_noun
+u3wc_peg(u3_noun cor)
+{
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(a) && b != 1) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qc_peg(a, b);
+ }
+}
diff --git a/vere/pkg/noun/jets/c/po.c b/vere/pkg/noun/jets/c/po.c
new file mode 100644
index 0000000..2fe8858
--- /dev/null
+++ b/vere/pkg/noun/jets/c/po.c
@@ -0,0 +1,1427 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3_po_find_prefix(c3_y one, c3_y two, c3_y three) {
+ switch (one) {
+ case 'b': switch (two) {
+ case 'a': switch (three) {
+ case 'c': return u3nc(0, 238);
+ case 'l': return u3nc(0, 107);
+ case 'n': return u3nc(0, 92);
+ case 'r': return u3nc(0, 183);
+ case 't': return u3nc(0, 172);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'c': return u3nc(0, 56);
+ case 'd': return u3nc(0, 106);
+ case 'l': return u3nc(0, 144);
+ case 'n': return u3nc(0, 2);
+ case 's': return u3nc(0, 60);
+ case 't': return u3nc(0, 182);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'l': return u3nc(0, 45);
+ case 'n': return u3nc(0, 244);
+ case 'r': return u3nc(0, 188);
+ case 's': return u3nc(0, 171);
+ case 't': return u3nc(0, 98);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'd': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 181);
+ case 'c': return u3nc(0, 117);
+ case 'l': return u3nc(0, 37);
+ case 'n': return u3nc(0, 234);
+ case 'p': return u3nc(0, 66);
+ case 'r': return u3nc(0, 23);
+ case 's': return u3nc(0, 61);
+ case 't': return u3nc(0, 215);
+ case 'v': return u3nc(0, 105);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'b': return u3nc(0, 179);
+ case 'f': return u3nc(0, 57);
+ case 'g': return u3nc(0, 193);
+ case 'l': return u3nc(0, 49);
+ case 'n': return u3nc(0, 217);
+ case 'r': return u3nc(0, 11);
+ case 's': return u3nc(0, 129);
+ case 'v': return u3nc(0, 116);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 146);
+ case 'l': return u3nc(0, 102);
+ case 'n': return u3nc(0, 233);
+ case 'p': return u3nc(0, 18);
+ case 'r': return u3nc(0, 24);
+ case 's': return u3nc(0, 187);
+ case 't': return u3nc(0, 47);
+ case 'v': return u3nc(0, 236);
+ case 'z': return u3nc(0, 0);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'f': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 120);
+ case 'd': return u3nc(0, 206);
+ case 'l': return u3nc(0, 152);
+ case 'm': return u3nc(0, 214);
+ case 'n': return u3nc(0, 158);
+ case 's': return u3nc(0, 195);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'd': return u3nc(0, 8);
+ case 'g': return u3nc(0, 138);
+ case 'l': return u3nc(0, 194);
+ case 'n': return u3nc(0, 90);
+ case 'p': return u3nc(0, 255);
+ case 'r': return u3nc(0, 169);
+ case 't': return u3nc(0, 226);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'd': return u3nc(0, 247);
+ case 'g': return u3nc(0, 20);
+ case 'l': return u3nc(0, 27);
+ case 'n': return u3nc(0, 91);
+ case 'p': return u3nc(0, 213);
+ case 'r': return u3nc(0, 50);
+ case 's': return u3nc(0, 46);
+ case 't': return u3nc(0, 221);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'h': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 209);
+ case 'c': return u3nc(0, 174);
+ case 'd': return u3nc(0, 145);
+ case 'l': return u3nc(0, 203);
+ case 'n': return u3nc(0, 41);
+ case 'p': return u3nc(0, 156);
+ case 'r': return u3nc(0, 198);
+ case 's': return u3nc(0, 170);
+ case 't': return u3nc(0, 218);
+ case 'v': return u3nc(0, 176);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'd': return u3nc(0, 7);
+ case 'l': return u3nc(0, 190);
+ case 'n': return u3nc(0, 200);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'b': return u3nc(0, 197);
+ case 'c': return u3nc(0, 223);
+ case 'd': return u3nc(0, 26);
+ case 'l': return u3nc(0, 32);
+ case 'p': return u3nc(0, 22);
+ case 's': return u3nc(0, 180);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'l': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 161);
+ case 'c': return u3nc(0, 34);
+ case 'd': return u3nc(0, 235);
+ case 'g': return u3nc(0, 205);
+ case 'n': return u3nc(0, 232);
+ case 'p': return u3nc(0, 240);
+ case 'r': return u3nc(0, 225);
+ case 's': return u3nc(0, 128);
+ case 't': return u3nc(0, 134);
+ case 'v': return u3nc(0, 252);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'b': return u3nc(0, 39);
+ case 'd': return u3nc(0, 21);
+ case 'g': return u3nc(0, 111);
+ case 'n': return u3nc(0, 178);
+ case 's': return u3nc(0, 9);
+ case 't': return u3nc(0, 5);
+ case 'v': return u3nc(0, 36);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 69);
+ case 'd': return u3nc(0, 186);
+ case 'm': return u3nc(0, 166);
+ case 'n': return u3nc(0, 135);
+ case 'p': return u3nc(0, 63);
+ case 'r': return u3nc(0, 25);
+ case 's': return u3nc(0, 48);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'm': switch (two) {
+ case 'a': switch (three) {
+ case 'c': return u3nc(0, 191);
+ case 'g': return u3nc(0, 103);
+ case 'l': return u3nc(0, 110);
+ case 'p': return u3nc(0, 130);
+ case 'r': return u3nc(0, 1);
+ case 's': return u3nc(0, 202);
+ case 't': return u3nc(0, 253);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'c': return u3nc(0, 157);
+ case 'd': return u3nc(0, 62);
+ case 'g': return u3nc(0, 199);
+ case 'l': return u3nc(0, 212);
+ case 'n': return u3nc(0, 79);
+ case 'p': return u3nc(0, 254);
+ case 'r': return u3nc(0, 31);
+ case 's': return u3nc(0, 126);
+ case 't': return u3nc(0, 196);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 148);
+ case 'd': return u3nc(0, 19);
+ case 'g': return u3nc(0, 162);
+ case 'l': return u3nc(0, 67);
+ case 'n': return u3nc(0, 122);
+ case 'p': return u3nc(0, 208);
+ case 'r': return u3nc(0, 93);
+ case 's': return u3nc(0, 231);
+ case 't': return u3nc(0, 82);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'n': switch (two) {
+ case 'a': switch (three) {
+ case 'c': return u3nc(0, 219);
+ case 'l': return u3nc(0, 230);
+ case 'm': return u3nc(0, 243);
+ case 'p': return u3nc(0, 87);
+ case 'r': return u3nc(0, 65);
+ case 't': return u3nc(0, 77);
+ case 'v': return u3nc(0, 137);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'b': return u3nc(0, 140);
+ case 'd': return u3nc(0, 72);
+ case 'l': return u3nc(0, 210);
+ case 'm': return u3nc(0, 224);
+ case 's': return u3nc(0, 124);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 250);
+ case 'd': return u3nc(0, 136);
+ case 'l': return u3nc(0, 216);
+ case 'm': return u3nc(0, 139);
+ case 'p': return u3nc(0, 88);
+ case 'r': return u3nc(0, 97);
+ case 's': return u3nc(0, 211);
+ case 'v': return u3nc(0, 70);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'p': switch (two) {
+ case 'a': switch (three) {
+ case 'c': return u3nc(0, 149);
+ case 'd': return u3nc(0, 114);
+ case 'g': return u3nc(0, 141);
+ case 'l': return u3nc(0, 127);
+ case 'n': return u3nc(0, 78);
+ case 'r': return u3nc(0, 185);
+ case 's': return u3nc(0, 33);
+ case 't': return u3nc(0, 159);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'c': return u3nc(0, 104);
+ case 'd': return u3nc(0, 43);
+ case 'l': return u3nc(0, 51);
+ case 'n': return u3nc(0, 165);
+ case 't': return u3nc(0, 242);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 173);
+ case 'd': return u3nc(0, 81);
+ case 'l': return u3nc(0, 239);
+ case 'n': return u3nc(0, 248);
+ case 's': return u3nc(0, 86);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'r': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 131);
+ case 'c': return u3nc(0, 184);
+ case 'd': return u3nc(0, 201);
+ case 'g': return u3nc(0, 204);
+ case 'l': return u3nc(0, 143);
+ case 'm': return u3nc(0, 52);
+ case 'n': return u3nc(0, 123);
+ case 'p': return u3nc(0, 228);
+ case 'v': return u3nc(0, 150);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'b': return u3nc(0, 222);
+ case 'c': return u3nc(0, 167);
+ case 'd': return u3nc(0, 147);
+ case 'g': return u3nc(0, 16);
+ case 'l': return u3nc(0, 64);
+ case 'n': return u3nc(0, 28);
+ case 'p': return u3nc(0, 151);
+ case 's': return u3nc(0, 220);
+ case 't': return u3nc(0, 80);
+ case 'v': return u3nc(0, 237);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 58);
+ case 'l': return u3nc(0, 133);
+ case 'n': return u3nc(0, 96);
+ case 'p': return u3nc(0, 75);
+ case 's': return u3nc(0, 245);
+ case 'v': return u3nc(0, 35);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 's': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 13);
+ case 'l': return u3nc(0, 115);
+ case 'm': return u3nc(0, 4);
+ case 'n': return u3nc(0, 68);
+ case 'p': return u3nc(0, 177);
+ case 'r': return u3nc(0, 229);
+ case 't': return u3nc(0, 38);
+ case 'v': return u3nc(0, 85);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'b': return u3nc(0, 15);
+ case 'c': return u3nc(0, 74);
+ case 'd': return u3nc(0, 119);
+ case 'g': return u3nc(0, 6);
+ case 'l': return u3nc(0, 30);
+ case 'm': return u3nc(0, 163);
+ case 'p': return u3nc(0, 95);
+ case 't': return u3nc(0, 71);
+ case 'v': return u3nc(0, 112);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'c': return u3nc(0, 100);
+ case 'g': return u3nc(0, 10);
+ case 'l': return u3nc(0, 17);
+ case 'm': return u3nc(0, 89);
+ case 'n': return u3nc(0, 164);
+ case 'p': return u3nc(0, 142);
+ case 'r': return u3nc(0, 251);
+ case 'v': return u3nc(0, 249);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 't': switch (two) {
+ case 'a': switch (three) {
+ case 'b': return u3nc(0, 40);
+ case 'c': return u3nc(0, 160);
+ case 'd': return u3nc(0, 55);
+ case 'g': return u3nc(0, 113);
+ case 'l': return u3nc(0, 241);
+ case 'm': return u3nc(0, 83);
+ case 'n': return u3nc(0, 118);
+ case 'p': return u3nc(0, 168);
+ case 'r': return u3nc(0, 121);
+ case 's': return u3nc(0, 109);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'c': return u3nc(0, 42);
+ case 'd': return u3nc(0, 175);
+ case 'l': return u3nc(0, 154);
+ case 'm': return u3nc(0, 108);
+ case 'n': return u3nc(0, 155);
+ case 'p': return u3nc(0, 73);
+ case 'r': return u3nc(0, 53);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'b': return u3nc(0, 132);
+ case 'c': return u3nc(0, 189);
+ case 'd': return u3nc(0, 153);
+ case 'g': return u3nc(0, 29);
+ case 'l': return u3nc(0, 84);
+ case 'm': return u3nc(0, 192);
+ case 'n': return u3nc(0, 246);
+ case 'p': return u3nc(0, 207);
+ case 'r': return u3nc(0, 44);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'w': switch (two) {
+ case 'a': switch (three) {
+ case 'c': return u3nc(0, 12);
+ case 'l': return u3nc(0, 227);
+ case 'n': return u3nc(0, 3);
+ case 't': return u3nc(0, 101);
+ default: return 0;
+ }
+ case 'i': switch (three) {
+ case 'c': return u3nc(0, 99);
+ case 'd': return u3nc(0, 59);
+ case 'n': return u3nc(0, 54);
+ case 's': return u3nc(0, 14);
+ case 't': return u3nc(0, 76);
+ default: return 0;
+ }
+ case 'o': switch (three) {
+ case 'l': return u3nc(0, 125);
+ case 'r': return u3nc(0, 94);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ default: return 0;
+ }
+}
+
+void
+u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c)
+{
+ switch (id) {
+ case 0: *a = 'd'; *b = 'o'; *c = 'z'; break;
+ case 1: *a = 'm'; *b = 'a'; *c = 'r'; break;
+ case 2: *a = 'b'; *b = 'i'; *c = 'n'; break;
+ case 3: *a = 'w'; *b = 'a'; *c = 'n'; break;
+ case 4: *a = 's'; *b = 'a'; *c = 'm'; break;
+ case 5: *a = 'l'; *b = 'i'; *c = 't'; break;
+ case 6: *a = 's'; *b = 'i'; *c = 'g'; break;
+ case 7: *a = 'h'; *b = 'i'; *c = 'd'; break;
+ case 8: *a = 'f'; *b = 'i'; *c = 'd'; break;
+ case 9: *a = 'l'; *b = 'i'; *c = 's'; break;
+ case 10: *a = 's'; *b = 'o'; *c = 'g'; break;
+ case 11: *a = 'd'; *b = 'i'; *c = 'r'; break;
+ case 12: *a = 'w'; *b = 'a'; *c = 'c'; break;
+ case 13: *a = 's'; *b = 'a'; *c = 'b'; break;
+ case 14: *a = 'w'; *b = 'i'; *c = 's'; break;
+ case 15: *a = 's'; *b = 'i'; *c = 'b'; break;
+ case 16: *a = 'r'; *b = 'i'; *c = 'g'; break;
+ case 17: *a = 's'; *b = 'o'; *c = 'l'; break;
+ case 18: *a = 'd'; *b = 'o'; *c = 'p'; break;
+ case 19: *a = 'm'; *b = 'o'; *c = 'd'; break;
+ case 20: *a = 'f'; *b = 'o'; *c = 'g'; break;
+ case 21: *a = 'l'; *b = 'i'; *c = 'd'; break;
+ case 22: *a = 'h'; *b = 'o'; *c = 'p'; break;
+ case 23: *a = 'd'; *b = 'a'; *c = 'r'; break;
+ case 24: *a = 'd'; *b = 'o'; *c = 'r'; break;
+ case 25: *a = 'l'; *b = 'o'; *c = 'r'; break;
+ case 26: *a = 'h'; *b = 'o'; *c = 'd'; break;
+ case 27: *a = 'f'; *b = 'o'; *c = 'l'; break;
+ case 28: *a = 'r'; *b = 'i'; *c = 'n'; break;
+ case 29: *a = 't'; *b = 'o'; *c = 'g'; break;
+ case 30: *a = 's'; *b = 'i'; *c = 'l'; break;
+ case 31: *a = 'm'; *b = 'i'; *c = 'r'; break;
+ case 32: *a = 'h'; *b = 'o'; *c = 'l'; break;
+ case 33: *a = 'p'; *b = 'a'; *c = 's'; break;
+ case 34: *a = 'l'; *b = 'a'; *c = 'c'; break;
+ case 35: *a = 'r'; *b = 'o'; *c = 'v'; break;
+ case 36: *a = 'l'; *b = 'i'; *c = 'v'; break;
+ case 37: *a = 'd'; *b = 'a'; *c = 'l'; break;
+ case 38: *a = 's'; *b = 'a'; *c = 't'; break;
+ case 39: *a = 'l'; *b = 'i'; *c = 'b'; break;
+ case 40: *a = 't'; *b = 'a'; *c = 'b'; break;
+ case 41: *a = 'h'; *b = 'a'; *c = 'n'; break;
+ case 42: *a = 't'; *b = 'i'; *c = 'c'; break;
+ case 43: *a = 'p'; *b = 'i'; *c = 'd'; break;
+ case 44: *a = 't'; *b = 'o'; *c = 'r'; break;
+ case 45: *a = 'b'; *b = 'o'; *c = 'l'; break;
+ case 46: *a = 'f'; *b = 'o'; *c = 's'; break;
+ case 47: *a = 'd'; *b = 'o'; *c = 't'; break;
+ case 48: *a = 'l'; *b = 'o'; *c = 's'; break;
+ case 49: *a = 'd'; *b = 'i'; *c = 'l'; break;
+ case 50: *a = 'f'; *b = 'o'; *c = 'r'; break;
+ case 51: *a = 'p'; *b = 'i'; *c = 'l'; break;
+ case 52: *a = 'r'; *b = 'a'; *c = 'm'; break;
+ case 53: *a = 't'; *b = 'i'; *c = 'r'; break;
+ case 54: *a = 'w'; *b = 'i'; *c = 'n'; break;
+ case 55: *a = 't'; *b = 'a'; *c = 'd'; break;
+ case 56: *a = 'b'; *b = 'i'; *c = 'c'; break;
+ case 57: *a = 'd'; *b = 'i'; *c = 'f'; break;
+ case 58: *a = 'r'; *b = 'o'; *c = 'c'; break;
+ case 59: *a = 'w'; *b = 'i'; *c = 'd'; break;
+ case 60: *a = 'b'; *b = 'i'; *c = 's'; break;
+ case 61: *a = 'd'; *b = 'a'; *c = 's'; break;
+ case 62: *a = 'm'; *b = 'i'; *c = 'd'; break;
+ case 63: *a = 'l'; *b = 'o'; *c = 'p'; break;
+ case 64: *a = 'r'; *b = 'i'; *c = 'l'; break;
+ case 65: *a = 'n'; *b = 'a'; *c = 'r'; break;
+ case 66: *a = 'd'; *b = 'a'; *c = 'p'; break;
+ case 67: *a = 'm'; *b = 'o'; *c = 'l'; break;
+ case 68: *a = 's'; *b = 'a'; *c = 'n'; break;
+ case 69: *a = 'l'; *b = 'o'; *c = 'c'; break;
+ case 70: *a = 'n'; *b = 'o'; *c = 'v'; break;
+ case 71: *a = 's'; *b = 'i'; *c = 't'; break;
+ case 72: *a = 'n'; *b = 'i'; *c = 'd'; break;
+ case 73: *a = 't'; *b = 'i'; *c = 'p'; break;
+ case 74: *a = 's'; *b = 'i'; *c = 'c'; break;
+ case 75: *a = 'r'; *b = 'o'; *c = 'p'; break;
+ case 76: *a = 'w'; *b = 'i'; *c = 't'; break;
+ case 77: *a = 'n'; *b = 'a'; *c = 't'; break;
+ case 78: *a = 'p'; *b = 'a'; *c = 'n'; break;
+ case 79: *a = 'm'; *b = 'i'; *c = 'n'; break;
+ case 80: *a = 'r'; *b = 'i'; *c = 't'; break;
+ case 81: *a = 'p'; *b = 'o'; *c = 'd'; break;
+ case 82: *a = 'm'; *b = 'o'; *c = 't'; break;
+ case 83: *a = 't'; *b = 'a'; *c = 'm'; break;
+ case 84: *a = 't'; *b = 'o'; *c = 'l'; break;
+ case 85: *a = 's'; *b = 'a'; *c = 'v'; break;
+ case 86: *a = 'p'; *b = 'o'; *c = 's'; break;
+ case 87: *a = 'n'; *b = 'a'; *c = 'p'; break;
+ case 88: *a = 'n'; *b = 'o'; *c = 'p'; break;
+ case 89: *a = 's'; *b = 'o'; *c = 'm'; break;
+ case 90: *a = 'f'; *b = 'i'; *c = 'n'; break;
+ case 91: *a = 'f'; *b = 'o'; *c = 'n'; break;
+ case 92: *a = 'b'; *b = 'a'; *c = 'n'; break;
+ case 93: *a = 'm'; *b = 'o'; *c = 'r'; break;
+ case 94: *a = 'w'; *b = 'o'; *c = 'r'; break;
+ case 95: *a = 's'; *b = 'i'; *c = 'p'; break;
+ case 96: *a = 'r'; *b = 'o'; *c = 'n'; break;
+ case 97: *a = 'n'; *b = 'o'; *c = 'r'; break;
+ case 98: *a = 'b'; *b = 'o'; *c = 't'; break;
+ case 99: *a = 'w'; *b = 'i'; *c = 'c'; break;
+ case 100: *a = 's'; *b = 'o'; *c = 'c'; break;
+ case 101: *a = 'w'; *b = 'a'; *c = 't'; break;
+ case 102: *a = 'd'; *b = 'o'; *c = 'l'; break;
+ case 103: *a = 'm'; *b = 'a'; *c = 'g'; break;
+ case 104: *a = 'p'; *b = 'i'; *c = 'c'; break;
+ case 105: *a = 'd'; *b = 'a'; *c = 'v'; break;
+ case 106: *a = 'b'; *b = 'i'; *c = 'd'; break;
+ case 107: *a = 'b'; *b = 'a'; *c = 'l'; break;
+ case 108: *a = 't'; *b = 'i'; *c = 'm'; break;
+ case 109: *a = 't'; *b = 'a'; *c = 's'; break;
+ case 110: *a = 'm'; *b = 'a'; *c = 'l'; break;
+ case 111: *a = 'l'; *b = 'i'; *c = 'g'; break;
+ case 112: *a = 's'; *b = 'i'; *c = 'v'; break;
+ case 113: *a = 't'; *b = 'a'; *c = 'g'; break;
+ case 114: *a = 'p'; *b = 'a'; *c = 'd'; break;
+ case 115: *a = 's'; *b = 'a'; *c = 'l'; break;
+ case 116: *a = 'd'; *b = 'i'; *c = 'v'; break;
+ case 117: *a = 'd'; *b = 'a'; *c = 'c'; break;
+ case 118: *a = 't'; *b = 'a'; *c = 'n'; break;
+ case 119: *a = 's'; *b = 'i'; *c = 'd'; break;
+ case 120: *a = 'f'; *b = 'a'; *c = 'b'; break;
+ case 121: *a = 't'; *b = 'a'; *c = 'r'; break;
+ case 122: *a = 'm'; *b = 'o'; *c = 'n'; break;
+ case 123: *a = 'r'; *b = 'a'; *c = 'n'; break;
+ case 124: *a = 'n'; *b = 'i'; *c = 's'; break;
+ case 125: *a = 'w'; *b = 'o'; *c = 'l'; break;
+ case 126: *a = 'm'; *b = 'i'; *c = 's'; break;
+ case 127: *a = 'p'; *b = 'a'; *c = 'l'; break;
+ case 128: *a = 'l'; *b = 'a'; *c = 's'; break;
+ case 129: *a = 'd'; *b = 'i'; *c = 's'; break;
+ case 130: *a = 'm'; *b = 'a'; *c = 'p'; break;
+ case 131: *a = 'r'; *b = 'a'; *c = 'b'; break;
+ case 132: *a = 't'; *b = 'o'; *c = 'b'; break;
+ case 133: *a = 'r'; *b = 'o'; *c = 'l'; break;
+ case 134: *a = 'l'; *b = 'a'; *c = 't'; break;
+ case 135: *a = 'l'; *b = 'o'; *c = 'n'; break;
+ case 136: *a = 'n'; *b = 'o'; *c = 'd'; break;
+ case 137: *a = 'n'; *b = 'a'; *c = 'v'; break;
+ case 138: *a = 'f'; *b = 'i'; *c = 'g'; break;
+ case 139: *a = 'n'; *b = 'o'; *c = 'm'; break;
+ case 140: *a = 'n'; *b = 'i'; *c = 'b'; break;
+ case 141: *a = 'p'; *b = 'a'; *c = 'g'; break;
+ case 142: *a = 's'; *b = 'o'; *c = 'p'; break;
+ case 143: *a = 'r'; *b = 'a'; *c = 'l'; break;
+ case 144: *a = 'b'; *b = 'i'; *c = 'l'; break;
+ case 145: *a = 'h'; *b = 'a'; *c = 'd'; break;
+ case 146: *a = 'd'; *b = 'o'; *c = 'c'; break;
+ case 147: *a = 'r'; *b = 'i'; *c = 'd'; break;
+ case 148: *a = 'm'; *b = 'o'; *c = 'c'; break;
+ case 149: *a = 'p'; *b = 'a'; *c = 'c'; break;
+ case 150: *a = 'r'; *b = 'a'; *c = 'v'; break;
+ case 151: *a = 'r'; *b = 'i'; *c = 'p'; break;
+ case 152: *a = 'f'; *b = 'a'; *c = 'l'; break;
+ case 153: *a = 't'; *b = 'o'; *c = 'd'; break;
+ case 154: *a = 't'; *b = 'i'; *c = 'l'; break;
+ case 155: *a = 't'; *b = 'i'; *c = 'n'; break;
+ case 156: *a = 'h'; *b = 'a'; *c = 'p'; break;
+ case 157: *a = 'm'; *b = 'i'; *c = 'c'; break;
+ case 158: *a = 'f'; *b = 'a'; *c = 'n'; break;
+ case 159: *a = 'p'; *b = 'a'; *c = 't'; break;
+ case 160: *a = 't'; *b = 'a'; *c = 'c'; break;
+ case 161: *a = 'l'; *b = 'a'; *c = 'b'; break;
+ case 162: *a = 'm'; *b = 'o'; *c = 'g'; break;
+ case 163: *a = 's'; *b = 'i'; *c = 'm'; break;
+ case 164: *a = 's'; *b = 'o'; *c = 'n'; break;
+ case 165: *a = 'p'; *b = 'i'; *c = 'n'; break;
+ case 166: *a = 'l'; *b = 'o'; *c = 'm'; break;
+ case 167: *a = 'r'; *b = 'i'; *c = 'c'; break;
+ case 168: *a = 't'; *b = 'a'; *c = 'p'; break;
+ case 169: *a = 'f'; *b = 'i'; *c = 'r'; break;
+ case 170: *a = 'h'; *b = 'a'; *c = 's'; break;
+ case 171: *a = 'b'; *b = 'o'; *c = 's'; break;
+ case 172: *a = 'b'; *b = 'a'; *c = 't'; break;
+ case 173: *a = 'p'; *b = 'o'; *c = 'c'; break;
+ case 174: *a = 'h'; *b = 'a'; *c = 'c'; break;
+ case 175: *a = 't'; *b = 'i'; *c = 'd'; break;
+ case 176: *a = 'h'; *b = 'a'; *c = 'v'; break;
+ case 177: *a = 's'; *b = 'a'; *c = 'p'; break;
+ case 178: *a = 'l'; *b = 'i'; *c = 'n'; break;
+ case 179: *a = 'd'; *b = 'i'; *c = 'b'; break;
+ case 180: *a = 'h'; *b = 'o'; *c = 's'; break;
+ case 181: *a = 'd'; *b = 'a'; *c = 'b'; break;
+ case 182: *a = 'b'; *b = 'i'; *c = 't'; break;
+ case 183: *a = 'b'; *b = 'a'; *c = 'r'; break;
+ case 184: *a = 'r'; *b = 'a'; *c = 'c'; break;
+ case 185: *a = 'p'; *b = 'a'; *c = 'r'; break;
+ case 186: *a = 'l'; *b = 'o'; *c = 'd'; break;
+ case 187: *a = 'd'; *b = 'o'; *c = 's'; break;
+ case 188: *a = 'b'; *b = 'o'; *c = 'r'; break;
+ case 189: *a = 't'; *b = 'o'; *c = 'c'; break;
+ case 190: *a = 'h'; *b = 'i'; *c = 'l'; break;
+ case 191: *a = 'm'; *b = 'a'; *c = 'c'; break;
+ case 192: *a = 't'; *b = 'o'; *c = 'm'; break;
+ case 193: *a = 'd'; *b = 'i'; *c = 'g'; break;
+ case 194: *a = 'f'; *b = 'i'; *c = 'l'; break;
+ case 195: *a = 'f'; *b = 'a'; *c = 's'; break;
+ case 196: *a = 'm'; *b = 'i'; *c = 't'; break;
+ case 197: *a = 'h'; *b = 'o'; *c = 'b'; break;
+ case 198: *a = 'h'; *b = 'a'; *c = 'r'; break;
+ case 199: *a = 'm'; *b = 'i'; *c = 'g'; break;
+ case 200: *a = 'h'; *b = 'i'; *c = 'n'; break;
+ case 201: *a = 'r'; *b = 'a'; *c = 'd'; break;
+ case 202: *a = 'm'; *b = 'a'; *c = 's'; break;
+ case 203: *a = 'h'; *b = 'a'; *c = 'l'; break;
+ case 204: *a = 'r'; *b = 'a'; *c = 'g'; break;
+ case 205: *a = 'l'; *b = 'a'; *c = 'g'; break;
+ case 206: *a = 'f'; *b = 'a'; *c = 'd'; break;
+ case 207: *a = 't'; *b = 'o'; *c = 'p'; break;
+ case 208: *a = 'm'; *b = 'o'; *c = 'p'; break;
+ case 209: *a = 'h'; *b = 'a'; *c = 'b'; break;
+ case 210: *a = 'n'; *b = 'i'; *c = 'l'; break;
+ case 211: *a = 'n'; *b = 'o'; *c = 's'; break;
+ case 212: *a = 'm'; *b = 'i'; *c = 'l'; break;
+ case 213: *a = 'f'; *b = 'o'; *c = 'p'; break;
+ case 214: *a = 'f'; *b = 'a'; *c = 'm'; break;
+ case 215: *a = 'd'; *b = 'a'; *c = 't'; break;
+ case 216: *a = 'n'; *b = 'o'; *c = 'l'; break;
+ case 217: *a = 'd'; *b = 'i'; *c = 'n'; break;
+ case 218: *a = 'h'; *b = 'a'; *c = 't'; break;
+ case 219: *a = 'n'; *b = 'a'; *c = 'c'; break;
+ case 220: *a = 'r'; *b = 'i'; *c = 's'; break;
+ case 221: *a = 'f'; *b = 'o'; *c = 't'; break;
+ case 222: *a = 'r'; *b = 'i'; *c = 'b'; break;
+ case 223: *a = 'h'; *b = 'o'; *c = 'c'; break;
+ case 224: *a = 'n'; *b = 'i'; *c = 'm'; break;
+ case 225: *a = 'l'; *b = 'a'; *c = 'r'; break;
+ case 226: *a = 'f'; *b = 'i'; *c = 't'; break;
+ case 227: *a = 'w'; *b = 'a'; *c = 'l'; break;
+ case 228: *a = 'r'; *b = 'a'; *c = 'p'; break;
+ case 229: *a = 's'; *b = 'a'; *c = 'r'; break;
+ case 230: *a = 'n'; *b = 'a'; *c = 'l'; break;
+ case 231: *a = 'm'; *b = 'o'; *c = 's'; break;
+ case 232: *a = 'l'; *b = 'a'; *c = 'n'; break;
+ case 233: *a = 'd'; *b = 'o'; *c = 'n'; break;
+ case 234: *a = 'd'; *b = 'a'; *c = 'n'; break;
+ case 235: *a = 'l'; *b = 'a'; *c = 'd'; break;
+ case 236: *a = 'd'; *b = 'o'; *c = 'v'; break;
+ case 237: *a = 'r'; *b = 'i'; *c = 'v'; break;
+ case 238: *a = 'b'; *b = 'a'; *c = 'c'; break;
+ case 239: *a = 'p'; *b = 'o'; *c = 'l'; break;
+ case 240: *a = 'l'; *b = 'a'; *c = 'p'; break;
+ case 241: *a = 't'; *b = 'a'; *c = 'l'; break;
+ case 242: *a = 'p'; *b = 'i'; *c = 't'; break;
+ case 243: *a = 'n'; *b = 'a'; *c = 'm'; break;
+ case 244: *a = 'b'; *b = 'o'; *c = 'n'; break;
+ case 245: *a = 'r'; *b = 'o'; *c = 's'; break;
+ case 246: *a = 't'; *b = 'o'; *c = 'n'; break;
+ case 247: *a = 'f'; *b = 'o'; *c = 'd'; break;
+ case 248: *a = 'p'; *b = 'o'; *c = 'n'; break;
+ case 249: *a = 's'; *b = 'o'; *c = 'v'; break;
+ case 250: *a = 'n'; *b = 'o'; *c = 'c'; break;
+ case 251: *a = 's'; *b = 'o'; *c = 'r'; break;
+ case 252: *a = 'l'; *b = 'a'; *c = 'v'; break;
+ case 253: *a = 'm'; *b = 'a'; *c = 't'; break;
+ case 254: *a = 'm'; *b = 'i'; *c = 'p'; break;
+ case 255: *a = 'f'; *b = 'i'; *c = 'p'; break;
+ default: u3m_bail(c3__exit);
+ }
+}
+
+u3_noun
+u3_po_find_suffix(c3_y one, c3_y two, c3_y three) {
+ switch (one) {
+ case 'b': switch (two) {
+ case 'e': switch (three) {
+ case 'c': return u3nc(0, 238);
+ case 'l': return u3nc(0, 107);
+ case 'n': return u3nc(0, 92);
+ case 'p': return u3nc(0, 183);
+ case 'r': return u3nc(0, 172);
+ case 's': return u3nc(0, 56);
+ case 't': return u3nc(0, 106);
+ case 'x': return u3nc(0, 144);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'd': return u3nc(0, 2);
+ case 'r': return u3nc(0, 60);
+ case 's': return u3nc(0, 182);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'l': return u3nc(0, 176);
+ case 'n': return u3nc(0, 45);
+ case 'r': return u3nc(0, 244);
+ case 't': return u3nc(0, 188);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'd': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 171);
+ case 'c': return u3nc(0, 98);
+ case 'f': return u3nc(0, 181);
+ case 'g': return u3nc(0, 117);
+ case 'l': return u3nc(0, 37);
+ case 'm': return u3nc(0, 234);
+ case 'n': return u3nc(0, 66);
+ case 'p': return u3nc(0, 23);
+ case 'r': return u3nc(0, 61);
+ case 's': return u3nc(0, 215);
+ case 't': return u3nc(0, 105);
+ case 'v': return u3nc(0, 179);
+ case 'x': return u3nc(0, 57);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'c': return u3nc(0, 193);
+ case 'l': return u3nc(0, 49);
+ case 'n': return u3nc(0, 217);
+ case 'r': return u3nc(0, 11);
+ case 's': return u3nc(0, 129);
+ case 't': return u3nc(0, 116);
+ case 'x': return u3nc(0, 146);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'l': return u3nc(0, 102);
+ case 'n': return u3nc(0, 233);
+ case 'r': return u3nc(0, 18);
+ case 's': return u3nc(0, 24);
+ case 't': return u3nc(0, 187);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'f': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 47);
+ case 'd': return u3nc(0, 236);
+ case 'l': return u3nc(0, 120);
+ case 'n': return u3nc(0, 206);
+ case 'p': return u3nc(0, 152);
+ case 'r': return u3nc(0, 158);
+ case 's': return u3nc(0, 255);
+ case 't': return u3nc(0, 214);
+ case 'x': return u3nc(0, 195);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'l': return u3nc(0, 8);
+ case 'n': return u3nc(0, 138);
+ case 'r': return u3nc(0, 194);
+ case 's': return u3nc(0, 90);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'l': return u3nc(0, 169);
+ case 'n': return u3nc(0, 226);
+ case 'r': return u3nc(0, 247);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'h': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 20);
+ case 'c': return u3nc(0, 27);
+ case 'p': return u3nc(0, 91);
+ case 's': return u3nc(0, 213);
+ case 't': return u3nc(0, 50);
+ case 'x': return u3nc(0, 46);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'l': return u3nc(0, 221);
+ case 's': return u3nc(0, 209);
+ case 't': return u3nc(0, 174);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'l': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 145);
+ case 'c': return u3nc(0, 203);
+ case 'd': return u3nc(0, 41);
+ case 'g': return u3nc(0, 156);
+ case 'n': return u3nc(0, 198);
+ case 'p': return u3nc(0, 170);
+ case 'r': return u3nc(0, 218);
+ case 't': return u3nc(0, 7);
+ case 'v': return u3nc(0, 190);
+ case 'x': return u3nc(0, 200);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'c': return u3nc(0, 197);
+ case 'd': return u3nc(0, 223);
+ case 'g': return u3nc(0, 26);
+ case 'n': return u3nc(0, 32);
+ case 'p': return u3nc(0, 22);
+ case 'r': return u3nc(0, 180);
+ case 's': return u3nc(0, 161);
+ case 't': return u3nc(0, 34);
+ case 'x': return u3nc(0, 235);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'd': return u3nc(0, 205);
+ case 'n': return u3nc(0, 232);
+ case 'r': return u3nc(0, 240);
+ case 's': return u3nc(0, 225);
+ case 't': return u3nc(0, 128);
+ case 'x': return u3nc(0, 134);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'm': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 114);
+ case 'c': return u3nc(0, 141);
+ case 'd': return u3nc(0, 127);
+ case 'g': return u3nc(0, 78);
+ case 'l': return u3nc(0, 185);
+ case 'p': return u3nc(0, 33);
+ case 'r': return u3nc(0, 159);
+ case 's': return u3nc(0, 104);
+ case 't': return u3nc(0, 43);
+ case 'v': return u3nc(0, 51);
+ case 'x': return u3nc(0, 165);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'd': return u3nc(0, 242);
+ case 'g': return u3nc(0, 173);
+ case 'l': return u3nc(0, 81);
+ case 'n': return u3nc(0, 239);
+ case 'r': return u3nc(0, 248);
+ case 's': return u3nc(0, 93);
+ case 't': return u3nc(0, 86);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'l': return u3nc(0, 191);
+ case 'n': return u3nc(0, 103);
+ case 'r': return u3nc(0, 110);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'n': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 130);
+ case 'c': return u3nc(0, 1);
+ case 'd': return u3nc(0, 202);
+ case 'l': return u3nc(0, 253);
+ case 'm': return u3nc(0, 157);
+ case 'p': return u3nc(0, 62);
+ case 'r': return u3nc(0, 199);
+ case 's': return u3nc(0, 212);
+ case 't': return u3nc(0, 79);
+ case 'v': return u3nc(0, 254);
+ case 'x': return u3nc(0, 31);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'b': return u3nc(0, 126);
+ case 'l': return u3nc(0, 196);
+ case 'm': return u3nc(0, 148);
+ case 'p': return u3nc(0, 19);
+ case 's': return u3nc(0, 162);
+ case 't': return u3nc(0, 67);
+ case 'x': return u3nc(0, 122);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'd': return u3nc(0, 208);
+ case 'l': return u3nc(0, 231);
+ case 'm': return u3nc(0, 82);
+ case 'r': return u3nc(0, 219);
+ case 's': return u3nc(0, 230);
+ case 't': return u3nc(0, 243);
+ case 'x': return u3nc(0, 87);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'p': switch (two) {
+ case 'e': switch (three) {
+ case 'c': return u3nc(0, 252);
+ case 'd': return u3nc(0, 39);
+ case 'g': return u3nc(0, 21);
+ case 'l': return u3nc(0, 111);
+ case 'm': return u3nc(0, 178);
+ case 'n': return u3nc(0, 9);
+ case 'r': return u3nc(0, 5);
+ case 's': return u3nc(0, 36);
+ case 't': return u3nc(0, 69);
+ case 'x': return u3nc(0, 186);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'b': return u3nc(0, 166);
+ case 'n': return u3nc(0, 135);
+ case 'r': return u3nc(0, 63);
+ case 't': return u3nc(0, 25);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'l': return u3nc(0, 48);
+ case 'x': return u3nc(0, 149);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'r': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 65);
+ case 'c': return u3nc(0, 77);
+ case 'd': return u3nc(0, 137);
+ case 'f': return u3nc(0, 140);
+ case 'g': return u3nc(0, 72);
+ case 'l': return u3nc(0, 210);
+ case 'm': return u3nc(0, 224);
+ case 'n': return u3nc(0, 124);
+ case 'p': return u3nc(0, 250);
+ case 's': return u3nc(0, 136);
+ case 't': return u3nc(0, 216);
+ case 'v': return u3nc(0, 139);
+ case 'x': return u3nc(0, 88);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'c': return u3nc(0, 97);
+ case 'd': return u3nc(0, 211);
+ case 'l': return u3nc(0, 70);
+ case 'm': return u3nc(0, 131);
+ case 'n': return u3nc(0, 184);
+ case 'p': return u3nc(0, 201);
+ case 's': return u3nc(0, 143);
+ case 't': return u3nc(0, 52);
+ case 'x': return u3nc(0, 123);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'c': return u3nc(0, 228);
+ case 'd': return u3nc(0, 204);
+ case 'g': return u3nc(0, 150);
+ case 'l': return u3nc(0, 222);
+ case 'm': return u3nc(0, 167);
+ case 'n': return u3nc(0, 147);
+ case 'p': return u3nc(0, 16);
+ case 's': return u3nc(0, 64);
+ case 't': return u3nc(0, 28);
+ case 'x': return u3nc(0, 151);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 's': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 220);
+ case 'c': return u3nc(0, 80);
+ case 'd': return u3nc(0, 237);
+ case 'f': return u3nc(0, 58);
+ case 'g': return u3nc(0, 133);
+ case 'l': return u3nc(0, 96);
+ case 'm': return u3nc(0, 75);
+ case 'n': return u3nc(0, 245);
+ case 'p': return u3nc(0, 35);
+ case 'r': return u3nc(0, 13);
+ case 't': return u3nc(0, 115);
+ case 'v': return u3nc(0, 4);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'b': return u3nc(0, 68);
+ case 'd': return u3nc(0, 177);
+ case 'g': return u3nc(0, 229);
+ case 'l': return u3nc(0, 38);
+ case 'm': return u3nc(0, 85);
+ case 'n': return u3nc(0, 15);
+ case 'p': return u3nc(0, 74);
+ case 'r': return u3nc(0, 119);
+ case 't': return u3nc(0, 6);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'd': return u3nc(0, 30);
+ case 'l': return u3nc(0, 163);
+ case 'm': return u3nc(0, 95);
+ case 'n': return u3nc(0, 71);
+ case 'p': return u3nc(0, 112);
+ case 'r': return u3nc(0, 100);
+ case 't': return u3nc(0, 10);
+ case 'x': return u3nc(0, 17);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 't': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 89);
+ case 'c': return u3nc(0, 164);
+ case 'd': return u3nc(0, 142);
+ case 'g': return u3nc(0, 251);
+ case 'l': return u3nc(0, 249);
+ case 'm': return u3nc(0, 40);
+ case 'n': return u3nc(0, 160);
+ case 'p': return u3nc(0, 55);
+ case 'r': return u3nc(0, 113);
+ case 's': return u3nc(0, 241);
+ case 'v': return u3nc(0, 83);
+ case 'x': return u3nc(0, 118);
+ default: return 0;
+ }
+ case 'u': switch (three) {
+ case 'c': return u3nc(0, 168);
+ case 'd': return u3nc(0, 121);
+ case 'g': return u3nc(0, 109);
+ case 'l': return u3nc(0, 42);
+ case 'n': return u3nc(0, 175);
+ case 's': return u3nc(0, 154);
+ case 'x': return u3nc(0, 108);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'c': return u3nc(0, 155);
+ case 'd': return u3nc(0, 73);
+ case 'l': return u3nc(0, 53);
+ case 'n': return u3nc(0, 132);
+ case 'p': return u3nc(0, 189);
+ case 'r': return u3nc(0, 153);
+ case 'v': return u3nc(0, 29);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'w': switch (two) {
+ case 'e': switch (three) {
+ case 'b': return u3nc(0, 84);
+ case 'd': return u3nc(0, 192);
+ case 'g': return u3nc(0, 246);
+ case 'l': return u3nc(0, 207);
+ case 'n': return u3nc(0, 44);
+ case 'p': return u3nc(0, 12);
+ case 'r': return u3nc(0, 227);
+ case 's': return u3nc(0, 3);
+ case 't': return u3nc(0, 101);
+ case 'x': return u3nc(0, 99);
+ default: return 0;
+ }
+ case 'y': switch (three) {
+ case 'c': return u3nc(0, 59);
+ case 'd': return u3nc(0, 54);
+ case 'l': return u3nc(0, 14);
+ case 'n': return u3nc(0, 76);
+ case 't': return u3nc(0, 125);
+ case 'x': return u3nc(0, 94);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ case 'z': switch (two) {
+ case 'o': switch (three) {
+ case 'd': return u3nc(0, 0);
+ default: return 0;
+ }
+ default: return 0;
+ }
+ default: return 0;
+ }
+}
+
+void
+u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c)
+{
+ switch (id) {
+ case 0: *a = 'z'; *b = 'o'; *c = 'd'; break;
+ case 1: *a = 'n'; *b = 'e'; *c = 'c'; break;
+ case 2: *a = 'b'; *b = 'u'; *c = 'd'; break;
+ case 3: *a = 'w'; *b = 'e'; *c = 's'; break;
+ case 4: *a = 's'; *b = 'e'; *c = 'v'; break;
+ case 5: *a = 'p'; *b = 'e'; *c = 'r'; break;
+ case 6: *a = 's'; *b = 'u'; *c = 't'; break;
+ case 7: *a = 'l'; *b = 'e'; *c = 't'; break;
+ case 8: *a = 'f'; *b = 'u'; *c = 'l'; break;
+ case 9: *a = 'p'; *b = 'e'; *c = 'n'; break;
+ case 10: *a = 's'; *b = 'y'; *c = 't'; break;
+ case 11: *a = 'd'; *b = 'u'; *c = 'r'; break;
+ case 12: *a = 'w'; *b = 'e'; *c = 'p'; break;
+ case 13: *a = 's'; *b = 'e'; *c = 'r'; break;
+ case 14: *a = 'w'; *b = 'y'; *c = 'l'; break;
+ case 15: *a = 's'; *b = 'u'; *c = 'n'; break;
+ case 16: *a = 'r'; *b = 'y'; *c = 'p'; break;
+ case 17: *a = 's'; *b = 'y'; *c = 'x'; break;
+ case 18: *a = 'd'; *b = 'y'; *c = 'r'; break;
+ case 19: *a = 'n'; *b = 'u'; *c = 'p'; break;
+ case 20: *a = 'h'; *b = 'e'; *c = 'b'; break;
+ case 21: *a = 'p'; *b = 'e'; *c = 'g'; break;
+ case 22: *a = 'l'; *b = 'u'; *c = 'p'; break;
+ case 23: *a = 'd'; *b = 'e'; *c = 'p'; break;
+ case 24: *a = 'd'; *b = 'y'; *c = 's'; break;
+ case 25: *a = 'p'; *b = 'u'; *c = 't'; break;
+ case 26: *a = 'l'; *b = 'u'; *c = 'g'; break;
+ case 27: *a = 'h'; *b = 'e'; *c = 'c'; break;
+ case 28: *a = 'r'; *b = 'y'; *c = 't'; break;
+ case 29: *a = 't'; *b = 'y'; *c = 'v'; break;
+ case 30: *a = 's'; *b = 'y'; *c = 'd'; break;
+ case 31: *a = 'n'; *b = 'e'; *c = 'x'; break;
+ case 32: *a = 'l'; *b = 'u'; *c = 'n'; break;
+ case 33: *a = 'm'; *b = 'e'; *c = 'p'; break;
+ case 34: *a = 'l'; *b = 'u'; *c = 't'; break;
+ case 35: *a = 's'; *b = 'e'; *c = 'p'; break;
+ case 36: *a = 'p'; *b = 'e'; *c = 's'; break;
+ case 37: *a = 'd'; *b = 'e'; *c = 'l'; break;
+ case 38: *a = 's'; *b = 'u'; *c = 'l'; break;
+ case 39: *a = 'p'; *b = 'e'; *c = 'd'; break;
+ case 40: *a = 't'; *b = 'e'; *c = 'm'; break;
+ case 41: *a = 'l'; *b = 'e'; *c = 'd'; break;
+ case 42: *a = 't'; *b = 'u'; *c = 'l'; break;
+ case 43: *a = 'm'; *b = 'e'; *c = 't'; break;
+ case 44: *a = 'w'; *b = 'e'; *c = 'n'; break;
+ case 45: *a = 'b'; *b = 'y'; *c = 'n'; break;
+ case 46: *a = 'h'; *b = 'e'; *c = 'x'; break;
+ case 47: *a = 'f'; *b = 'e'; *c = 'b'; break;
+ case 48: *a = 'p'; *b = 'y'; *c = 'l'; break;
+ case 49: *a = 'd'; *b = 'u'; *c = 'l'; break;
+ case 50: *a = 'h'; *b = 'e'; *c = 't'; break;
+ case 51: *a = 'm'; *b = 'e'; *c = 'v'; break;
+ case 52: *a = 'r'; *b = 'u'; *c = 't'; break;
+ case 53: *a = 't'; *b = 'y'; *c = 'l'; break;
+ case 54: *a = 'w'; *b = 'y'; *c = 'd'; break;
+ case 55: *a = 't'; *b = 'e'; *c = 'p'; break;
+ case 56: *a = 'b'; *b = 'e'; *c = 's'; break;
+ case 57: *a = 'd'; *b = 'e'; *c = 'x'; break;
+ case 58: *a = 's'; *b = 'e'; *c = 'f'; break;
+ case 59: *a = 'w'; *b = 'y'; *c = 'c'; break;
+ case 60: *a = 'b'; *b = 'u'; *c = 'r'; break;
+ case 61: *a = 'd'; *b = 'e'; *c = 'r'; break;
+ case 62: *a = 'n'; *b = 'e'; *c = 'p'; break;
+ case 63: *a = 'p'; *b = 'u'; *c = 'r'; break;
+ case 64: *a = 'r'; *b = 'y'; *c = 's'; break;
+ case 65: *a = 'r'; *b = 'e'; *c = 'b'; break;
+ case 66: *a = 'd'; *b = 'e'; *c = 'n'; break;
+ case 67: *a = 'n'; *b = 'u'; *c = 't'; break;
+ case 68: *a = 's'; *b = 'u'; *c = 'b'; break;
+ case 69: *a = 'p'; *b = 'e'; *c = 't'; break;
+ case 70: *a = 'r'; *b = 'u'; *c = 'l'; break;
+ case 71: *a = 's'; *b = 'y'; *c = 'n'; break;
+ case 72: *a = 'r'; *b = 'e'; *c = 'g'; break;
+ case 73: *a = 't'; *b = 'y'; *c = 'd'; break;
+ case 74: *a = 's'; *b = 'u'; *c = 'p'; break;
+ case 75: *a = 's'; *b = 'e'; *c = 'm'; break;
+ case 76: *a = 'w'; *b = 'y'; *c = 'n'; break;
+ case 77: *a = 'r'; *b = 'e'; *c = 'c'; break;
+ case 78: *a = 'm'; *b = 'e'; *c = 'g'; break;
+ case 79: *a = 'n'; *b = 'e'; *c = 't'; break;
+ case 80: *a = 's'; *b = 'e'; *c = 'c'; break;
+ case 81: *a = 'm'; *b = 'u'; *c = 'l'; break;
+ case 82: *a = 'n'; *b = 'y'; *c = 'm'; break;
+ case 83: *a = 't'; *b = 'e'; *c = 'v'; break;
+ case 84: *a = 'w'; *b = 'e'; *c = 'b'; break;
+ case 85: *a = 's'; *b = 'u'; *c = 'm'; break;
+ case 86: *a = 'm'; *b = 'u'; *c = 't'; break;
+ case 87: *a = 'n'; *b = 'y'; *c = 'x'; break;
+ case 88: *a = 'r'; *b = 'e'; *c = 'x'; break;
+ case 89: *a = 't'; *b = 'e'; *c = 'b'; break;
+ case 90: *a = 'f'; *b = 'u'; *c = 's'; break;
+ case 91: *a = 'h'; *b = 'e'; *c = 'p'; break;
+ case 92: *a = 'b'; *b = 'e'; *c = 'n'; break;
+ case 93: *a = 'm'; *b = 'u'; *c = 's'; break;
+ case 94: *a = 'w'; *b = 'y'; *c = 'x'; break;
+ case 95: *a = 's'; *b = 'y'; *c = 'm'; break;
+ case 96: *a = 's'; *b = 'e'; *c = 'l'; break;
+ case 97: *a = 'r'; *b = 'u'; *c = 'c'; break;
+ case 98: *a = 'd'; *b = 'e'; *c = 'c'; break;
+ case 99: *a = 'w'; *b = 'e'; *c = 'x'; break;
+ case 100: *a = 's'; *b = 'y'; *c = 'r'; break;
+ case 101: *a = 'w'; *b = 'e'; *c = 't'; break;
+ case 102: *a = 'd'; *b = 'y'; *c = 'l'; break;
+ case 103: *a = 'm'; *b = 'y'; *c = 'n'; break;
+ case 104: *a = 'm'; *b = 'e'; *c = 's'; break;
+ case 105: *a = 'd'; *b = 'e'; *c = 't'; break;
+ case 106: *a = 'b'; *b = 'e'; *c = 't'; break;
+ case 107: *a = 'b'; *b = 'e'; *c = 'l'; break;
+ case 108: *a = 't'; *b = 'u'; *c = 'x'; break;
+ case 109: *a = 't'; *b = 'u'; *c = 'g'; break;
+ case 110: *a = 'm'; *b = 'y'; *c = 'r'; break;
+ case 111: *a = 'p'; *b = 'e'; *c = 'l'; break;
+ case 112: *a = 's'; *b = 'y'; *c = 'p'; break;
+ case 113: *a = 't'; *b = 'e'; *c = 'r'; break;
+ case 114: *a = 'm'; *b = 'e'; *c = 'b'; break;
+ case 115: *a = 's'; *b = 'e'; *c = 't'; break;
+ case 116: *a = 'd'; *b = 'u'; *c = 't'; break;
+ case 117: *a = 'd'; *b = 'e'; *c = 'g'; break;
+ case 118: *a = 't'; *b = 'e'; *c = 'x'; break;
+ case 119: *a = 's'; *b = 'u'; *c = 'r'; break;
+ case 120: *a = 'f'; *b = 'e'; *c = 'l'; break;
+ case 121: *a = 't'; *b = 'u'; *c = 'd'; break;
+ case 122: *a = 'n'; *b = 'u'; *c = 'x'; break;
+ case 123: *a = 'r'; *b = 'u'; *c = 'x'; break;
+ case 124: *a = 'r'; *b = 'e'; *c = 'n'; break;
+ case 125: *a = 'w'; *b = 'y'; *c = 't'; break;
+ case 126: *a = 'n'; *b = 'u'; *c = 'b'; break;
+ case 127: *a = 'm'; *b = 'e'; *c = 'd'; break;
+ case 128: *a = 'l'; *b = 'y'; *c = 't'; break;
+ case 129: *a = 'd'; *b = 'u'; *c = 's'; break;
+ case 130: *a = 'n'; *b = 'e'; *c = 'b'; break;
+ case 131: *a = 'r'; *b = 'u'; *c = 'm'; break;
+ case 132: *a = 't'; *b = 'y'; *c = 'n'; break;
+ case 133: *a = 's'; *b = 'e'; *c = 'g'; break;
+ case 134: *a = 'l'; *b = 'y'; *c = 'x'; break;
+ case 135: *a = 'p'; *b = 'u'; *c = 'n'; break;
+ case 136: *a = 'r'; *b = 'e'; *c = 's'; break;
+ case 137: *a = 'r'; *b = 'e'; *c = 'd'; break;
+ case 138: *a = 'f'; *b = 'u'; *c = 'n'; break;
+ case 139: *a = 'r'; *b = 'e'; *c = 'v'; break;
+ case 140: *a = 'r'; *b = 'e'; *c = 'f'; break;
+ case 141: *a = 'm'; *b = 'e'; *c = 'c'; break;
+ case 142: *a = 't'; *b = 'e'; *c = 'd'; break;
+ case 143: *a = 'r'; *b = 'u'; *c = 's'; break;
+ case 144: *a = 'b'; *b = 'e'; *c = 'x'; break;
+ case 145: *a = 'l'; *b = 'e'; *c = 'b'; break;
+ case 146: *a = 'd'; *b = 'u'; *c = 'x'; break;
+ case 147: *a = 'r'; *b = 'y'; *c = 'n'; break;
+ case 148: *a = 'n'; *b = 'u'; *c = 'm'; break;
+ case 149: *a = 'p'; *b = 'y'; *c = 'x'; break;
+ case 150: *a = 'r'; *b = 'y'; *c = 'g'; break;
+ case 151: *a = 'r'; *b = 'y'; *c = 'x'; break;
+ case 152: *a = 'f'; *b = 'e'; *c = 'p'; break;
+ case 153: *a = 't'; *b = 'y'; *c = 'r'; break;
+ case 154: *a = 't'; *b = 'u'; *c = 's'; break;
+ case 155: *a = 't'; *b = 'y'; *c = 'c'; break;
+ case 156: *a = 'l'; *b = 'e'; *c = 'g'; break;
+ case 157: *a = 'n'; *b = 'e'; *c = 'm'; break;
+ case 158: *a = 'f'; *b = 'e'; *c = 'r'; break;
+ case 159: *a = 'm'; *b = 'e'; *c = 'r'; break;
+ case 160: *a = 't'; *b = 'e'; *c = 'n'; break;
+ case 161: *a = 'l'; *b = 'u'; *c = 's'; break;
+ case 162: *a = 'n'; *b = 'u'; *c = 's'; break;
+ case 163: *a = 's'; *b = 'y'; *c = 'l'; break;
+ case 164: *a = 't'; *b = 'e'; *c = 'c'; break;
+ case 165: *a = 'm'; *b = 'e'; *c = 'x'; break;
+ case 166: *a = 'p'; *b = 'u'; *c = 'b'; break;
+ case 167: *a = 'r'; *b = 'y'; *c = 'm'; break;
+ case 168: *a = 't'; *b = 'u'; *c = 'c'; break;
+ case 169: *a = 'f'; *b = 'y'; *c = 'l'; break;
+ case 170: *a = 'l'; *b = 'e'; *c = 'p'; break;
+ case 171: *a = 'd'; *b = 'e'; *c = 'b'; break;
+ case 172: *a = 'b'; *b = 'e'; *c = 'r'; break;
+ case 173: *a = 'm'; *b = 'u'; *c = 'g'; break;
+ case 174: *a = 'h'; *b = 'u'; *c = 't'; break;
+ case 175: *a = 't'; *b = 'u'; *c = 'n'; break;
+ case 176: *a = 'b'; *b = 'y'; *c = 'l'; break;
+ case 177: *a = 's'; *b = 'u'; *c = 'd'; break;
+ case 178: *a = 'p'; *b = 'e'; *c = 'm'; break;
+ case 179: *a = 'd'; *b = 'e'; *c = 'v'; break;
+ case 180: *a = 'l'; *b = 'u'; *c = 'r'; break;
+ case 181: *a = 'd'; *b = 'e'; *c = 'f'; break;
+ case 182: *a = 'b'; *b = 'u'; *c = 's'; break;
+ case 183: *a = 'b'; *b = 'e'; *c = 'p'; break;
+ case 184: *a = 'r'; *b = 'u'; *c = 'n'; break;
+ case 185: *a = 'm'; *b = 'e'; *c = 'l'; break;
+ case 186: *a = 'p'; *b = 'e'; *c = 'x'; break;
+ case 187: *a = 'd'; *b = 'y'; *c = 't'; break;
+ case 188: *a = 'b'; *b = 'y'; *c = 't'; break;
+ case 189: *a = 't'; *b = 'y'; *c = 'p'; break;
+ case 190: *a = 'l'; *b = 'e'; *c = 'v'; break;
+ case 191: *a = 'm'; *b = 'y'; *c = 'l'; break;
+ case 192: *a = 'w'; *b = 'e'; *c = 'd'; break;
+ case 193: *a = 'd'; *b = 'u'; *c = 'c'; break;
+ case 194: *a = 'f'; *b = 'u'; *c = 'r'; break;
+ case 195: *a = 'f'; *b = 'e'; *c = 'x'; break;
+ case 196: *a = 'n'; *b = 'u'; *c = 'l'; break;
+ case 197: *a = 'l'; *b = 'u'; *c = 'c'; break;
+ case 198: *a = 'l'; *b = 'e'; *c = 'n'; break;
+ case 199: *a = 'n'; *b = 'e'; *c = 'r'; break;
+ case 200: *a = 'l'; *b = 'e'; *c = 'x'; break;
+ case 201: *a = 'r'; *b = 'u'; *c = 'p'; break;
+ case 202: *a = 'n'; *b = 'e'; *c = 'd'; break;
+ case 203: *a = 'l'; *b = 'e'; *c = 'c'; break;
+ case 204: *a = 'r'; *b = 'y'; *c = 'd'; break;
+ case 205: *a = 'l'; *b = 'y'; *c = 'd'; break;
+ case 206: *a = 'f'; *b = 'e'; *c = 'n'; break;
+ case 207: *a = 'w'; *b = 'e'; *c = 'l'; break;
+ case 208: *a = 'n'; *b = 'y'; *c = 'd'; break;
+ case 209: *a = 'h'; *b = 'u'; *c = 's'; break;
+ case 210: *a = 'r'; *b = 'e'; *c = 'l'; break;
+ case 211: *a = 'r'; *b = 'u'; *c = 'd'; break;
+ case 212: *a = 'n'; *b = 'e'; *c = 's'; break;
+ case 213: *a = 'h'; *b = 'e'; *c = 's'; break;
+ case 214: *a = 'f'; *b = 'e'; *c = 't'; break;
+ case 215: *a = 'd'; *b = 'e'; *c = 's'; break;
+ case 216: *a = 'r'; *b = 'e'; *c = 't'; break;
+ case 217: *a = 'd'; *b = 'u'; *c = 'n'; break;
+ case 218: *a = 'l'; *b = 'e'; *c = 'r'; break;
+ case 219: *a = 'n'; *b = 'y'; *c = 'r'; break;
+ case 220: *a = 's'; *b = 'e'; *c = 'b'; break;
+ case 221: *a = 'h'; *b = 'u'; *c = 'l'; break;
+ case 222: *a = 'r'; *b = 'y'; *c = 'l'; break;
+ case 223: *a = 'l'; *b = 'u'; *c = 'd'; break;
+ case 224: *a = 'r'; *b = 'e'; *c = 'm'; break;
+ case 225: *a = 'l'; *b = 'y'; *c = 's'; break;
+ case 226: *a = 'f'; *b = 'y'; *c = 'n'; break;
+ case 227: *a = 'w'; *b = 'e'; *c = 'r'; break;
+ case 228: *a = 'r'; *b = 'y'; *c = 'c'; break;
+ case 229: *a = 's'; *b = 'u'; *c = 'g'; break;
+ case 230: *a = 'n'; *b = 'y'; *c = 's'; break;
+ case 231: *a = 'n'; *b = 'y'; *c = 'l'; break;
+ case 232: *a = 'l'; *b = 'y'; *c = 'n'; break;
+ case 233: *a = 'd'; *b = 'y'; *c = 'n'; break;
+ case 234: *a = 'd'; *b = 'e'; *c = 'm'; break;
+ case 235: *a = 'l'; *b = 'u'; *c = 'x'; break;
+ case 236: *a = 'f'; *b = 'e'; *c = 'd'; break;
+ case 237: *a = 's'; *b = 'e'; *c = 'd'; break;
+ case 238: *a = 'b'; *b = 'e'; *c = 'c'; break;
+ case 239: *a = 'm'; *b = 'u'; *c = 'n'; break;
+ case 240: *a = 'l'; *b = 'y'; *c = 'r'; break;
+ case 241: *a = 't'; *b = 'e'; *c = 's'; break;
+ case 242: *a = 'm'; *b = 'u'; *c = 'd'; break;
+ case 243: *a = 'n'; *b = 'y'; *c = 't'; break;
+ case 244: *a = 'b'; *b = 'y'; *c = 'r'; break;
+ case 245: *a = 's'; *b = 'e'; *c = 'n'; break;
+ case 246: *a = 'w'; *b = 'e'; *c = 'g'; break;
+ case 247: *a = 'f'; *b = 'y'; *c = 'r'; break;
+ case 248: *a = 'm'; *b = 'u'; *c = 'r'; break;
+ case 249: *a = 't'; *b = 'e'; *c = 'l'; break;
+ case 250: *a = 'r'; *b = 'e'; *c = 'p'; break;
+ case 251: *a = 't'; *b = 'e'; *c = 'g'; break;
+ case 252: *a = 'p'; *b = 'e'; *c = 'c'; break;
+ case 253: *a = 'n'; *b = 'e'; *c = 'l'; break;
+ case 254: *a = 'n'; *b = 'e'; *c = 'v'; break;
+ case 255: *a = 'f'; *b = 'e'; *c = 's'; break;
+ default: u3m_bail(c3__exit);
+ }
+}
+
+u3_noun
+u3qc_po_ins(u3_noun a)
+{
+ c3_y byt_y[3];
+ u3r_bytes(0, 3, byt_y, a);
+
+ return u3_po_find_prefix(byt_y[0], byt_y[1], byt_y[2]);
+}
+
+u3_noun
+u3wcp_ins(u3_noun cor)
+{
+ u3_noun a;
+ u3x_mean(cor, u3x_sam, &a, 0);
+
+ if ( c3n == u3ud(a) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ return u3qc_po_ins(a);
+}
+
+u3_noun
+u3qc_po_ind(u3_noun a)
+{
+ c3_y byt_y[3];
+ u3r_bytes(0, 3, byt_y, a);
+
+ return u3_po_find_suffix(byt_y[0], byt_y[1], byt_y[2]);
+}
+
+u3_noun
+u3wcp_ind(u3_noun cor)
+{
+ u3_noun a;
+ u3x_mean(cor, u3x_sam, &a, 0);
+
+ if ( c3n == u3ud(a) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ return u3qc_po_ind(a);
+}
+
+u3_noun
+u3wcp_tos(u3_noun cor)
+{
+ u3_noun a;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) ||
+ (c3n == u3ud(a)) ||
+ (a >= 256) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y byt_y[3];
+ u3_po_to_prefix(a, &byt_y[0], &byt_y[1], &byt_y[2]);
+ return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16));
+ }
+}
+
+u3_noun
+u3wcp_tod(u3_noun cor)
+{
+ u3_noun a;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) ||
+ (c3n == u3ud(a)) ||
+ (a >= 256) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ c3_y byt_y[3];
+ u3_po_to_suffix(a, &byt_y[0], &byt_y[1], &byt_y[2]);
+ return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16));
+ }
+}
diff --git a/vere/pkg/noun/jets/c/pow.c b/vere/pkg/noun/jets/c/pow.c
new file mode 100644
index 0000000..8d45fc8
--- /dev/null
+++ b/vere/pkg/noun/jets/c/pow.c
@@ -0,0 +1,38 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_pow(u3_atom a,
+ u3_atom b)
+ {
+ if ( !_(u3a_is_cat(b)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ mpz_t a_mp;
+
+ u3r_mp(a_mp, a);
+ mpz_pow_ui(a_mp, a_mp, b);
+
+ return u3i_mp(a_mp);
+ }
+ }
+ u3_noun
+ u3wc_pow(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_pow(a, b);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/rap.c b/vere/pkg/noun/jets/c/rap.c
new file mode 100644
index 0000000..4c95693
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rap.c
@@ -0,0 +1,88 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_rap(u3_atom a,
+ u3_noun b)
+ {
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w tot_w = 0;
+ u3i_slab sab_u;
+
+ /* Measure and validate the slab required.
+ */
+ {
+ u3_noun cab = b;
+
+ while ( 1 ) {
+ u3_noun h_cab;
+ c3_w len_w;
+
+ if ( 0 == cab ) {
+ break;
+ }
+ else if ( c3n == u3du(cab) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( c3n == u3ud(h_cab = u3h(cab)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) {
+ return u3m_bail(c3__fail);
+ }
+ tot_w += len_w;
+ cab = u3t(cab);
+ }
+
+ if ( 0 == tot_w ) {
+ return 0;
+ }
+
+ u3i_slab_init(&sab_u, a_g, tot_w);
+ }
+
+ /* Chop the list atoms in.
+ */
+ {
+ u3_noun cab = b;
+ c3_w pos_w = 0;
+
+ while ( 0 != cab ) {
+ u3_noun h_cab = u3h(cab);
+ c3_w len_w = u3r_met(a_g, h_cab);
+
+ u3r_chop(a_g, 0, len_w, pos_w, sab_u.buf_w, h_cab);
+ pos_w += len_w;
+ cab = u3t(cab);
+ }
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+ u3_noun
+ u3wc_rap(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun pro;
+
+ pro = u3qc_rap(a, b);
+ return pro;
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/rep.c b/vere/pkg/noun/jets/c/rep.c
new file mode 100644
index 0000000..914e917
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rep.c
@@ -0,0 +1,199 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/*
+ Get the lowest `n` bits of a word `w` using a bitmask.
+*/
+#define TAKEBITS(n,w) \
+ ((n)==32) ? (w) : \
+ ((n)==0) ? 0 : \
+ ((w) & ((1 << (n)) - 1))
+
+/*
+ Divide, rounding up.
+*/
+#define DIVCEIL(x,y) \
+ (x==0) ? 0 : \
+ 1 + ((x - 1) / y);
+
+static u3_noun
+_bit_rep(u3_atom bits, u3_noun blox)
+{
+ if ( (c3n == u3a_is_cat(bits) || bits==0 || bits>31) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ //
+ // Calculate input and output size.
+ //
+ c3_w num_blox_w = u3qb_lent(blox);
+ c3_w bit_widt_w = num_blox_w * bits;
+ c3_w wor_widt_w = DIVCEIL(bit_widt_w, 32);
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 5, wor_widt_w);
+
+ //
+ // Fill the atom buffer with bits from each block.
+ //
+ // Bits are pushed into the `acc_w` register and flushed to the buffer
+ // once full.
+ //
+ // acc_w register
+ // use_w number of register bits filled (used)
+ // cur_w next buffer word to flush into.
+ //
+ {
+ c3_w acc_w=0, use_w=0, *cur_w=sab_u.buf_w;
+
+# define FLUSH() *cur_w++=acc_w; acc_w=use_w=0
+# define SLICE(sz,off,val) TAKEBITS(sz, val) << off
+
+ for (c3_w i=0; i<num_blox_w; i++) {
+ u3_noun blok_n = u3h(blox);
+ blox = u3t(blox);
+
+ if ( c3n == u3a_is_cat(blok_n) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w blok_w = blok_n;
+
+ for (c3_w rem_in_blok_w=bits; rem_in_blok_w;) {
+ c3_w rem_in_acc_w = 32 - use_w;
+ if (rem_in_blok_w == rem_in_acc_w) { // EQ
+ acc_w |= SLICE(rem_in_blok_w, use_w, blok_w);
+ FLUSH();
+ rem_in_blok_w = 0;
+ }
+ else if (rem_in_blok_w < rem_in_acc_w) { // LT
+ acc_w |= SLICE(rem_in_blok_w, use_w, blok_w);
+ use_w += rem_in_blok_w;
+ rem_in_blok_w = 0;
+ }
+ else { // GT
+ acc_w |= SLICE(rem_in_acc_w, use_w, blok_w);
+ rem_in_blok_w -= rem_in_acc_w;
+ blok_w = blok_w >> rem_in_acc_w;
+ FLUSH();
+ }
+ }
+ }
+
+ //
+ // If the last word isn't fully used, it will still need to be
+ // flushed.
+ //
+ if (use_w) {
+ FLUSH();
+ }
+ }
+
+ return u3i_slab_mint(&sab_u);
+}
+
+static u3_noun
+_block_rep(u3_atom a,
+ u3_noun b)
+{
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_g a_g = a;
+ c3_w tot_w = 0;
+ u3i_slab sab_u;
+
+ /* Measure and validate the slab required.
+ */
+ {
+ u3_noun cab = b;
+
+ while ( 1 ) {
+ u3_noun h_cab;
+ c3_w len_w;
+
+ if ( 0 == cab ) {
+ break;
+ }
+ else if ( c3n == u3du(cab) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( c3n == u3ud(h_cab = u3h(cab)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) {
+ return u3m_bail(c3__fail);
+ }
+ tot_w++;
+ cab = u3t(cab);
+ }
+
+ if ( 0 == tot_w ) {
+ return 0;
+ }
+
+ u3i_slab_init(&sab_u, a_g, tot_w);
+ }
+
+ /* Chop the list atoms in.
+ */
+ {
+ u3_noun cab = b;
+ c3_w pos_w = 0;
+
+ while ( 0 != cab ) {
+ u3_noun h_cab = u3h(cab);
+
+ u3r_chop(a_g, 0, 1, pos_w, sab_u.buf_w, h_cab);
+ pos_w++;
+ cab = u3t(cab);
+ }
+ }
+
+ return u3i_slab_mint(&sab_u);
+ }
+}
+
+u3_noun
+u3qc_rep(u3_atom a,
+ u3_atom b,
+ u3_noun c)
+{
+ if ( 1 == b ) {
+ return _block_rep(a, c);
+ }
+
+ if ( 0 == a ) {
+ return _bit_rep(b, c);
+ }
+
+ u3l_log("rep: stub");
+ return u3_none;
+}
+
+u3_noun
+u3wc_rep(u3_noun cor)
+{
+ u3_atom bloq, step;
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0);
+ u3x_bite(a, &bloq, &step);
+
+ return u3qc_rep(bloq, step, b);
+}
+
+u3_noun
+u3kc_rep(u3_atom a,
+ u3_atom b,
+ u3_noun c)
+{
+ u3_noun res = u3qc_rep(a, b, c);
+ u3z(a); u3z(b); u3z(c);
+ return res;
+}
diff --git a/vere/pkg/noun/jets/c/rev.c b/vere/pkg/noun/jets/c/rev.c
new file mode 100644
index 0000000..1ce74c0
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rev.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_rev(u3_atom boz,
+ u3_atom len,
+ u3_atom dat)
+ {
+ if ( !_(u3a_is_cat(boz)) || (boz >= 32) ||
+ !_(u3a_is_cat(len)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ dat = u3qc_end(boz, len, dat);
+ c3_w met = u3r_met(boz, dat);
+ return u3kc_lsh(boz, (len - met), u3kc_swp(boz, dat));
+ }
+
+ u3_noun
+ u3wc_rev(u3_noun cor)
+ {
+ u3_noun boz, len, dat;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &boz,
+ u3x_sam_6, &len,
+ u3x_sam_7, &dat, 0)) ||
+ (c3n == u3ud(boz)) ||
+ (c3n == u3ud(len)) ||
+ (c3n == u3ud(dat)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_rev(boz, len, dat);
+ }
+ }
+
+ u3_noun
+ u3kc_rev(u3_atom boz,
+ u3_atom len,
+ u3_atom dat)
+ {
+ u3_noun res = u3qc_rev(boz, len, dat);
+ u3z(boz); u3z(len); u3z(dat);
+ return res;
+ }
diff --git a/vere/pkg/noun/jets/c/rig.c b/vere/pkg/noun/jets/c/rig.c
new file mode 100644
index 0000000..7e5e7b9
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rig.c
@@ -0,0 +1,82 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+c3_d
+u3qc_rig_s(c3_g foq_g,
+ c3_w sep_w,
+ c3_g toq_g)
+{
+ c3_d sep_d = sep_w;
+
+ if ( foq_g >= toq_g ) {
+ return sep_d << (foq_g - toq_g);
+ }
+ else {
+ c3_g dif_g = toq_g - foq_g;
+
+ sep_d += (1 << dif_g) - 1;
+ return sep_d >> dif_g;
+ }
+}
+
+u3_noun
+u3qc_rig(u3_atom foq,
+ u3_atom sep,
+ u3_atom toq)
+{
+ if ( c3y == u3r_sing(foq, toq) ) {
+ return u3k(sep);
+ }
+
+ if ( (c3y == u3a_is_cat(foq)) && (foq < 32)
+ && (c3y == u3a_is_cat(toq)) && (toq < 32)
+ && (c3y == u3a_is_cat(sep)) )
+ {
+ c3_d sep_d = u3qc_rig_s((c3_g)foq, (c3_w)sep, (c3_g)toq);
+ return u3i_chub(sep_d);
+ }
+
+ if ( c3y == u3qa_gth(foq, toq) ) {
+ u3_atom d = u3qa_sub(foq, toq);
+ u3_atom e = u3qc_lsh(0, d, sep);
+ u3z(d);
+ return e;
+ }
+ else {
+ u3_atom d = u3qa_sub(toq, foq);
+ u3_atom e = u3qc_rsh(0, d, sep);
+ u3_atom f = u3qc_end(0, d, sep);
+
+ if ( f ) {
+ e = u3i_vint(e);
+ u3z(f);
+ }
+
+ u3z(d);
+ return e;
+ }
+}
+
+u3_noun
+u3wc_rig(u3_noun cor)
+{
+ u3_atom boq, sep, vat;
+ {
+ u3_noun sam = u3h(u3t(cor));
+ u3_noun bit = u3h(sam);
+
+ if ( c3y == u3a_is_atom(bit) ) {
+ return 0;
+ }
+
+ boq = u3x_atom(u3h(bit));
+ sep = u3x_atom(u3t(bit));
+ vat = u3x_atom(u3t(sam));
+ }
+
+ return u3qc_rig(boq, sep, vat);
+}
diff --git a/vere/pkg/noun/jets/c/rip.c b/vere/pkg/noun/jets/c/rip.c
new file mode 100644
index 0000000..bff23b8
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rip.c
@@ -0,0 +1,192 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/*
+ Get the lowest `n` bits of a word `w` using a bitmask.
+*/
+#define TAKEBITS(n,w) \
+ ((n)==32) ? (w) : \
+ ((n)==0) ? 0 : \
+ ((w) & ((1 << (n)) - 1))
+
+/*
+ Divide, rounding up.
+*/
+#define DIVCEIL(x,y) \
+ (x==0) ? 0 : \
+ 1 + ((x - 1) / y);
+
+/*
+ `ripn` breaks `atom` into a list of blocks, of bit-width `bits`. The
+ resulting list will be least-significant block first.
+
+ XX TODO This only handles cases where the bit-width is <= 32.
+
+ For each block we produce, we need to grab the relevant words inside
+ `atom`, so we first compute their indicies.
+
+ `ins_idx` is the word-index of the least-significant word we
+ care about, and `sig_idx` is the word after that.
+
+ Next we grab those words (`ins_word` and `sig_word`) from the atom
+ using `u3r_word`. Note that `sig_idx` might be out-of-bounds for the
+ underlying array of `atom`, but `u3r_word` returns 0 in that case,
+ which is exatly what we want.
+
+ Now, we need to grab the relevant bits out of both words, and combine
+ them. `bits_rem_in_ins_word` is the number of remaining (insignificant)
+ bits in `ins_word`, `nbits_ins` is the number of bits we want from the
+ less-significant word, and `nbits_sig` from the more-significant one.
+
+ Take the least significant `nbits_sig` bits from `sig_word`, and take
+ the slice we care about from `ins_word`. In order to take that slice,
+ we drop `bits_rem_in_ins_word` insignificant bits, and then take the
+ `nbits_sig` most-significant bits.
+
+ Last, we slice out those bits from the two words, combine them into
+ one word, and cons them onto the front of the result.
+*/
+static u3_noun
+_bit_rip(u3_atom bits, u3_atom atom)
+{
+ if ( !_(u3a_is_cat(bits) || bits==0 || bits>31) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w bit_width = u3r_met(0, atom);
+ c3_w num_blocks = DIVCEIL(bit_width, bits);
+
+ u3_noun res = u3_nul;
+
+ for ( c3_w blk = 0; blk < num_blocks; blk++ ) {
+ c3_w next_blk = blk + 1;
+ c3_w blks_rem = num_blocks - next_blk;
+ c3_w bits_rem = blks_rem * bits;
+ c3_w ins_idx = bits_rem / 32;
+ c3_w sig_idx = ins_idx + 1;
+
+ c3_w bits_rem_in_ins_word = bits_rem % 32;
+
+ c3_w ins_word = u3r_word(ins_idx, atom);
+ c3_w sig_word = u3r_word(sig_idx, atom);
+ c3_w nbits_ins = c3_min(bits, 32 - bits_rem_in_ins_word);
+ c3_w nbits_sig = bits - nbits_ins;
+
+ c3_w ins_word_bits = TAKEBITS(nbits_ins, ins_word >> bits_rem_in_ins_word);
+ c3_w sig_word_bits = TAKEBITS(nbits_sig, sig_word);
+
+ c3_w item = ins_word_bits | (sig_word_bits << nbits_ins);
+
+ res = u3nc(item, res);
+ }
+
+ return res;
+}
+
+static u3_noun
+_block_rip(u3_atom bloq, u3_atom b)
+{
+ if ( !_(u3a_is_cat(bloq)) || (bloq >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_g bloq_g = bloq;
+
+ /*
+ This is a fast-path for the case where all the resulting blocks will
+ fit in 31-bit direct atoms.
+ */
+ if ( bloq_g < 5 ) { // produce direct atoms
+ u3_noun acc = u3_nul;
+
+ c3_w met_w = u3r_met(bloq_g, b); // num blocks in atom
+ c3_w nbits_w = 1 << bloq_g; // block size in bits
+ c3_w bmask_w = (1 << nbits_w) - 1; // result mask
+
+ for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { // `i_w` is block index
+ c3_w nex_w = i_w + 1; // next block
+ c3_w pat_w = met_w - nex_w; // blks left after this
+ c3_w bit_w = pat_w << bloq_g; // bits left after this
+ c3_w wor_w = bit_w >> 5; // wrds left after this
+ c3_w sif_w = bit_w & 31; // bits left in word
+ c3_w src_w = u3r_word(wor_w, b); // find word by index
+ c3_w rip_w = (src_w >> sif_w) & bmask_w; // get item from word
+
+ acc = u3nc(rip_w, acc);
+ }
+
+ return acc;
+ }
+
+ u3_noun acc = u3_nul;
+ c3_w met_w = u3r_met(bloq_g, b);
+ c3_w len_w = u3r_met(5, b);
+ c3_g san_g = (bloq_g - 5);
+ c3_w san_w = 1 << san_g;
+ c3_w dif_w = (met_w << san_g) - len_w;
+ c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w));
+
+ for ( c3_w i_w = 0; i_w < met_w; i_w++ ) {
+ c3_w pat_w = (met_w - (i_w + 1));
+ c3_w wut_w = (pat_w << san_g);
+ c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
+ c3_w j_w;
+ u3_atom rip;
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 5, sap_w);
+
+ for ( j_w = 0; j_w < sap_w; j_w++ ) {
+ sab_u.buf_w[j_w] = u3r_word(wut_w + j_w, b);
+ }
+
+ rip = u3i_slab_mint(&sab_u);
+ acc = u3nc(rip, acc);
+ len_w -= san_w;
+ }
+
+ return acc;
+}
+
+u3_noun
+u3qc_rip(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+{
+ if ( 1 == b ) {
+ return _block_rip(a, c);
+ }
+
+ if ( 0 == a ) {
+ return _bit_rip(b, c);
+ }
+
+ u3l_log("rip: stub");
+ return u3_none;
+}
+
+u3_noun
+u3wc_rip(u3_noun cor)
+{
+ u3_atom bloq, step;
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0);
+ u3x_bite(a, &bloq, &step);
+
+ return u3qc_rip(bloq, step, u3x_atom(b));
+}
+
+u3_noun
+u3kc_rip(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+{
+ u3_noun pro = u3qc_rip(a, b, c);
+ u3z(a); u3z(b); u3z(c);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/c/rsh.c b/vere/pkg/noun/jets/c/rsh.c
new file mode 100644
index 0000000..6fc8ddf
--- /dev/null
+++ b/vere/pkg/noun/jets/c/rsh.c
@@ -0,0 +1,60 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_rsh(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+{
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ else if ( !_(u3a_is_cat(b)) ) {
+ return 0;
+ }
+ else {
+ c3_g a_g = a;
+ c3_w b_w = b;
+ c3_w len_w = u3r_met(a_g, c);
+
+ if ( b_w >= len_w ) {
+ return 0;
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, (len_w - b_w));
+
+ u3r_chop(a_g, b_w, (len_w - b_w), 0, sab_u.buf_w, c);
+
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+}
+
+u3_noun
+u3wc_rsh(u3_noun cor)
+{
+ u3_atom bloq, step;
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0);
+ u3x_bite(a, &bloq, &step);
+
+ return u3qc_rsh(bloq, step, u3x_atom(b));
+}
+
+u3_noun
+u3kc_rsh(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+{
+ u3_noun d = u3qc_rsh(a, b, c);
+
+ u3z(a); u3z(b); u3z(c);
+ return d;
+}
diff --git a/vere/pkg/noun/jets/c/sew.c b/vere/pkg/noun/jets/c/sew.c
new file mode 100644
index 0000000..02359f7
--- /dev/null
+++ b/vere/pkg/noun/jets/c/sew.c
@@ -0,0 +1,74 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_weak
+u3qc_sew(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom d,
+ u3_atom e
+ )
+{
+ c3_w b_w, c_w;
+ if (0 == c) return u3k(e);
+ if ( !_(u3r_safe_word(b, &b_w)) ||
+ !_(u3r_safe_word(c, &c_w)) ) {
+ return u3_none;
+ }
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ c3_g a_g = a;
+ c3_w len_e_w = u3r_met(a_g, e);
+ u3i_slab sab_u;
+ c3_w* src_w;
+ c3_w len_src_w;
+ if ( _(u3a_is_cat(e)) ) {
+ len_src_w = e ? 1 : 0;
+ src_w = &e;
+ }
+ else {
+ u3a_atom* src_u = u3a_to_ptr(e);
+ len_src_w = src_u->len_w;
+ src_w = src_u->buf_w;
+ }
+ u3i_slab_init(&sab_u, a_g, c3_max(len_e_w, b_w + c_w));
+ u3r_chop_words(a_g, 0, b_w, 0, sab_u.buf_w, len_src_w, src_w);
+ u3r_chop(a_g, 0, c_w, b_w, sab_u.buf_w, d);
+ if (len_e_w > b_w + c_w) {
+ u3r_chop_words(a_g,
+ b_w + c_w,
+ len_e_w - (b_w + c_w),
+ b_w + c_w,
+ sab_u.buf_w,
+ len_src_w,
+ src_w);
+ }
+ return u3i_slab_mint(&sab_u);
+}
+
+u3_weak
+u3wc_sew(u3_noun cor)
+{
+ u3_noun a, b, c, d, e;
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_12, &b,
+ 106, &c,
+ 107, &d,
+ u3x_sam_7, &e, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) ||
+ (c3n == u3ud(d)) ||
+ (c3n == u3ud(e)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qc_sew(a, b, c, d, e);
+ }
+}
diff --git a/vere/pkg/noun/jets/c/sqt.c b/vere/pkg/noun/jets/c/sqt.c
new file mode 100644
index 0000000..b20db59
--- /dev/null
+++ b/vere/pkg/noun/jets/c/sqt.c
@@ -0,0 +1,33 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_sqt(u3_atom a)
+ {
+ mpz_t a_mp, b_mp;
+
+ u3r_mp(a_mp, a);
+ mpz_init(b_mp);
+ mpz_sqrtrem(a_mp, b_mp, a_mp);
+
+ return u3nc(u3i_mp(a_mp), u3i_mp(b_mp));
+ }
+ u3_noun
+ u3wc_sqt(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_sqt(a);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/c/swp.c b/vere/pkg/noun/jets/c/swp.c
new file mode 100644
index 0000000..4f503e7
--- /dev/null
+++ b/vere/pkg/noun/jets/c/swp.c
@@ -0,0 +1,50 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qc_swp(u3_atom a,
+ u3_atom b)
+{
+ if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+ c3_g a_g = a;
+ c3_w len_w = u3r_met(a_g, b);
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, len_w);
+
+ for (c3_w i = 0; i < len_w; i++) {
+ u3r_chop(a_g, i, 1, len_w - i - 1, sab_u.buf_w, b);
+ }
+
+ return u3i_slab_mint(&sab_u);
+}
+
+u3_noun
+u3wc_swp(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+
+ if ( (c3n == u3ud(a))
+ || (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+
+ return u3qc_swp(a, b);
+ }
+
+u3_noun
+u3kc_swp(u3_atom a,
+ u3_atom b)
+{
+ u3_noun pro = u3qc_swp(a, b);
+ u3z(a); u3z(b);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/c/xeb.c b/vere/pkg/noun/jets/c/xeb.c
new file mode 100644
index 0000000..6a23ac1
--- /dev/null
+++ b/vere/pkg/noun/jets/c/xeb.c
@@ -0,0 +1,32 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qc_xeb(u3_atom a)
+ {
+ c3_w met_w = u3r_met(0, a);
+
+ if ( !_(u3a_is_cat(met_w)) ) {
+ return u3i_words(1, &met_w);
+ }
+ else return met_w;
+ }
+ u3_noun
+ u3wc_xeb(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qc_xeb(a);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/d/by_all.c b/vere/pkg/noun/jets/d/by_all.c
new file mode 100644
index 0000000..25926a7
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_all.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_by_all(u3_noun a, u3j_site* sit_u)
+{
+ if ( u3_nul == a ) {
+ return c3y;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) {
+ case c3y: break;
+ case c3n: return c3n;
+ default: return u3m_bail(c3__exit);
+ }
+
+ if ( c3n == _by_all(l_a, sit_u) ) {
+ return c3n;
+ }
+
+ return _by_all(r_a, sit_u);
+ }
+}
+
+u3_noun
+u3qdb_all(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ pro = _by_all(a, &sit_u);
+ u3j_gate_lose(&sit_u);
+
+ return pro;
+}
+
+u3_noun
+u3wdb_all(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_all(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/by_any.c b/vere/pkg/noun/jets/d/by_any.c
new file mode 100644
index 0000000..b81f32d
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_any.c
@@ -0,0 +1,51 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_by_any(u3_noun a, u3j_site* sit_u)
+{
+ if ( u3_nul == a ) {
+ return c3n;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) {
+ case c3y: return c3y;
+ case c3n: break;
+ default: return u3m_bail(c3__exit);
+ }
+
+ if ( c3y == _by_any(l_a, sit_u) ) {
+ return c3y;
+ }
+
+ return _by_any(r_a, sit_u);
+ }
+}
+
+u3_noun
+u3qdb_any(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ pro = _by_any(a, &sit_u);
+ u3j_gate_lose(&sit_u);
+
+ return pro;
+}
+
+u3_noun
+u3wdb_any(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_any(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/by_apt.c b/vere/pkg/noun/jets/d/by_apt.c
new file mode 100644
index 0000000..66a6414
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_apt.c
@@ -0,0 +1,78 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static c3_o
+_by_apt(u3_noun a, u3_weak l, u3_weak r)
+{
+ if ( u3_nul == a ) {
+ return c3y;
+ }
+ else {
+ u3_noun p_n_a, l_a, r_a;
+ {
+ u3_noun n_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ p_n_a = u3h(n_a);
+ }
+
+ if ( u3_none != l ) {
+ if ( (c3n == u3qc_gor(p_n_a, l))
+ || (c3y == u3r_sing(p_n_a, l)) )
+ {
+ return c3n;
+ }
+ }
+
+ if ( u3_none != r ) {
+ if ( (c3n == u3qc_gor(r, p_n_a))
+ || (c3y == u3r_sing(r, p_n_a)) )
+ {
+ return c3n;
+ }
+ }
+
+ if ( u3_nul != l_a ) {
+ u3_noun p_n_l_a = u3h(u3h(l_a));
+
+ if ( (c3n == u3qc_mor(p_n_a, p_n_l_a))
+ || (c3y == u3r_sing(p_n_a, p_n_l_a)) )
+ {
+ return c3n;
+ }
+
+ if ( c3n == _by_apt(l_a, p_n_a, r) ) {
+ return c3n;
+ }
+ }
+
+ if ( u3_nul != r_a ) {
+ u3_noun p_n_r_a = u3h(u3h(r_a));
+
+ if ( (c3n == u3qc_mor(p_n_a, p_n_r_a))
+ || (c3y == u3r_sing(p_n_a, p_n_r_a)) )
+ {
+ return c3n;
+ }
+
+ return _by_apt(r_a, l, p_n_a);
+ }
+
+ return c3y;
+ }
+}
+
+u3_noun
+u3qdb_apt(u3_noun a)
+{
+ return _by_apt(a, u3_none, u3_none);
+}
+
+u3_noun
+u3wdb_apt(u3_noun cor)
+{
+ return u3qdb_apt(u3x_at(u3x_con_sam, cor));
+}
diff --git a/vere/pkg/noun/jets/d/by_bif.c b/vere/pkg/noun/jets/d/by_bif.c
new file mode 100644
index 0000000..0a2f23a
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_bif.c
@@ -0,0 +1,74 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* internal functions
+*/
+static u3_noun
+_b_bif_putroot(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3nt(u3k(b), u3_nul, u3_nul);
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3_noun p_n_a, q_n_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_cell(n_a, &p_n_a, &q_n_a);
+
+ if ( c3y == u3r_sing(b, p_n_a) ) {
+ return u3nt(u3k(b), u3k(l_a), u3k(r_a));
+ }
+ else {
+ u3_noun c, n_c, l_c, r_c;
+ u3_noun d;
+
+ if ( c3y == u3qc_gor(b, p_n_a) ) {
+ c = _b_bif_putroot(l_a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nt(u3k(n_c),
+ u3k(l_c),
+ u3nt(u3k(n_a), u3k(r_c), u3k(r_a))
+ );
+ u3z(c);
+ return d;
+ }
+ else {
+ c = _b_bif_putroot(r_a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nt(u3k(n_c),
+ u3nt(u3k(n_a), u3k(l_a), u3k(l_c)),
+ u3k(r_c)
+ );
+ u3z(c);
+ return d;
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdb_bif(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_bif(a, b);
+}
+
+u3_noun
+u3qdb_bif(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c, n_c, l_c, r_c;
+ u3_noun d;
+
+ c = _b_bif_putroot(a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nc(u3k(l_c), u3k(r_c));
+ u3z(c);
+ return d;
+}
diff --git a/vere/pkg/noun/jets/d/by_del.c b/vere/pkg/noun/jets/d/by_del.c
new file mode 100644
index 0000000..86ba416
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_del.c
@@ -0,0 +1,93 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_rebalance(u3_noun a)
+{
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ if ( u3_nul == l_a) {
+ return u3k(r_a);
+ }
+ else if ( u3_nul == r_a) {
+ return u3k(l_a);
+ }
+ else {
+ u3_noun n_l_a, l_l_a, r_l_a;
+ u3_noun n_r_a, l_r_a, r_r_a;
+ u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a);
+ u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a);
+
+ if ( c3y == u3qc_mor(u3h(n_l_a), u3h(n_r_a)) ) {
+ u3_noun new_right = u3nt(u3k(n_a),
+ u3k(r_l_a),
+ u3k(r_a));
+
+ u3_noun ret = u3nt(u3k(n_l_a),
+ u3k(l_l_a),
+ _rebalance(new_right));
+ u3z(new_right);
+
+ return ret;
+ }
+ else {
+ u3_noun new_left = u3nt(u3k(n_a),
+ u3k(l_a),
+ u3k(l_r_a));
+
+ u3_noun ret = u3nt(u3k(n_r_a),
+ _rebalance(new_left),
+ u3k(r_r_a));
+ u3z(new_left);
+
+ return ret;
+ }
+ }
+}
+
+u3_noun
+u3qdb_del(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3_noun pn_a;
+ u3x_cell(a, &n_a, &lr_a);
+ u3x_cell(n_a, &pn_a, 0);
+
+ if ( c3y == u3r_sing(pn_a, b) ) {
+ return _rebalance(a);
+ }
+ else {
+ u3_noun l_a, r_a;
+ u3x_cell(lr_a, &l_a, &r_a);
+
+ if ( c3y == u3qc_gor(b, pn_a) ) {
+ return u3nt(u3k(n_a),
+ u3qdb_del(l_a, b),
+ u3k(r_a));
+ }
+ else {
+ return u3nt(u3k(n_a),
+ u3k(l_a),
+ u3qdb_del(r_a, b));
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdb_del(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_del(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/by_dif.c b/vere/pkg/noun/jets/d/by_dif.c
new file mode 100644
index 0000000..44dcd1a
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_dif.c
@@ -0,0 +1,83 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* internal functions
+*/
+
+/* RETAIN
+*/
+static u3_noun
+_b_dif_join(u3_noun d,
+ u3_noun e)
+{
+ if ( u3_nul == d ) {
+ return u3k(e);
+ }
+ else if ( u3_nul == e ) {
+ return u3k(d);
+ }
+ else {
+ u3_noun n_d, lr_d;
+ u3_noun n_e, lr_e;
+ u3x_cell(d, &n_d, &lr_d);
+ u3x_cell(e, &n_e, &lr_e);
+
+ if ( c3y == u3qc_mor(u3h(n_d), u3h(n_e)) ) {
+ u3_noun l_d, r_d;
+ u3x_cell(lr_d, &l_d, &r_d);
+
+ return u3nt(u3k(n_d),
+ u3k(l_d),
+ _b_dif_join(r_d, e));
+ }
+ else {
+ u3_noun l_e, r_e;
+ u3x_cell(lr_e, &l_e, &r_e);
+
+ return u3nt(u3k(n_e),
+ _b_dif_join(d, l_e),
+ u3k(r_e));
+ }
+ }
+}
+
+u3_noun
+u3wdb_dif(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_dif(a, b);
+}
+
+u3_noun
+u3qdb_dif(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun n_b, p_n_b, q_n_b, l_b, r_b;
+ u3_noun c, l_c, r_c;
+ u3x_trel(b, &n_b, &l_b, &r_b);
+ u3x_cell(n_b, &p_n_b, &q_n_b);
+
+ c = u3qdb_bif(a, p_n_b);
+ u3x_cell(c, &l_c, &r_c);
+
+ u3_noun d = u3qdb_dif(l_c, l_b);
+ u3_noun e = u3qdb_dif(r_c, r_b);
+
+ u3z(c);
+
+ u3_noun pro = _b_dif_join(d, e);
+ u3z(d);
+ u3z(e);
+
+ return pro;
+ }
+}
diff --git a/vere/pkg/noun/jets/d/by_gas.c b/vere/pkg/noun/jets/d/by_gas.c
new file mode 100644
index 0000000..2da171d
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_gas.c
@@ -0,0 +1,44 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdb_gas(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun i_b, t_b,
+ pi_b, qi_b;
+ u3x_cell(b, &i_b, &t_b);
+ u3x_cell(i_b, &pi_b, &qi_b);
+
+ u3_noun c = u3qdb_put(a, pi_b, qi_b);
+ u3_noun d = u3qdb_gas(c, t_b);
+ u3z(c);
+ return d;
+ }
+}
+
+u3_noun
+u3wdb_gas(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_gas(a, b);
+}
+
+u3_noun
+u3kdb_gas(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdb_gas(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/d/by_get.c b/vere/pkg/noun/jets/d/by_get.c
new file mode 100644
index 0000000..19e77b9
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_get.c
@@ -0,0 +1,63 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdb_get(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3_noun pn_a, qn_a;
+ u3x_cell(a, &n_a, &lr_a);
+ u3x_cell(n_a, &pn_a, &qn_a);
+
+ if ( (c3y == u3r_sing(b, pn_a)) ) {
+ return u3nc(u3_nul, u3k(qn_a));
+ }
+ else {
+ return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_get(u3h(lr_a), b)
+ : u3qdb_get(u3t(lr_a), b);
+ }
+ }
+}
+
+u3_noun
+u3wdb_get(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_get(a, b);
+}
+
+u3_weak
+u3kdb_get(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdb_get(a, b);
+ u3z(a); u3z(b);
+
+ if ( c3n == u3du(c) ) {
+ u3z(c);
+ return u3_none;
+ }
+ else {
+ u3_noun pro = u3k(u3t(c));
+ u3z(c);
+ return pro;
+ }
+}
+
+u3_noun
+u3kdb_got(u3_noun a,
+ u3_noun b)
+{
+ return u3x_good(u3kdb_get(a, b));
+}
diff --git a/vere/pkg/noun/jets/d/by_has.c b/vere/pkg/noun/jets/d/by_has.c
new file mode 100644
index 0000000..24bcb31
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_has.c
@@ -0,0 +1,47 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdb_has(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return c3n;
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3_noun pn_a;
+ u3x_cell(a, &n_a, &lr_a);
+ u3x_cell(n_a, &pn_a, 0);
+
+ if ( (c3y == u3r_sing(b, pn_a)) ) {
+ return c3y;
+ }
+ else {
+ return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_has(u3h(lr_a), b)
+ : u3qdb_has(u3t(lr_a), b);
+ }
+ }
+}
+
+u3_noun
+u3wdb_has(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_has(a, b);
+}
+
+u3_noun
+u3kdb_has(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdb_has(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/d/by_int.c b/vere/pkg/noun/jets/d/by_int.c
new file mode 100644
index 0000000..5caa8aa
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_int.c
@@ -0,0 +1,72 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdb_int(u3_noun a, u3_noun b)
+{
+ if ( (u3_nul == a)
+ || (u3_nul == b) )
+ {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3_noun n_b, l_b, r_b;
+ u3_noun p_n_a, q_n_a;
+ u3_noun p_n_b, q_n_b;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_trel(b, &n_b, &l_b, &r_b);
+ u3x_cell(n_a, &p_n_a, &q_n_a);
+ u3x_cell(n_b, &p_n_b, &q_n_b);
+
+ if ( c3y == u3qc_mor(p_n_a, p_n_b) ) {
+ if ( c3y == u3r_sing(p_n_b, p_n_a) ) {
+ return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b));
+ }
+ else if ( c3y == u3qc_gor(p_n_b, p_n_a) ) {
+ u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul);
+ u3_noun new_a = u3qdb_int(l_a, new_l_b);
+
+ u3z(new_l_b);
+ return u3kdb_uni(new_a, u3qdb_int(a, r_b));
+ }
+ else {
+ u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b));
+ u3_noun new_a = u3qdb_int(r_a, new_r_b);
+
+ u3z(new_r_b);
+ return u3kdb_uni(new_a, u3qdb_int(a, l_b));
+ }
+ }
+ else if ( c3y == u3r_sing(p_n_a, p_n_b) ) {
+ return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b));
+ }
+ else if ( c3y == u3qc_gor(p_n_a, p_n_b) ) {
+ u3_noun new_l_a = u3nt(u3k(n_a), u3k(l_a), u3_nul);
+ u3_noun new_a = u3qdb_int(new_l_a, l_b);
+
+ u3z(new_l_a);
+ return u3kdb_uni(new_a, u3qdb_int(r_a, b));
+ }
+ else {
+ u3_noun new_r_a = u3nt(u3k(n_a), u3_nul, u3k(r_a));
+ u3_noun new_a = u3qdb_int(new_r_a, r_b);
+
+ u3z(new_r_a);
+ return u3kdb_uni(new_a, u3qdb_int(l_a, b));
+ }
+ }
+}
+
+u3_noun
+u3wdb_int(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_int(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/by_jab.c b/vere/pkg/noun/jets/d/by_jab.c
new file mode 100644
index 0000000..597e454
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_jab.c
@@ -0,0 +1,63 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3kdb_jab(u3_noun a,
+ u3_noun key,
+ u3_noun fun)
+ {
+ if ( u3_nul == a ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3_noun pn_a, qn_a;
+ u3_noun pro;
+ u3x_cell(a, &n_a, &lr_a);
+ u3x_cell(n_a, &pn_a, &qn_a);
+
+ if ( (c3y == u3r_sing(key, pn_a)) ) {
+ u3_noun value = u3n_slam_on(fun, u3k(qn_a));
+ pro = u3nc(u3nc(u3k(u3h(u3h(a))), value), u3k(u3t(a)));
+ u3z(a); u3z(key);
+ return pro;
+ }
+ else {
+ u3_noun l_a, r_a;
+ u3x_cell(lr_a, &l_a, &r_a);
+
+ u3k(n_a); u3k(l_a); u3k(r_a);
+ if ( c3y == u3qc_gor(key, pn_a) ) {
+ pro = u3nt(n_a, u3kdb_jab(l_a, key, fun), r_a);
+ }
+ else {
+ pro = u3nt(n_a, l_a, u3kdb_jab(r_a, key, fun));
+ }
+ u3z(a);
+ return pro;
+ }
+ }
+}
+
+u3_noun
+u3qdb_jab(u3_noun a,
+ u3_noun key,
+ u3_noun fun)
+{
+ return u3kdb_jab(u3k(a), u3k(key), u3k(fun));
+}
+
+u3_noun
+u3wdb_jab(u3_noun cor)
+{
+ u3_noun a, key, fun;
+ u3x_mean(cor, u3x_sam_2, &key,
+ u3x_sam_3, &fun,
+ u3x_con_sam, &a, 0);
+
+ return u3qdb_jab(a, key, fun);
+}
diff --git a/vere/pkg/noun/jets/d/by_key.c b/vere/pkg/noun/jets/d/by_key.c
new file mode 100644
index 0000000..b4f8a09
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_key.c
@@ -0,0 +1,42 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+// [a] is RETAINED, [set] is TRANSFERRED
+//
+static u3_noun
+_by_key(u3_noun a, u3_noun set)
+{
+ if ( u3_nul == a ) {
+ return set;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ {
+ u3_noun new = u3qdi_put(set, u3h(n_a));
+ u3z(set);
+ set = new;
+ }
+
+ set = _by_key(l_a, set);
+
+ return _by_key(r_a, set);
+ }
+}
+
+u3_noun
+u3qdb_key(u3_noun a)
+{
+ return _by_key(a, u3_nul);
+}
+
+u3_noun
+u3wdb_key(u3_noun cor)
+{
+ return u3qdb_key(u3x_at(u3x_con_sam, cor));
+}
diff --git a/vere/pkg/noun/jets/d/by_put.c b/vere/pkg/noun/jets/d/by_put.c
new file mode 100644
index 0000000..ad0e7ec
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_put.c
@@ -0,0 +1,102 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdb_put(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+{
+ if ( u3_nul == a ) {
+ return u3nt(u3nc(u3k(b), u3k(c)),
+ u3_nul,
+ u3_nul);
+ }
+ else {
+ 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);
+
+ if ( c3y == u3r_sing(pn_a, b) ) {
+ if ( c3y == u3r_sing(qn_a, c) ) {
+ return u3k(a);
+ }
+ else {
+ return u3nt(u3nc(u3k(b), u3k(c)),
+ u3k(l_a),
+ u3k(r_a));
+ }
+ }
+ else {
+ u3_noun d, n_d, l_d, r_d;
+
+ if ( c3y == u3qc_gor(b, pn_a) ) {
+ d = u3qdb_put(l_a, b, c);
+
+ if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) {
+ return u3nt(u3k(n_a),
+ d,
+ u3k(r_a));
+ }
+ else {
+ u3r_trel(d, &n_d, &l_d, &r_d);
+
+ u3_noun e = u3nt(u3k(n_d),
+ u3k(l_d),
+ u3nt(u3k(n_a),
+ u3k(r_d),
+ u3k(r_a)));
+
+ u3z(d);
+ return e;
+ }
+ }
+ else {
+ d = u3qdb_put(r_a, b, c);
+
+ if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) {
+ return u3nt(u3k(n_a),
+ u3k(l_a),
+ d);
+ }
+ else {
+ u3r_trel(d, &n_d, &l_d, &r_d);
+
+ u3_noun e = u3nt(u3k(n_d),
+ u3nt(u3k(n_a),
+ u3k(l_a),
+ u3k(l_d)),
+ u3k(r_d));
+
+ u3z(d);
+ return e;
+ }
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdb_put(u3_noun cor)
+{
+ u3_noun a, b, c;
+ u3x_mean(cor, u3x_sam_2, &b,
+ u3x_sam_3, &c,
+ u3x_con_sam, &a, 0);
+ return u3qdb_put(a, b, c);
+}
+
+u3_noun
+u3kdb_put(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+{
+ u3_noun pro = u3qdb_put(a, b, c);
+ u3z(a); u3z(b); u3z(c);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/d/by_run.c b/vere/pkg/noun/jets/d/by_run.c
new file mode 100644
index 0000000..491a32c
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_run.c
@@ -0,0 +1,53 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_by_run(u3_noun a, u3j_site* sit_u)
+{
+ if ( u3_nul == a ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3_noun p_n_a, q_n_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_cell(n_a, &p_n_a, &q_n_a);
+
+ u3k(p_n_a);
+ u3k(q_n_a);
+ u3k(l_a);
+ u3k(r_a);
+
+ u3_noun pro = u3nt(u3nc(p_n_a, u3j_gate_slam(sit_u, q_n_a)),
+ _by_run(l_a, sit_u),
+ _by_run(r_a, sit_u));
+
+ u3z(a);
+ return pro;
+ }
+}
+
+u3_noun
+u3qdb_run(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ pro = _by_run(u3k(a), &sit_u);
+ u3j_gate_lose(&sit_u);
+
+ return pro;
+}
+
+u3_noun
+u3wdb_run(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_run(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/by_uni.c b/vere/pkg/noun/jets/d/by_uni.c
new file mode 100644
index 0000000..6bdcd4c
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_uni.c
@@ -0,0 +1,101 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+u3_noun
+u3qdb_uni(u3_noun a, u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else if ( u3_nul == a ) {
+ return u3k(b);
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3_noun n_b, l_b, r_b;
+ u3_noun p_n_a, q_n_a;
+ u3_noun p_n_b, q_n_b;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_trel(b, &n_b, &l_b, &r_b);
+ u3x_cell(n_a, &p_n_a, &q_n_a);
+ u3x_cell(n_b, &p_n_b, &q_n_b);
+
+ if ( c3y == u3r_sing(p_n_a, p_n_b) ) {
+ return u3nt(u3k(n_b),
+ u3qdb_uni(l_a, l_b),
+ u3qdb_uni(r_a, r_b));
+ }
+ else if ( c3y == u3qc_mor(p_n_a, p_n_b) ) {
+ u3_noun new_a, old_b;
+
+ if ( c3y == u3qc_gor(p_n_b, p_n_a) ) {
+ u3_noun new_b = u3nt(u3k(n_b), u3k(l_b), u3_nul);
+ u3_noun new_la = u3qdb_uni(l_a, new_b);
+ u3z(new_b);
+
+ new_a = u3nt(u3k(n_a), new_la, u3k(r_a));
+ old_b = r_b;
+ }
+ else {
+ u3_noun new_b = u3nt(u3k(n_b), u3_nul, u3k(r_b));
+ u3_noun new_ra = u3qdb_uni(r_a, new_b);
+ u3z(new_b);
+
+ new_a = u3nt(u3k(n_a), u3k(l_a), new_ra);
+ old_b = l_b;
+ }
+
+ {
+ u3_noun pro = u3qdb_uni(new_a, old_b);
+ u3z(new_a);
+ return pro;
+ }
+ }
+ else {
+ u3_noun old_a, new_b;
+
+ if ( c3y == u3qc_gor(p_n_a, p_n_b) ) {
+ u3_noun new_a = u3nt(u3k(n_a), u3k(l_a), u3_nul);
+ u3_noun new_lb = u3qdb_uni(new_a, l_b);
+ u3z(new_a);
+
+ new_b = u3nt(u3k(n_b), new_lb, u3k(r_b));
+ old_a = r_a;
+ }
+ else {
+ u3_noun new_a = u3nt(u3k(n_a), u3_nul, u3k(r_a));
+ u3_noun new_rb = u3qdb_uni(new_a, r_b);
+ u3z(new_a);
+
+ new_b = u3nt(u3k(n_b), u3k(l_b), new_rb);
+ old_a = l_a;
+ }
+
+ {
+ u3_noun pro = u3qdb_uni(old_a, new_b);
+ u3z(new_b);
+ return pro;
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdb_uni(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_uni(a, b);
+}
+
+u3_noun
+u3kdb_uni(u3_noun a, u3_noun b)
+{
+ u3_noun pro = u3qdb_uni(a, b);
+ u3z(a); u3z(b);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/d/by_urn.c b/vere/pkg/noun/jets/d/by_urn.c
new file mode 100644
index 0000000..5c82876
--- /dev/null
+++ b/vere/pkg/noun/jets/d/by_urn.c
@@ -0,0 +1,52 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_by_urn(u3_noun a, u3j_site* sit_u)
+{
+ if ( u3_nul == a ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, l_a, r_a, p_n_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ p_n_a = u3h(n_a);
+
+ u3k(p_n_a);
+ u3k(n_a);
+ u3k(l_a);
+ u3k(r_a);
+
+ u3_noun pro = u3nt(u3nc(p_n_a, u3j_gate_slam(sit_u, n_a)),
+ _by_urn(l_a, sit_u),
+ _by_urn(r_a, sit_u));
+
+ u3z(a);
+ return pro;
+ }
+}
+
+u3_noun
+u3qdb_urn(u3_noun a, u3_noun b)
+{
+ u3_noun pro;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ pro = _by_urn(u3k(a), &sit_u);
+ u3j_gate_lose(&sit_u);
+
+ return pro;
+}
+
+u3_noun
+u3wdb_urn(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdb_urn(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/in_apt.c b/vere/pkg/noun/jets/d/in_apt.c
new file mode 100644
index 0000000..93e7b48
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_apt.c
@@ -0,0 +1,121 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static c3_o
+_in_apt_140(u3_noun a, u3_weak l, u3_weak r)
+{
+ if ( u3_nul == a ) {
+ return c3y;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ if ( (u3_none != l) && (c3n == u3qc_gor(n_a, l)) ) {
+ return c3n;
+ }
+
+ if ( (u3_none != r) && (c3n == u3qc_gor(r, n_a)) ) {
+ return c3n;
+ }
+
+ if ( u3_nul != l_a ) {
+ if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) {
+ return c3n;
+ }
+
+ if ( c3n == _in_apt_140(l_a, n_a, r) ) {
+ return c3n;
+ }
+ }
+
+ if ( u3_nul != r_a ) {
+ if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) {
+ return c3n;
+ }
+
+ return _in_apt_140(r_a, l, n_a);
+ }
+
+ return c3y;
+ }
+}
+
+u3_noun
+u3qdi_apt_140(u3_noun a)
+{
+ return _in_apt_140(a, u3_none, u3_none);
+}
+
+u3_noun
+u3wdi_apt_140(u3_noun cor)
+{
+ return u3qdi_apt_140(u3x_at(u3x_con_sam, cor));
+}
+
+
+static c3_o
+_in_apt(u3_noun a, u3_weak l, u3_weak r)
+{
+ if ( u3_nul == a ) {
+ return c3y;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ if ( (u3_none != l) &&
+ ( (c3y == u3r_sing(n_a, l)) || (c3n == u3qc_gor(n_a, l)) )) {
+ return c3n;
+ }
+
+ if ( (u3_none != r) &&
+ ( (c3y == u3r_sing(r, n_a)) || (c3n == u3qc_gor(r, n_a)) )) {
+ return c3n;
+ }
+
+ if ( u3_nul != l_a ) {
+ if ( c3y == u3r_sing(n_a, u3h(l_a)) ) {
+ return c3n;
+ }
+
+ if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) {
+ return c3n;
+ }
+
+ if ( c3n == _in_apt(l_a, n_a, r) ) {
+ return c3n;
+ }
+ }
+
+ if ( u3_nul != r_a ) {
+ if ( c3y == u3r_sing(n_a, u3h(r_a)) ) {
+ return c3n;
+ }
+
+ if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) {
+ return c3n;
+ }
+
+ return _in_apt(r_a, l, n_a);
+ }
+
+ return c3y;
+ }
+}
+
+u3_noun
+u3qdi_apt(u3_noun a)
+{
+ return _in_apt(a, u3_none, u3_none);
+}
+
+u3_noun
+u3wdi_apt(u3_noun cor)
+{
+ return u3qdi_apt(u3x_at(u3x_con_sam, cor));
+}
diff --git a/vere/pkg/noun/jets/d/in_bif.c b/vere/pkg/noun/jets/d/in_bif.c
new file mode 100644
index 0000000..76596b1
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_bif.c
@@ -0,0 +1,72 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* internal functions
+*/
+static u3_noun
+_i_bif_putroot(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a) {
+ return u3nt(u3k(b), u3_nul, u3_nul);
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3x_cell(a, &n_a, &lr_a);
+
+ if ( c3y == u3r_sing(b, n_a) ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun c, n_c, l_c, r_c;
+ u3_noun d;
+ u3_noun l_a, r_a;
+ u3x_cell(lr_a, &l_a, &r_a);
+
+ if ( c3y == u3qc_gor(b, n_a) ) {
+ c = _i_bif_putroot(l_a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nt(u3k(n_c),
+ u3k(l_c),
+ u3nt(u3k(n_a), u3k(r_c), u3k(r_a)));
+ u3z(c);
+ return d;
+ }
+ else {
+ c = _i_bif_putroot(r_a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nt(u3k(n_c),
+ u3nt(u3k(n_a), u3k(l_a), u3k(l_c)),
+ u3k(r_c));
+ u3z(c);
+ return d;
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdi_bif(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_bif(a, b);
+}
+
+u3_noun
+u3qdi_bif(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c, n_c, l_c, r_c;
+ u3_noun d;
+
+ c = _i_bif_putroot(a, b);
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ d = u3nc(u3k(l_c), u3k(r_c));
+ u3z(c);
+ return d;
+}
diff --git a/vere/pkg/noun/jets/d/in_del.c b/vere/pkg/noun/jets/d/in_del.c
new file mode 100644
index 0000000..5871a45
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_del.c
@@ -0,0 +1,88 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_rebalance(u3_noun a)
+{
+ u3_noun l_a, n_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ if ( u3_nul == l_a) {
+ return u3k(r_a);
+ }
+ else if ( u3_nul == r_a) {
+ return u3k(l_a);
+ }
+ else {
+ u3_noun n_l_a, l_l_a, r_l_a;
+ u3_noun n_r_a, l_r_a, r_r_a;
+ u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a);
+ u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a);
+
+ if ( c3y == u3qc_mor(n_l_a, n_r_a) ) {
+ u3_noun new_right = u3nt(u3k(n_a),
+ u3k(r_l_a),
+ u3k(r_a));
+
+ u3_noun ret = u3nt(u3k(n_l_a),
+ u3k(l_l_a),
+ _rebalance(new_right));
+ u3z(new_right);
+
+ return ret;
+ }
+ else {
+ u3_noun new_left = u3nt(u3k(n_a),
+ u3k(l_a),
+ u3k(l_r_a));
+
+ u3_noun ret = u3nt(u3k(n_r_a),
+ _rebalance(new_left),
+ u3k(r_r_a));
+ u3z(new_left);
+
+ return ret;
+ }
+ }
+}
+
+u3_noun
+u3qdi_del(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun l_a, n_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ if ( c3y == u3r_sing(n_a, b) ) {
+ return _rebalance(a);
+ }
+ else {
+ if ( c3y == u3qc_gor(b, n_a) ) {
+ return u3nt(u3k(n_a),
+ u3qdi_del(l_a, b),
+ u3k(r_a));
+ }
+ else {
+ return u3nt(u3k(n_a),
+ u3k(l_a),
+ u3qdi_del(r_a, b));
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdi_del(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_del(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/in_dif.c b/vere/pkg/noun/jets/d/in_dif.c
new file mode 100644
index 0000000..bff391d
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_dif.c
@@ -0,0 +1,82 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* internal functions
+*/
+
+/* RETAIN
+*/
+static u3_noun
+_i_dif_join(u3_noun d,
+ u3_noun e)
+{
+ if ( u3_nul == d ) {
+ return u3k(e);
+ }
+ else if ( u3_nul == e ) {
+ return u3k(d);
+ }
+ else {
+ u3_noun n_d, lr_d;
+ u3_noun n_e, lr_e;
+ u3x_cell(d, &n_d, &lr_d);
+ u3x_cell(e, &n_e, &lr_e);
+
+ if ( c3y == u3qc_mor(n_d, n_e) ) {
+ u3_noun l_d, r_d;
+ u3x_cell(lr_d, &l_d, &r_d);
+
+ return u3nt(u3k(n_d),
+ u3k(l_d),
+ _i_dif_join(r_d, e));
+ }
+ else {
+ u3_noun l_e, r_e;
+ u3x_cell(lr_e, &l_e, &r_e);
+
+ return u3nt(u3k(n_e),
+ _i_dif_join(d, l_e),
+ u3k(r_e));
+ }
+ }
+}
+
+u3_noun
+u3wdi_dif(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_dif(a, b);
+}
+
+u3_noun
+u3qdi_dif(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun n_b, l_b, r_b;
+ u3_noun c, l_c, r_c;
+ u3_noun d, e;
+
+ u3x_trel(b, &n_b, &l_b, &r_b);
+ c = u3qdi_bif(a, n_b);
+ u3x_cell(c, &l_c, &r_c);
+
+ d = u3qdi_dif(l_c, l_b);
+ e = u3qdi_dif(r_c, r_b);
+ u3z(c);
+
+ u3_noun pro = _i_dif_join(d, e);
+ u3z(d);
+ u3z(e);
+
+ return pro;
+ }
+}
diff --git a/vere/pkg/noun/jets/d/in_gas.c b/vere/pkg/noun/jets/d/in_gas.c
new file mode 100644
index 0000000..888e070
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_gas.c
@@ -0,0 +1,42 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdi_gas(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun i_b, t_b;
+ u3x_cell(b, &i_b, &t_b);
+
+ u3_noun c = u3qdi_put(a, i_b);
+ u3_noun d = u3qdi_gas(c, t_b);
+ u3z(c);
+ return d;
+ }
+}
+
+u3_noun
+u3wdi_gas(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_gas(a, b);
+}
+
+u3_noun
+u3kdi_gas(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdi_gas(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/d/in_has.c b/vere/pkg/noun/jets/d/in_has.c
new file mode 100644
index 0000000..ea6fb5f
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_has.c
@@ -0,0 +1,45 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdi_has(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return c3n;
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3x_cell(a, &n_a, &lr_a);
+
+ if ( (c3y == u3r_sing(b, n_a)) ) {
+ return c3y;
+ }
+ else {
+ return ( c3y == u3qc_gor(b, n_a) ) ? u3qdi_has(u3h(lr_a), b)
+ : u3qdi_has(u3t(lr_a), b);
+ }
+ }
+}
+
+u3_noun
+u3wdi_has(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_has(a, b);
+}
+
+u3_noun
+u3kdi_has(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdi_has(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
diff --git a/vere/pkg/noun/jets/d/in_int.c b/vere/pkg/noun/jets/d/in_int.c
new file mode 100644
index 0000000..fc5bfaa
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_int.c
@@ -0,0 +1,65 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdi_int(u3_noun a, u3_noun b)
+{
+ if ( (u3_nul == a)
+ || (u3_nul == b) )
+ {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3_noun n_b, l_b, r_b;
+
+ {
+ u3_noun lr_a, lr_b;
+ u3x_cell(a, &n_a, &lr_a);
+ u3x_cell(b, &n_b, &lr_b);
+
+ if ( c3y == u3qc_mor(n_a, n_b) ) {
+ u3_noun c;
+ c = a; a = b; b = c;
+ c = n_a; n_a = n_b; n_b = c;
+ c = lr_a; lr_a = lr_b; lr_b = c;
+ }
+
+ u3x_cell(lr_a, &l_a, &r_a);
+ u3x_cell(lr_b, &l_b, &r_b);
+ }
+
+ if ( c3y == u3r_sing(n_b, n_a) ) {
+ return u3nt(u3k(n_a),
+ u3qdi_int(l_a, l_b),
+ u3qdi_int(r_a, r_b));
+ }
+ else if ( c3y == u3qc_gor(n_b, n_a) ) {
+ u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul);
+ u3_noun new_a = u3qdi_int(l_a, new_l_b);
+
+ u3z(new_l_b);
+ return u3kdi_uni(new_a, u3qdi_int(a, r_b));
+ }
+ else {
+ u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b));
+ u3_noun new_a = u3qdi_int(r_a, new_r_b);
+
+ u3z(new_r_b);
+ return u3kdi_uni(new_a, u3qdi_int(a, l_b));
+ }
+ }
+}
+
+u3_noun
+u3wdi_int(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_int(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/in_put.c b/vere/pkg/noun/jets/d/in_put.c
new file mode 100644
index 0000000..909d48e
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_put.c
@@ -0,0 +1,87 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qdi_put(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3nt(u3k(b), u3_nul, u3_nul);
+ }
+ else {
+ u3_noun n_a, lr_a;
+ u3x_cell(a, &n_a, &lr_a);
+
+ if ( c3y == u3r_sing(n_a, b) ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun c, n_c, l_c, r_c;
+ u3_noun l_a, r_a;
+ u3x_cell(lr_a, &l_a, &r_a);
+
+ if ( c3y == u3qc_gor(b, n_a) ) {
+ c = u3qdi_put(l_a, b);
+
+ if ( c3y == u3qc_mor(n_a, u3h(c)) ) {
+ return u3nt(u3k(n_a),
+ c,
+ u3k(r_a));
+ }
+ else {
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ {
+ u3_noun d = u3nt(u3k(n_c),
+ u3k(l_c),
+ u3nt(u3k(n_a), u3k(r_c), u3k(r_a)));
+
+ u3z(c);
+ return d;
+ }
+ }
+ }
+ else {
+ c = u3qdi_put(r_a, b);
+
+ if ( c3y == u3qc_mor(n_a, u3h(c)) ) {
+ return u3nt(u3k(n_a),
+ u3k(l_a),
+ c);
+ }
+ else {
+ u3r_trel(c, &n_c, &l_c, &r_c);
+ {
+ u3_noun d = u3nt(u3k(n_c),
+ u3nt(u3k(n_a), u3k(l_a), u3k(l_c)),
+ u3k(r_c));
+
+ u3z(c);
+ return d;
+ }
+ }
+ }
+ }
+ }
+}
+
+u3_noun
+u3wdi_put(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_put(a, b);
+}
+
+u3_noun
+u3kdi_put(u3_noun a,
+ u3_noun b)
+{
+ u3_noun pro = u3qdi_put(a, b);
+ u3z(a); u3z(b);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/d/in_rep.c b/vere/pkg/noun/jets/d/in_rep.c
new file mode 100644
index 0000000..fafdad5
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_rep.c
@@ -0,0 +1,52 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+// [a] and [out] are TRANSFERRED
+//
+static void
+_in_rep(u3_noun a, u3j_site* sit_u, u3_noun* out)
+{
+ if ( u3_nul == a ) {
+ return;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ u3k(n_a);
+ u3k(l_a);
+ u3k(r_a);
+
+ *out = u3j_gate_slam(sit_u, u3nc(n_a, *out));
+
+ _in_rep(l_a, sit_u, out);
+ _in_rep(r_a, sit_u, out);
+
+ u3z(a);
+ }
+}
+
+u3_noun
+u3qdi_rep(u3_noun a, u3_noun b)
+{
+ u3_noun out = u3k(u3x_at(u3x_sam_3, b));
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ _in_rep(u3k(a), &sit_u, &out);
+ u3j_gate_lose(&sit_u);
+
+ return out;
+}
+
+u3_noun
+u3wdi_rep(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_rep(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/in_run.c b/vere/pkg/noun/jets/d/in_run.c
new file mode 100644
index 0000000..2216a5c
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_run.c
@@ -0,0 +1,59 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+// [a] and [out] are TRANSFERRED
+//
+static void
+_in_run(u3_noun a, u3j_site* sit_u, u3_noun* out)
+{
+ if ( u3_nul == a ) {
+ return;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ u3k(n_a);
+ u3k(l_a);
+ u3k(r_a);
+
+ {
+ u3_noun new = u3j_gate_slam(sit_u, n_a);
+ u3_noun pro = u3qdi_put(*out, new);
+
+ u3z(new);
+ u3z(*out);
+ *out = pro;
+ }
+
+ _in_run(l_a, sit_u, out);
+ _in_run(r_a, sit_u, out);
+
+ u3z(a);
+ }
+}
+
+u3_noun
+u3qdi_run(u3_noun a, u3_noun b)
+{
+ u3_noun out = u3_nul;
+ u3j_site sit_u;
+
+ u3j_gate_prep(&sit_u, u3k(b));
+ _in_run(u3k(a), &sit_u, &out);
+ u3j_gate_lose(&sit_u);
+
+ return out;
+}
+
+u3_noun
+u3wdi_run(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_run(a, b);
+}
diff --git a/vere/pkg/noun/jets/d/in_tap.c b/vere/pkg/noun/jets/d/in_tap.c
new file mode 100644
index 0000000..a9af4f1
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_tap.c
@@ -0,0 +1,46 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_tap_in(u3_noun a,
+ u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return b;
+ }
+ else {
+ u3_noun n_a, l_a, r_a;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+
+ return _tap_in(r_a,
+ u3nc(u3k(n_a),
+ _tap_in(l_a, b)));
+ }
+}
+
+u3_noun
+u3qdi_tap(u3_noun a)
+{
+ return _tap_in(a, u3_nul);
+}
+
+u3_noun
+u3wdi_tap(u3_noun cor)
+{
+ u3_noun a;
+ u3x_mean(cor, u3x_con_sam, &a, 0);
+ return u3qdi_tap(a);
+}
+
+u3_noun
+u3kdi_tap(u3_noun a)
+{
+ u3_noun b = u3qdi_tap(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/d/in_uni.c b/vere/pkg/noun/jets/d/in_uni.c
new file mode 100644
index 0000000..504ddcb
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_uni.c
@@ -0,0 +1,98 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* internal functions
+*/
+static u3_noun
+_in_uni(u3_noun a, u3_noun b)
+{
+ if ( u3_nul == a ) {
+ return u3k(b);
+ }
+ else if ( u3_nul == b ) {
+ return u3k(a);
+ }
+ else {
+ u3_noun n_a, l_a, r_a,
+ n_b, l_b, r_b,
+ neb, sub, naw, pro;
+ u3x_trel(a, &n_a, &l_a, &r_a);
+ u3x_trel(b, &n_b, &l_b, &r_b);
+
+ if ( c3n == u3qc_mor(n_a, n_b) ) {
+ if ( c3y == u3r_sing(n_a, n_b) ) {
+ return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b));
+ }
+ else if ( c3y == u3qc_gor(n_a, n_b) ) {
+ naw = u3nt(u3k(n_a), u3k(l_a), u3_nul);
+ sub = _in_uni(naw, l_b);
+ neb = u3nt(u3k(n_b), sub, u3k(r_b));
+ pro = _in_uni(r_a, neb);
+ u3z(naw); u3z(neb);
+ return pro;
+ }
+ else {
+ naw = u3nt(u3k(n_a), u3_nul, u3k(r_a));
+ sub = _in_uni(naw, r_b);
+ neb = u3nt(u3k(n_b), u3k(l_b), sub);
+ pro = _in_uni(l_a, neb);
+ u3z(naw); u3z(neb);
+ return pro;
+ }
+ }
+ else if ( c3y == u3r_sing(n_b, n_a) ) {
+ return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b));
+ }
+ else if ( c3y == u3qc_gor(n_b, n_a) ) {
+ neb = u3nt(u3k(n_b), u3k(l_b), u3_nul);
+ sub = _in_uni(l_a, neb);
+ naw = u3nt(u3k(n_a), sub, u3k(r_a));
+ pro = _in_uni(naw, r_b);
+ u3z(neb); u3z(naw);
+ return pro;
+ }
+ else {
+ neb = u3nt(u3k(n_b), u3_nul, u3k(r_b));
+ sub = _in_uni(r_a, neb);
+ naw = u3nt(u3k(n_a), u3k(l_a), sub);
+ pro = _in_uni(naw, l_b);
+ u3z(neb); u3z(naw);
+ return pro;
+ }
+ }
+}
+
+u3_noun
+u3kdi_uni(u3_noun a,
+ u3_noun b)
+{
+ u3_noun c = u3qdi_uni(a, b);
+ u3z(a); u3z(b);
+ return c;
+}
+
+u3_noun
+u3qdi_uni(u3_noun a,
+ u3_noun b)
+{
+ if ( c3y == u3r_sing(a, b) ) {
+ return u3k(a);
+ }
+ else {
+ return _in_uni(a, b);
+ }
+}
+
+u3_noun
+u3wdi_uni(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0);
+ return u3qdi_uni(a, b);
+}
+
diff --git a/vere/pkg/noun/jets/d/in_wyt.c b/vere/pkg/noun/jets/d/in_wyt.c
new file mode 100644
index 0000000..2ae72fa
--- /dev/null
+++ b/vere/pkg/noun/jets/d/in_wyt.c
@@ -0,0 +1,35 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+STATIC_ASSERT( (UINT32_MAX > u3a_cells),
+ "width precision" );
+
+static c3_w
+_wyt_in(u3_noun a)
+{
+ if ( u3_nul == a ) {
+ return 0;
+ }
+ else {
+ u3_noun l_a, r_a;
+ u3x_trel(a, 0, &l_a, &r_a);
+
+ return 1 + _wyt_in(l_a) + _wyt_in(r_a);
+ }
+}
+
+u3_noun
+u3qdi_wyt(u3_noun a)
+{
+ return u3i_word(_wyt_in(a));
+}
+
+u3_noun
+u3wdi_wyt(u3_noun cor)
+{
+ return u3qdi_wyt(u3x_at(u3x_con_2, cor));
+}
diff --git a/vere/pkg/noun/jets/e/adler.c b/vere/pkg/noun/jets/e/adler.c
new file mode 100644
index 0000000..d7e1211
--- /dev/null
+++ b/vere/pkg/noun/jets/e/adler.c
@@ -0,0 +1,127 @@
+#include <imprison.h>
+#include <jets/k.h>
+#include <log.h>
+#include <nock.h>
+#include <retrieve.h>
+#include <types.h>
+#include <xtract.h>
+
+static void _x_octs(u3_noun octs, u3_atom* p_octs, u3_atom* q_octs) {
+
+ if (c3n == u3r_mean(octs,
+ 2, p_octs,
+ 3, q_octs, 0)){
+ u3m_bail(c3__exit);
+ }
+
+ if (c3n == u3a_is_atom(*p_octs) ||
+ c3n == u3a_is_atom(*q_octs)) {
+ u3m_bail(c3__exit);
+ }
+}
+
+static c3_o _x_octs_buffer(u3_atom* p_octs, u3_atom *q_octs,
+ c3_w* p_octs_w, c3_y** buf_y,
+ c3_w* len_w, c3_w* lead_w)
+{
+ if (c3n == u3r_safe_word(*p_octs, p_octs_w)) {
+ return c3n;
+ }
+
+ *len_w = u3r_met(3, *q_octs);
+
+ if (c3y == u3a_is_cat(*q_octs)) {
+ *buf_y = (c3_y*)q_octs;
+ }
+ else {
+ u3a_atom* ptr_a = u3a_to_ptr(*q_octs);
+ *buf_y = (c3_y*)ptr_a->buf_w;
+ }
+
+ *lead_w = 0;
+
+ if (*p_octs_w > *len_w) {
+ *lead_w = *p_octs_w - *len_w;
+ }
+ else {
+ *len_w = *p_octs_w;
+ }
+
+ return c3y;
+}
+
+#define BASE 65521
+#define NMAX 5552
+
+u3_noun _qe_adler32(u3_noun octs)
+{
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w, len_w, lead_w;
+ c3_y *buf_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &buf_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ c3_w adler_w, sum2_w;
+
+ adler_w = 0x1;
+ sum2_w = 0x0;
+
+ c3_w pos_w = 0;
+
+ // Process all non-zero bytes
+ //
+ while (pos_w < len_w) {
+
+ c3_w rem_w = (len_w - pos_w);
+
+ if (rem_w > NMAX) {
+ rem_w = NMAX;
+ }
+
+ while (rem_w--) {
+ adler_w += *(buf_y + pos_w++);
+ sum2_w += adler_w;
+ }
+
+ adler_w %= BASE;
+ sum2_w %= BASE;
+ }
+
+ // Process leading zeros
+ //
+ while (pos_w < p_octs_w) {
+
+ c3_w rem_w = (p_octs_w - pos_w);
+
+ if (rem_w > NMAX) {
+ rem_w = NMAX;
+ }
+
+ // leading zeros: adler sum is unchanged
+ sum2_w += rem_w*adler_w;
+ pos_w += rem_w;
+
+ adler_w %= BASE;
+ sum2_w %= BASE;
+ }
+
+ return u3i_word(sum2_w << 16 | adler_w);
+}
+
+
+u3_noun
+u3we_adler32(u3_noun cor)
+{
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam, &octs, 0);
+
+ return _qe_adler32(octs);
+}
diff --git a/vere/pkg/noun/jets/e/aes_cbc.c b/vere/pkg/noun/jets/e/aes_cbc.c
new file mode 100644
index 0000000..f5369e0
--- /dev/null
+++ b/vere/pkg/noun/jets/e/aes_cbc.c
@@ -0,0 +1,182 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+/* All of the CBC hoon truncates its key and prv inputs by passing them to
+ * the ECB functions, which truncate them, hence the raw u3r_bytes unpacking.
+ */
+
+typedef int (*urcrypt_cbc)(c3_y**,
+ size_t*,
+ c3_y*,
+ c3_y*,
+ urcrypt_realloc_t);
+
+ static u3_atom
+ _cqea_cbc_help(c3_y* key_y, u3_atom iv, u3_atom msg, urcrypt_cbc low_f)
+ {
+ u3_atom ret;
+ c3_w met_w;
+ c3_y iv_y[16];
+ c3_y* msg_y = u3r_bytes_all(&met_w, msg);
+ size_t len = met_w;
+
+ u3r_bytes(0, 16, iv_y, iv);
+ if ( 0 != (*low_f)(&msg_y, &len, key_y, iv_y, &u3a_realloc) ) {
+ ret = u3_none;
+ }
+ else {
+ ret = u3i_bytes(len, msg_y);
+ }
+ u3a_free(msg_y);
+
+ return ret;
+ }
+
+ static u3_atom
+ _cqea_cbca_en(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[16];
+ u3r_bytes(0, 16, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_en);
+ }
+
+ u3_noun
+ u3wea_cbca_en(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbca-en", _cqea_cbca_en(a, b, c));
+ }
+ }
+
+ static u3_atom
+ _cqea_cbca_de(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[16];
+ u3r_bytes(0, 16, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_de);
+ }
+
+ u3_noun
+ u3wea_cbca_de(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbca-de", _cqea_cbca_de(a, b, c));
+ }
+ }
+
+ static u3_atom
+ _cqea_cbcb_en(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[24];
+ u3r_bytes(0, 24, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_en);
+ }
+
+ u3_noun
+ u3wea_cbcb_en(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbcb-en", _cqea_cbcb_en(a, b, c));
+ }
+ }
+
+ static u3_atom
+ _cqea_cbcb_de(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[24];
+ u3r_bytes(0, 24, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_de);
+ }
+
+ u3_noun
+ u3wea_cbcb_de(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbcb-de", _cqea_cbcb_de(a, b, c));
+ }
+ }
+
+ static u3_atom
+ _cqea_cbcc_en(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_en);
+ }
+
+ u3_noun
+ u3wea_cbcc_en(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbcc-en", _cqea_cbcc_en(a, b, c));
+ }
+ }
+
+ static u3_atom
+ _cqea_cbcc_de(u3_atom key,
+ u3_atom iv,
+ u3_atom msg)
+ {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_de);
+ }
+
+ u3_noun
+ u3wea_cbcc_de(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("cbcc-de", _cqea_cbcc_de(a, b, c));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/aes_ecb.c b/vere/pkg/noun/jets/e/aes_ecb.c
new file mode 100644
index 0000000..eff536d
--- /dev/null
+++ b/vere/pkg/noun/jets/e/aes_ecb.c
@@ -0,0 +1,166 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+typedef int (*urcrypt_ecb)(c3_y*, c3_y[16], c3_y[16]);
+
+
+ /* All of the ECB hoon truncates its key and blk inputs with +fe, in these
+ * jets we unpack with an unconditional u3r_bytes */
+
+ static u3_atom
+ _cqea_ecb_help(c3_y* key_y, u3_atom blk, urcrypt_ecb low_f)
+ {
+ c3_y blk_y[16], out_y[16];
+
+ u3r_bytes(0, 16, blk_y, blk);
+
+ if ( 0 != (*low_f)(key_y, blk_y, out_y) ) {
+ return u3_none;
+ }
+ else {
+ return u3i_bytes(16, out_y);
+ }
+ }
+
+ static u3_atom
+ _cqea_ecba_en(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[16];
+ u3r_bytes(0, 16, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_en);
+ }
+
+ u3_noun
+ u3wea_ecba_en(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecba-en", _cqea_ecba_en(a, b));
+ }
+ }
+
+ static u3_atom
+ _cqea_ecba_de(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[16];
+ u3r_bytes(0, 16, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_de);
+ }
+
+ u3_noun
+ u3wea_ecba_de(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecba-de", _cqea_ecba_de(a, b));
+ }
+ }
+
+ static u3_atom
+ _cqea_ecbb_en(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[24];
+ u3r_bytes(0, 24, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_en);
+ }
+
+ u3_noun
+ u3wea_ecbb_en(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecbb-en", _cqea_ecbb_en(a, b));
+ }
+ }
+
+ static u3_atom
+ _cqea_ecbb_de(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[24];
+ u3r_bytes(0, 24, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_de);
+ }
+
+ u3_noun
+ u3wea_ecbb_de(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecbb-de", _cqea_ecbb_de(a, b));
+ }
+ }
+
+ static u3_atom
+ _cqea_ecbc_en(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_en);
+ }
+
+ u3_noun
+ u3wea_ecbc_en(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecbc-en", _cqea_ecbc_en(a, b));
+ }
+ }
+
+ static u3_atom
+ _cqea_ecbc_de(u3_atom key,
+ u3_atom blk)
+ {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_de);
+ }
+
+ u3_noun
+ u3wea_ecbc_de(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("ecbc-de", _cqea_ecbc_de(a, b));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/aes_siv.c b/vere/pkg/noun/jets/e/aes_siv.c
new file mode 100644
index 0000000..f88ba6a
--- /dev/null
+++ b/vere/pkg/noun/jets/e/aes_siv.c
@@ -0,0 +1,370 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+typedef int (*urcrypt_siv)(c3_y*, size_t,
+ urcrypt_aes_siv_data*, size_t,
+ c3_y*, c3_y[16], c3_y*);
+
+
+// soc_w = number of items
+// mat_w = size in bytes of assoc array
+// dat_w = size of allocation (array + atom storage)
+static void
+_cqea_measure_ads(u3_noun ads, c3_w* soc_w, c3_w *mat_w, c3_w *dat_w)
+{
+ u3_noun i, t;
+ c3_w a_w, b_w, tmp_w;
+
+ for ( a_w = b_w = 0, t = ads; u3_nul != t; ++a_w ) {
+ u3x_cell(t, &i, &t);
+ if ( c3n == u3ud(i) ) {
+ u3m_bail(c3__exit);
+ return;
+ }
+ else {
+ tmp_w = b_w;
+ b_w += u3r_met(3, i);
+ if ( b_w < tmp_w ) {
+ u3m_bail(c3__fail);
+ return;
+ }
+ }
+ }
+
+ // check for size overflows
+ tmp_w = a_w * sizeof(urcrypt_aes_siv_data);
+ if ( (tmp_w / a_w) != sizeof(urcrypt_aes_siv_data) ) {
+ u3m_bail(c3__fail);
+ }
+ else if ( (*dat_w = tmp_w + b_w) < tmp_w ) {
+ u3m_bail(c3__fail);
+ }
+ else {
+ *soc_w = a_w;
+ *mat_w = tmp_w;
+ }
+}
+
+// assumes ads is a valid (list @) because it's already been measured
+static void
+_cqea_encode_ads(u3_noun ads,
+ c3_w mat_w,
+ urcrypt_aes_siv_data *dat_u)
+{
+ c3_w met_w;
+ u3_noun i, t;
+ urcrypt_aes_siv_data *cur_u;
+ c3_y *dat_y = ((c3_y*) dat_u) + mat_w;
+
+ for ( cur_u = dat_u, t = ads; u3_nul != t; t = u3t(t), ++cur_u ) {
+ i = u3h(t);
+ met_w = u3r_met(3, i);
+ u3r_bytes(0, met_w, dat_y, i);
+ cur_u->length = met_w;
+ cur_u->bytes = dat_y;
+ dat_y += met_w;
+ }
+}
+
+static void
+_cqea_ads_free(urcrypt_aes_siv_data *dat_u)
+{
+ if ( NULL != dat_u ) {
+ u3a_free(dat_u);
+ }
+}
+
+static urcrypt_aes_siv_data*
+_cqea_ads_alloc(u3_noun ads, c3_w *soc_w)
+{
+ if ( !ads ) {
+ *soc_w = 0;
+ return NULL;
+ }
+ else {
+ c3_w mat_w, dat_w;
+ urcrypt_aes_siv_data *dat_u;
+
+ _cqea_measure_ads(ads, soc_w, &mat_w, &dat_w);
+ dat_u = u3a_malloc(dat_w);
+ _cqea_encode_ads(ads, mat_w, dat_u);
+ return dat_u;
+ }
+}
+
+static u3_noun
+_cqea_siv_en(c3_y* key_y,
+ c3_w key_w,
+ u3_noun ads,
+ u3_atom txt,
+ urcrypt_siv low_f)
+{
+ u3_noun ret;
+ c3_w txt_w, soc_w;
+ c3_y *txt_y, *out_y, iv_y[16];
+ urcrypt_aes_siv_data *dat_u;
+
+ dat_u = _cqea_ads_alloc(ads, &soc_w);
+ txt_y = u3r_bytes_all(&txt_w, txt);
+ out_y = u3a_malloc(txt_w);
+
+ ret = ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) )
+ ? u3_none
+ : u3nt(u3i_bytes(16, iv_y),
+ u3i_words(1, &txt_w),
+ u3i_bytes(txt_w, out_y));
+
+ u3a_free(txt_y);
+ u3a_free(out_y);
+ _cqea_ads_free(dat_u);
+ return ret;
+}
+
+static u3_noun
+_cqea_siv_de(c3_y* key_y,
+ c3_w key_w,
+ u3_noun ads,
+ u3_atom iv,
+ u3_atom len,
+ u3_atom txt,
+ urcrypt_siv low_f)
+{
+ c3_w txt_w;
+ if ( !u3r_word_fit(&txt_w, len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun ret;
+ c3_w soc_w;
+ c3_y *txt_y, *out_y, iv_y[16];
+ urcrypt_aes_siv_data *dat_u;
+
+ u3r_bytes(0, 16, iv_y, iv);
+ dat_u = _cqea_ads_alloc(ads, &soc_w);
+ txt_y = u3r_bytes_alloc(0, txt_w, txt);
+ out_y = u3a_malloc(txt_w);
+
+ if ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) ) {
+ return u3m_bail(c3__evil);
+ }
+
+ ret = u3nc(0, u3i_bytes(txt_w, out_y));
+
+ u3a_free(txt_y);
+ u3a_free(out_y);
+ _cqea_ads_free(dat_u);
+
+ return ret;
+ }
+}
+
+// the siv* hoon doesn't explicitly check keysizes, but all of these functions
+// have fixed maximum keysizes, so we will punt if we get a key that is too
+// large.
+
+static u3_noun
+_cqea_siva_en(u3_atom key,
+ u3_noun ads,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 32 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_siv_en(key_y, 32, ads, txt, &urcrypt_aes_siva_en);
+ }
+}
+
+u3_noun
+u3wea_siva_en(u3_noun cor)
+{
+ u3_noun key, ads, txt;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("siva-en", _cqea_siva_en(key, ads, txt));
+ }
+}
+
+static u3_noun
+_cqea_siva_de(u3_atom key,
+ u3_noun ads,
+ u3_atom iv,
+ u3_atom len,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 32 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ return _cqea_siv_de(key_y, 32, ads, iv, len, txt, &urcrypt_aes_siva_de);
+ }
+}
+
+u3_noun
+u3wea_siva_de(u3_noun cor)
+{
+ u3_noun key, ads, iv, len, txt;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &iv,
+ u3x_sam_6, &len,
+ u3x_sam_7, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("siva-de", _cqea_siva_de(key, ads, iv, len, txt));
+ }
+}
+
+static u3_noun
+_cqea_sivb_en(u3_atom key,
+ u3_noun ads,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 48 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[48];
+ u3r_bytes(0, 48, key_y, key);
+ return _cqea_siv_en(key_y, 48, ads, txt, &urcrypt_aes_sivb_en);
+ }
+}
+
+
+u3_noun
+u3wea_sivb_en(u3_noun cor)
+{
+ u3_noun key, ads, txt;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("sivb-en", _cqea_sivb_en(key, ads, txt));
+ }
+}
+
+static u3_noun
+_cqea_sivb_de(u3_atom key,
+ u3_noun ads,
+ u3_atom iv,
+ u3_atom len,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 48 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[48];
+ u3r_bytes(0, 48, key_y, key);
+ return _cqea_siv_de(key_y, 48, ads, iv, len, txt, &urcrypt_aes_sivb_de);
+ }
+}
+
+u3_noun
+u3wea_sivb_de(u3_noun cor)
+{
+ u3_noun key, ads, iv, len, txt;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &iv,
+ u3x_sam_6, &len,
+ u3x_sam_7, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("sivb-de", _cqea_sivb_de(key, ads, iv, len, txt));
+ }
+}
+
+static u3_noun
+_cqea_sivc_en(u3_atom key,
+ u3_noun ads,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 64 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[64];
+ u3r_bytes(0, 64, key_y, key);
+ return _cqea_siv_en(key_y, 64, ads, txt, &urcrypt_aes_sivc_en);
+ }
+}
+
+u3_noun
+u3wea_sivc_en(u3_noun cor)
+{
+ u3_noun key, ads, txt;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("sivc-en", _cqea_sivc_en(key, ads, txt));
+ }
+}
+
+static u3_noun
+_cqea_sivc_de(u3_atom key,
+ u3_noun ads,
+ u3_atom iv,
+ u3_atom len,
+ u3_atom txt)
+{
+ if ( u3r_met(3, key) > 64 ) {
+ return u3_none;
+ }
+ else {
+ c3_y key_y[64];
+ u3r_bytes(0, 64, key_y, key);
+ return _cqea_siv_de(key_y, 64, ads, iv, len, txt, &urcrypt_aes_sivc_de);
+ }
+}
+
+u3_noun
+u3wea_sivc_de(u3_noun cor)
+{
+ u3_noun key, ads, iv, len, txt;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &iv,
+ u3x_sam_6, &len,
+ u3x_sam_7, &txt,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &ads, 0) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(txt) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("sivc-de", _cqea_sivc_de(key, ads, iv, len, txt));
+ }
+}
diff --git a/vere/pkg/noun/jets/e/argon2.c b/vere/pkg/noun/jets/e/argon2.c
new file mode 100644
index 0000000..e52d42c
--- /dev/null
+++ b/vere/pkg/noun/jets/e/argon2.c
@@ -0,0 +1,151 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+/* helpers
+*/
+
+ static int
+ argon2_alloc(uint8_t** output, size_t bytes)
+ {
+ *output = u3a_malloc(bytes);
+ return 1;
+ }
+
+ static void
+ argon2_free(uint8_t* memory, size_t bytes)
+ {
+ u3a_free(memory);
+ }
+
+ static c3_t
+ _cqear_unpack_type(c3_y* out, u3_atom in)
+ {
+ switch ( in ) {
+ default:
+ return 0;
+ case c3__d:
+ *out = urcrypt_argon2_d;
+ return 1;
+ case c3__i:
+ *out = urcrypt_argon2_i;
+ return 1;
+ case c3__id:
+ *out = urcrypt_argon2_id;
+ return 1;
+ case c3__u:
+ *out = urcrypt_argon2_u;
+ return 1;
+ }
+ }
+
+
+ static u3_atom
+ _cqe_argon2( // configuration params,
+ u3_atom out, u3_atom type, u3_atom version,
+ u3_atom threads, u3_atom mem_cost, u3_atom time_cost,
+ u3_atom wik, u3_atom key, u3_atom wix, u3_atom extra,
+ // input params
+ u3_atom wid, u3_atom dat, u3_atom wis, u3_atom sat )
+ {
+ c3_y typ_u;
+ c3_w out_w, wik_w, wix_w, wid_w, wis_w, ver_w, ted_w, mem_w, tim_w;
+
+ if ( !(u3r_word_fit(&out_w, out) &&
+ u3r_word_fit(&wik_w, wik) &&
+ u3r_word_fit(&wix_w, wix) &&
+ u3r_word_fit(&wid_w, wid) &&
+ u3r_word_fit(&wis_w, wis)) ) {
+ // too big to allocate
+ return u3m_bail(c3__fail);
+ }
+ else if ( !(_cqear_unpack_type(&typ_u, type) &&
+ u3r_word_fit(&ver_w, version) &&
+ u3r_word_fit(&ted_w, threads) &&
+ u3r_word_fit(&mem_w, mem_cost) &&
+ u3r_word_fit(&tim_w, time_cost)) ) {
+ return u3_none;
+ }
+ else {
+ u3_atom ret;
+ c3_y *key_y = u3r_bytes_alloc(0, wik_w, key),
+ *ex_y = u3r_bytes_alloc(0, wix_w, extra),
+ *dat_y = u3r_bytes_alloc(0, wid_w, dat),
+ *sat_y = u3r_bytes_alloc(0, wis_w, sat),
+ *out_y = u3a_malloc(out_w);
+
+ const c3_c* err_c = urcrypt_argon2(
+ typ_u, ver_w, ted_w, mem_w, tim_w,
+ wik_w, key_y,
+ wix_w, ex_y,
+ wid_w, dat_y,
+ wis_w, sat_y,
+ out_w, out_y,
+ &argon2_alloc,
+ &argon2_free);
+
+ u3a_free(key_y);
+ u3a_free(ex_y);
+ u3a_free(dat_y);
+ u3a_free(sat_y);
+
+ if ( NULL == err_c ) {
+ ret = u3i_bytes(out_w, out_y);
+ }
+ else {
+ ret = u3_none;
+ u3l_log("argon2-error: %s", err_c);
+ }
+
+ u3a_free(out_y);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_argon2(u3_noun cor)
+ {
+ u3_noun // configuration params
+ out, type, version,
+ threads, mem_cost, time_cost,
+ wik, key, wix, extra,
+ // input params
+ wid, dat, wis, sat,
+ // for use during unpacking
+ wmsg, wsat, arg, brg, wkey, wext;
+
+ // the hoon code for argon2 takes configuration parameters,
+ // and then produces a gate. we jet that inner gate.
+ // this does mean that the config params have gotten buried
+ // pretty deep in the subject, hence the +510.
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &wmsg,
+ u3x_sam_3, &wsat,
+ 510, &arg, 0) ||
+ u3r_cell(wmsg, &wid, &dat) || u3ud(wid) || u3ud(dat) ||
+ u3r_cell(wsat, &wis, &sat) || u3ud(wis) || u3ud(sat) ||
+ //
+ u3r_qual(arg, &out, &type, &version, &brg) ||
+ u3ud(out) || u3ud(type) || u3ud(version) ||
+ //
+ u3r_qual(brg, &threads, &mem_cost, &time_cost, &arg) ||
+ u3ud(threads) || u3ud(mem_cost) || u3ud(time_cost) ||
+ //
+ u3r_cell(arg, &wkey, &wext) ||
+ u3r_cell(wkey, &wik, &key) || u3ud(wik) || u3ud(key) ||
+ u3r_cell(wext, &wix, &extra) || u3ud(wix) || u3ud(extra)
+ )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("argon2",
+ _cqe_argon2(out, type, version,
+ threads, mem_cost, time_cost,
+ wik, key, wix, extra,
+ wid, dat, wis, sat));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/base.c b/vere/pkg/noun/jets/e/base.c
new file mode 100644
index 0000000..8bbc761
--- /dev/null
+++ b/vere/pkg/noun/jets/e/base.c
@@ -0,0 +1,152 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_en_base16(u3_atom len, u3_atom dat)
+{
+ if ( c3n == u3a_is_cat(len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_w len_w = (c3_w)len;
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 4, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ {
+ c3_y* buf_y = sab_u.buf_y;
+ c3_y inp_y;
+
+ while ( len_w-- ) {
+ inp_y = u3r_byte(len_w, dat);
+
+ *buf_y++ = u3s_dit_y[inp_y >> 4];
+ *buf_y++ = u3s_dit_y[inp_y & 0xf];
+ }
+ }
+
+ return u3i_slab_moot_bytes(&sab_u);
+ }
+}
+
+static inline c3_o
+_of_hex_digit(c3_y inp_y, c3_y* out_y)
+{
+ if ( inp_y >= '0' && inp_y <= '9' ) {
+ *out_y = inp_y - '0';
+ return c3y;
+ }
+ else if ( inp_y >= 'a' && inp_y <= 'f' ) {
+ *out_y = inp_y - 87;
+ return c3y;
+ }
+ else if ( inp_y >= 'A' && inp_y <= 'F' ) {
+ *out_y = inp_y - 55;
+ return c3y;
+ }
+
+ return c3n;
+}
+
+static inline c3_o
+_of_hex_odd(u3_atom inp, c3_w len_w, c3_w byt_w, c3_y* buf_y)
+{
+ c3_y low_y, hig_y, lit_y, hit_y;
+
+ hig_y = u3r_byte(--byt_w, inp);
+
+ while ( --len_w ) {
+ low_y = u3r_byte(--byt_w, inp);
+
+ if ( (c3n == _of_hex_digit(low_y, &lit_y))
+ || (c3n == _of_hex_digit(hig_y, &hit_y)) )
+ {
+ return c3n;
+ }
+ else {
+ *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4);
+ }
+
+ hig_y = u3r_byte(--byt_w, inp);
+ }
+
+ if ( c3n == _of_hex_digit(hig_y, &hit_y) ) {
+ return c3n;
+ }
+ else {
+ *buf_y = hit_y & 0xf;
+ }
+
+ return c3y;
+}
+
+static inline c3_o
+_of_hex_even(u3_atom inp, c3_w len_w, c3_y* buf_y)
+{
+ c3_y lit_y, hit_y;
+ c3_s inp_s;
+
+ while ( len_w-- ) {
+ inp_s = u3r_short(len_w, inp);
+
+ if ( (c3n == _of_hex_digit(inp_s & 0xff, &lit_y))
+ || (c3n == _of_hex_digit(inp_s >> 8, &hit_y)) )
+ {
+ return c3n;
+ }
+ else {
+ *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4);
+ }
+ }
+
+ return c3y;
+}
+
+u3_noun
+u3qe_de_base16(u3_atom inp)
+{
+ c3_w len_w = u3r_met(4, inp);
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 3, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ // even byte-length input can be parsed in aligned, 16-bit increments,
+ // but odd byte-length input cannot, and is expressed more simply in bytes.
+ //
+ {
+ c3_w byt_w = u3r_met(3, inp);
+ c3_o ret_o = ( byt_w & 1 )
+ ? _of_hex_odd(inp, len_w, byt_w, sab_u.buf_y)
+ : _of_hex_even(inp, len_w, sab_u.buf_y);
+
+ if ( c3n == ret_o ) {
+ u3i_slab_free(&sab_u);
+ return u3_nul;
+ }
+ else {
+ u3_noun dat = u3i_slab_mint_bytes(&sab_u);
+ return u3nt(u3_nul, u3i_word(len_w), dat);
+ }
+ }
+}
+
+u3_noun
+u3we_en_base16(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qe_en_base16(u3x_atom(a), u3x_atom(b));
+}
+
+u3_noun
+u3we_de_base16(u3_noun cor)
+{
+ u3_noun sam = u3x_at(u3x_sam, cor);
+ return u3qe_de_base16(u3x_atom(sam));
+}
diff --git a/vere/pkg/noun/jets/e/blake.c b/vere/pkg/noun/jets/e/blake.c
new file mode 100644
index 0000000..cac4c48
--- /dev/null
+++ b/vere/pkg/noun/jets/e/blake.c
@@ -0,0 +1,163 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqe_blake2b(u3_atom wid, u3_atom dat,
+ u3_atom wik, u3_atom dak,
+ u3_atom out)
+ {
+ c3_w wid_w;
+ if ( !u3r_word_fit(&wid_w, wid) ) {
+ // impossible to represent an atom this large
+ return u3m_bail(c3__fail);
+ }
+ else {
+ // the hoon adjusts these widths to its liking
+ int err;
+ c3_y out_y[64], dak_y[64];
+ c3_w wik_w = c3_min(wik, 64),
+ out_w = c3_max(1, c3_min(out, 64));
+ c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat);
+
+ u3r_bytes(0, wik_w, dak_y, dak);
+ err = urcrypt_blake2(wid_w, dat_y, wik_w, dak_y, out_w, out_y);
+ u3a_free(dat_y);
+
+ if ( 0 == err ) {
+ return u3i_bytes(out_w, out_y);
+ }
+ else {
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3we_blake2b(u3_noun cor)
+ {
+ u3_noun msg, key, out, // arguments
+ wid, dat, // destructured msg
+ wik, dak; // destructured key
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &msg,
+ u3x_sam_6, &key,
+ u3x_sam_7, &out, 0) ||
+ u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) ||
+ u3r_cell(key, &wik, &dak) || u3ud(wik) || u3ud(dak) ||
+ u3ud(out) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("blake2b", _cqe_blake2b(wid, dat, wik, dak, out));
+ }
+ }
+
+ static u3_atom
+ _cqe_blake3_hash(u3_atom wid, u3_atom dat,
+ u3_atom key, u3_atom flags, u3_atom out)
+ {
+ c3_w wid_w, out_w;
+ if ( !u3r_word_fit(&wid_w, wid) || !u3r_word_fit(&out_w, out) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y key_y[32];
+ u3r_bytes(0, 32, key_y, key);
+ c3_y flags_y = u3r_byte(0, flags);
+ c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat);
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 3, out_w);
+ c3_y* out_y = sab_u.buf_y;
+ urcrypt_blake3_hash(wid_w, dat_y, key_y, flags_y, out, out_y);
+ u3a_free(dat_y);
+ return u3i_slab_mint(&sab_u);
+ }
+ }
+
+ u3_noun
+ u3we_blake3_hash(u3_noun cor)
+ {
+ u3_noun out, msg, // arguments
+ wid, dat, // destructured msg
+ sam, key, flags; // context
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &out,
+ u3x_sam_3, &msg,
+ u3x_con_sam, &sam, 0) ||
+ u3ud(out) ||
+ u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) ||
+ u3r_cell(sam, &key, &flags) || u3ud(key) || u3ud(flags) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("blake3_hash", _cqe_blake3_hash(wid, dat, key, flags, out));
+ }
+ }
+
+ static u3_noun
+ _cqe_blake3_chunk_output(u3_atom wid, u3_atom dat, u3_atom cv, u3_atom counter, u3_atom flags)
+ {
+ c3_w wid_w;
+ if ( !u3r_word_fit(&wid_w, wid) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ c3_y cv_y[32], block_y[64], block_len;
+ c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat);
+ c3_d counter_d = u3r_chub(0, counter);
+ c3_y flags_y = u3r_byte(0, flags);
+ u3r_bytes(0, 32, cv_y, cv);
+ urcrypt_blake3_chunk_output(wid_w, dat_y, cv_y, block_y, &block_len, &counter_d, &flags_y);
+ return u3i_cell(u3i_bytes(32, cv_y), u3i_qual(u3k(counter), u3i_bytes(64, block_y), block_len, flags_y));
+ }
+ }
+
+ u3_noun
+ u3we_blake3_chunk_output(u3_noun cor)
+ {
+ u3_noun counter, msg, // arguments
+ wid, dat, // destructured msg
+ key, flags; // context
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &counter,
+ u3x_sam_3, &msg,
+ u3x_con_sam_2, &key,
+ u3x_con_sam_3, &flags, 0) ||
+ u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) ||
+ u3ud(key) || u3ud(flags))
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("blake3_chunk_output", _cqe_blake3_chunk_output(wid, dat, key, counter, flags));
+ }
+ }
+
+ static u3_atom
+ _cqe_blake3_compress(u3_atom cv, u3_atom counter,
+ u3_atom block, u3_atom block_len, u3_atom flags)
+ {
+ c3_y cv_y[32], block_y[64], out_y[64];
+ u3r_bytes(0, 32, cv_y, cv);
+ u3r_bytes(0, 64, block_y, block);
+ urcrypt_blake3_compress(cv_y, block_y, block_len, counter, flags, out_y);
+ return u3i_bytes(64, out_y);
+ }
+
+ u3_noun
+ u3we_blake3_compress(u3_noun cor)
+ {
+ u3_noun output = u3x_at(u3x_sam, cor);
+ u3_noun cv, counter, block, block_len, flags; // destructured output
+
+ if ( u3r_quil(output, &cv, &counter, &block, &block_len, &flags) ||
+ u3ud(cv) || u3ud(block) || u3ud(block_len) || u3ud(counter) || u3ud(flags))
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("blake3_compress", _cqe_blake3_compress(cv, counter, block, block_len, flags));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/bytestream.c b/vere/pkg/noun/jets/e/bytestream.c
new file mode 100644
index 0000000..71761e1
--- /dev/null
+++ b/vere/pkg/noun/jets/e/bytestream.c
@@ -0,0 +1,1247 @@
+#include <types.h>
+#include <imprison.h>
+#include <jets/k.h>
+#include <nock.h>
+#include <retrieve.h>
+#include <xtract.h>
+#include <log.h>
+
+// XX do not crash on indirect atoms, but default to Hoon
+// XX use u3i_word to imprison all indirect atoms
+//
+static void
+_x_octs(u3_noun octs, u3_atom* p_octs, u3_atom* q_octs) {
+
+ if (c3n == u3r_mean(octs,
+ 2, p_octs,
+ 3, q_octs, 0)){
+ u3m_bail(c3__exit);
+ }
+
+ if (c3n == u3a_is_atom(*p_octs) ||
+ c3n == u3a_is_atom(*q_octs)) {
+ u3m_bail(c3__exit);
+ }
+}
+static c3_o
+_x_octs_buffer(u3_atom* p_octs, u3_atom *q_octs,
+ c3_w* p_octs_w, c3_y** buf_y,
+ c3_w* len_w, c3_w* lead_w)
+{
+ if (c3n == u3r_safe_word(*p_octs, p_octs_w)) {
+ return c3n;
+ }
+
+ *len_w = u3r_met(3, *q_octs);
+
+ if (c3y == u3a_is_cat(*q_octs)) {
+ *buf_y = (c3_y*)q_octs;
+ }
+ else {
+ u3a_atom* ptr_a = u3a_to_ptr(*q_octs);
+ *buf_y = (c3_y*)ptr_a->buf_w;
+ }
+
+ *lead_w = 0;
+
+ if (*p_octs_w > *len_w) {
+ *lead_w = *p_octs_w - *len_w;
+ }
+ else {
+ *len_w = *p_octs_w;
+ }
+
+ return c3y;
+}
+
+u3_noun
+_qe_bytestream_rip_octs(u3_atom p_octs, u3_atom q_octs) {
+
+ c3_w p_octs_w, len_w, lead_w;
+ c3_y* buf_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &buf_y,
+ &len_w, &lead_w)){
+ return u3_none;
+ }
+
+ if (p_octs_w == 0) {
+ return u3_nul;
+ }
+
+ u3_noun rip = u3_nul;
+
+ while (lead_w--) {
+ rip = u3nc(0x0, rip);
+ }
+
+ buf_y += len_w - 1;
+
+ while (len_w--) {
+ rip = u3nc(*(buf_y--), rip);
+ }
+
+ return rip;
+}
+
+u3_noun
+u3we_bytestream_rip_octs(u3_noun cor){
+
+ u3_noun sam = u3x_at(u3x_sam, cor);
+
+ u3_atom p_octs, q_octs;
+ _x_octs(sam, &p_octs, &q_octs);
+
+ return _qe_bytestream_rip_octs(p_octs, q_octs);
+
+}
+
+u3_noun
+_qe_bytestream_cat_octs(u3_noun octs_a, u3_noun octs_b) {
+
+ u3_atom p_octs_a, p_octs_b;
+ u3_atom q_octs_a, q_octs_b;
+
+ _x_octs(octs_a, &p_octs_a, &q_octs_a);
+ _x_octs(octs_b, &p_octs_b, &q_octs_b);
+
+ c3_w p_octs_a_w, p_octs_b_w;
+ c3_w len_w, lem_w;
+ c3_w lead_w, leaf_w;
+
+ c3_y* sea_y;
+ c3_y* seb_y;
+
+ if (c3n == _x_octs_buffer(&p_octs_a, &q_octs_a,
+ &p_octs_a_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ if (c3n == _x_octs_buffer(&p_octs_b, &q_octs_b,
+ &p_octs_b_w, &seb_y,
+ &lem_w, &leaf_w)) {
+ return u3_none;
+ }
+
+ if (p_octs_a_w == 0) {
+ return u3k(octs_b);
+ }
+
+ if (p_octs_b_w == 0) {
+ return u3k(octs_a);
+ }
+
+ c3_d p_octs_d = p_octs_a_w + p_octs_b_w;
+
+ u3_noun ret;
+
+ // Both a and b are 0.
+ //
+ if (len_w == 0 && lem_w == 0) {
+ ret = u3nc(u3i_chub(p_octs_d), u3i_word(0));
+ }
+ else {
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 3, (c3_d)p_octs_a_w + lem_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ memcpy(sab_u.buf_y, sea_y, len_w);
+ memset(sab_u.buf_y + len_w, 0, lead_w);
+ memcpy(sab_u.buf_y + p_octs_a_w, seb_y, lem_w);
+
+ u3_noun q_octs = u3i_slab_moot(&sab_u);
+ ret = u3nc(u3i_chub(p_octs_d), q_octs);
+ }
+ return ret;
+}
+
+u3_noun
+u3we_bytestream_cat_octs(u3_noun cor) {
+
+ u3_noun octs_a, octs_b;
+
+ u3x_mean(cor, u3x_sam_2, &octs_a, u3x_sam_3, &octs_b, 0);
+
+ return _qe_bytestream_cat_octs(octs_a, octs_b);
+
+}
+
+u3_noun
+_qe_bytestream_can_octs(u3_noun octs_list) {
+
+ if (u3_nul == octs_list) {
+ return u3nc(0, 0);
+ }
+
+ if (u3_nul == u3t(octs_list)) {
+ return u3k(u3h(octs_list));
+ }
+
+ /* We can octs in two steps:
+ * first loop iteration computes the total required
+ * buffer size in bytes, factoring in the leading bytes
+ * of the final octs. The second loop iterates over each octs,
+ * copying the data to the output buffer.
+ */
+
+ // Compute total size
+ //
+ c3_d tot_d = 0;
+
+ u3_noun octs_list_start = octs_list;
+ u3_noun octs = u3_none;
+ // Last non-zero octs
+ u3_noun last_octs = u3_none;
+
+ while (octs_list != u3_nul) {
+
+ octs = u3h(octs_list);
+
+ if (c3n == u3a_is_atom(u3h(octs)) ||
+ c3n == u3a_is_atom(u3t(octs))) {
+ u3m_bail(c3__exit);
+ }
+ c3_w p_octs_w;
+
+ if (c3n == u3r_safe_word(u3h(octs), &p_octs_w)) {
+ u3z(octs_list);
+ return u3_none;
+ }
+ // Check for overflow
+ //
+ if ( p_octs_w > (UINT64_MAX - tot_d)){
+ return u3_none;
+ }
+ tot_d += p_octs_w;
+
+ octs_list = u3t(octs_list);
+ }
+
+ // Compute leading zeros of last non-zero octs -- the buffer
+ // size is decreased by this much.
+ //
+ // =leading-zeros (sub p.octs (met 3 q.octs))
+ //
+ // p.octs fits into a word -- this has been verified
+ // in the loop above.
+ //
+ // The resulting buf_len_w is correct only if the last
+ // octs is non-zero: but at the return u3i_slab_mint
+ // takes care of trimming.
+ //
+ c3_w last_lead_w = (u3r_word(0, u3h(octs)) - u3r_met(3, u3t(octs)));
+ c3_d buf_len_w = tot_d - last_lead_w;
+
+ if (buf_len_w == 0) {
+ return u3nc(u3i_word(tot_d), 0);
+ }
+
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 3, buf_len_w);
+ c3_y* buf_y = sab_u.buf_y;
+
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ c3_y* sea_y;
+ u3_atom p_octs, q_octs;
+ c3_w p_octs_w, q_octs_w;
+ c3_w len_w, lead_w;
+
+ // Bytes written so far
+ //
+ c3_d wit_d = 0;
+
+ octs_list = octs_list_start;
+
+ while (octs_list != u3_nul) {
+
+ octs = u3h(octs_list);
+
+ _x_octs(octs, &p_octs, &q_octs);
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)){
+ return u3_none;
+ }
+
+ if (p_octs_w == 0) {
+ octs_list = u3t(octs_list);
+ continue;
+ }
+
+ memcpy(buf_y, sea_y, len_w);
+ buf_y += len_w;
+ wit_d += len_w;
+
+ // More bytes to follow, write leading zeros
+ //
+ if (wit_d < buf_len_w) {
+ memset(buf_y, 0, lead_w);
+ buf_y += lead_w;
+ wit_d += lead_w;
+ }
+
+ octs_list = u3t(octs_list);
+ }
+
+ u3_assert((buf_y - sab_u.buf_y) == buf_len_w);
+
+ return u3nc(u3i_chub(tot_d), u3i_slab_mint(&sab_u));
+}
+
+u3_noun
+u3we_bytestream_can_octs(u3_noun cor)
+{
+ u3_noun octs_list;
+
+ u3x_mean(cor, u3x_sam_1, &octs_list, 0);
+
+ return _qe_bytestream_can_octs(octs_list);
+}
+u3_noun
+_qe_bytestream_skip_line(u3_atom pos, u3_noun octs)
+{
+ c3_w pos_w;
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ while (pos_w < len_w) {
+ if (*(sea_y + pos_w) == '\n') {
+ break;
+ }
+ pos_w++;
+ }
+ // Newline not found, position at the end
+ if (*(sea_y + pos_w) != '\n') {
+ pos_w = p_octs;
+ }
+ else {
+ pos_w++;
+ }
+
+ return u3nc(u3i_word(pos_w), u3k(octs));
+}
+u3_noun
+u3we_bytestream_skip_line(u3_noun cor)
+{
+
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &pos, u3x_sam_3, &octs, 0);
+
+ return _qe_bytestream_skip_line(pos, octs);
+
+}
+u3_noun
+_qe_bytestream_find_byte(u3_atom bat, u3_atom pos, u3_noun octs)
+{
+ c3_w bat_w, pos_w;
+
+ if (c3n == u3r_safe_word(bat, &bat_w) || bat_w > 0xff) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ while (pos_w < len_w) {
+
+ if (*(sea_y + pos_w) == bat_w) {
+ return u3nc(u3_nul, u3i_word(pos_w));
+ }
+
+ pos_w++;
+ }
+ // Here we are sure that:
+ // (1) bat_w has not been found
+ // (2) therefore pos_w == len_w
+ //
+ // If bat_w == 0, and there is still input
+ // in the stream, it means pos_w points at
+ // the first leading zero.
+ //
+ if (pos_w < p_octs && bat_w == 0) {
+ return u3nc(u3_nul, u3i_word(pos_w));
+ }
+
+ return u3_nul;
+}
+u3_noun
+u3we_bytestream_find_byte(u3_noun cor)
+{
+ u3_atom bat;
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &bat,
+ u3x_sam_6, &pos,
+ u3x_sam_7, &octs, 0);
+
+ return _qe_bytestream_find_byte(bat, pos, octs);
+}
+u3_noun
+_qe_bytestream_seek_byte(u3_atom bat, u3_atom pos, u3_noun octs)
+{
+ c3_w bat_w, pos_w;
+
+ if (c3n == u3r_safe_word(bat, &bat_w) || bat_w > 0xff) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ while (pos_w < len_w) {
+
+ if (*(sea_y + pos_w) == bat_w) {
+ u3_noun idx = u3nc(u3_nul, u3i_word(pos_w));
+ u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs));
+ return u3nc(idx, new_bays);
+ }
+
+ pos_w++;
+ }
+
+ // find leading zero: see comment in *_find_byte
+ //
+ if (pos_w < p_octs && bat_w == 0) {
+ u3_noun idx = u3nc(u3_nul, u3i_word(pos_w));
+ u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs));
+ return u3nc(idx, new_bays);
+ }
+
+ return u3nc(u3_nul, u3nc(u3k(pos), u3k(octs)));
+
+}
+u3_noun
+u3we_bytestream_seek_byte(u3_noun cor)
+{
+ u3_atom bat;
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &bat,
+ u3x_sam_6, &pos,
+ u3x_sam_7, &octs, 0);
+
+ return _qe_bytestream_seek_byte(bat, pos, octs);
+}
+
+u3_noun
+_qe_bytestream_read_byte(u3_atom pos, u3_noun octs)
+{
+ c3_w pos_w;
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ if (pos_w + 1 > p_octs_w) {
+ u3m_bail(c3__exit);
+ }
+
+ c3_y bat_y;
+
+ if (pos_w < len_w) {
+ bat_y = *(sea_y + pos_w);
+ }
+ else {
+ bat_y = 0;
+ }
+
+ u3_noun new_bays = u3nc(u3i_word(pos_w + 1), u3k(octs));
+
+ return u3nc(bat_y, new_bays);
+}
+
+u3_noun
+u3we_bytestream_read_byte(u3_noun cor)
+{
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &pos,
+ u3x_sam_3, &octs, 0);
+
+ return _qe_bytestream_read_byte(pos, octs);
+}
+
+u3_noun
+_qe_bytestream_read_octs(u3_atom n, u3_atom pos, u3_noun octs)
+{
+ c3_w n_w, pos_w;
+
+ if (c3n == u3r_safe_word(n, &n_w)) {
+ return u3_none;
+ }
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ if (n_w == 0) {
+ return u3nc(u3nc(0,0), u3nc(u3k(pos), u3k(octs)));
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ if (pos_w + n_w > p_octs_w) {
+ u3m_bail(c3__exit);
+ }
+
+ // Number of bytes to read, excluding leading zeros
+ //
+ c3_w red_w = n_w;
+
+ if (pos_w + n_w > len_w) {
+ if (pos_w < len_w) {
+ red_w = len_w - pos_w;
+ }
+ // leading zeros - nothing to read
+ //
+ else {
+ red_w = 0;
+ }
+ }
+
+ u3_noun read_octs;
+
+ if (red_w == 0) {
+ read_octs = u3nc(u3i_word(n_w), 0);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 3, n_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ memcpy(sab_u.buf_y, sea_y + pos_w, red_w);
+
+ if (red_w < n_w) {
+ memset(sab_u.buf_y + red_w, 0, (n_w - red_w));
+ }
+
+ read_octs = u3nc(u3i_word(n_w), u3i_slab_moot(&sab_u));
+ }
+
+ u3_noun new_bays = u3nc(u3i_word(pos_w + n_w), u3k(octs));
+
+ return u3nc(read_octs, new_bays);
+}
+
+u3_noun
+u3we_bytestream_read_octs(u3_noun cor)
+{
+ u3_atom n;
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &n,
+ u3x_sam_6, &pos,
+ u3x_sam_7, &octs, 0);
+
+ return _qe_bytestream_read_octs(n, pos, octs);
+}
+
+
+u3_noun
+_qe_peek_octs(c3_w n_w, c3_w pos_w, c3_w p_octs_w, c3_y* sea_y,
+ c3_w len_w)
+{
+ if (n_w == 0) {
+ return u3nc(0, 0);
+ }
+
+ if (pos_w + n_w > p_octs_w) {
+ return u3m_bail(c3__exit);
+ }
+
+ // Read leading zeros only
+ //
+ if (pos_w >= len_w) {
+ return u3nc(u3i_word(n_w), 0);
+ }
+ // Number of remaining buffer bytes
+ c3_w reb_w = len_w - pos_w;
+
+ u3i_slab sab_u;
+ c3_w my_len_w;
+
+ if (n_w < reb_w) {
+ my_len_w = n_w;
+ }
+ else {
+ my_len_w = reb_w;
+ }
+ u3i_slab_bare(&sab_u, 3, my_len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+ memcpy(sab_u.buf_y, sea_y + pos_w, my_len_w);
+
+ return u3nc(u3i_word(n_w), u3i_slab_moot(&sab_u));
+}
+u3_noun _qe_bytestream_chunk(u3_atom size, u3_noun pos, u3_noun octs)
+{
+ c3_w size_w, pos_w;
+
+ if (c3n == u3r_safe_word(size, &size_w)) {
+ return u3_none;
+ }
+
+ if (size_w == 0) {
+ return u3_nul;
+ }
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ u3_noun hun = u3_nul;
+
+ while (pos_w < p_octs) {
+ // Remaining bytes
+ //
+ c3_w rem = (p_octs - pos_w);
+
+ if (rem < size) {
+ u3_noun octs = _qe_peek_octs(rem, pos_w, p_octs_w, sea_y,
+ len_w);
+ hun = u3nc(octs, hun);
+ pos_w += rem;
+ }
+ else {
+ u3_noun octs = _qe_peek_octs(size, pos_w, p_octs_w, sea_y,
+ len_w);
+ hun = u3nc(octs, hun);
+ pos_w += size;
+ }
+ }
+
+ return u3kb_flop(hun);
+}
+
+u3_noun
+u3we_bytestream_chunk(u3_noun cor)
+{
+ u3_atom size;
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(cor, u3x_sam_2, &size,
+ u3x_sam_6, &pos,
+ u3x_sam_7, &octs, 0);
+
+ return _qe_bytestream_chunk(size, pos, octs);
+}
+
+u3_noun
+_qe_bytestream_extract(u3_noun sea, u3_noun rac)
+{
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(sea, 2, &pos, 3, &octs, 0);
+
+ c3_w pos_w;
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ u3_noun dal = u3_nul;
+
+ u3_noun new_sea = u3_none;
+
+ while (pos_w < p_octs_w) {
+ new_sea = u3nc(u3i_word(pos_w), u3k(octs));
+ u3_noun ext = u3x_good(u3n_slam_on(u3k(rac), new_sea));
+
+ u3_atom sip, ken;
+ c3_w sip_w, ken_w;
+
+ u3x_mean(ext, 2, &sip, 3, &ken, 0);
+
+ if (c3n == u3r_safe_word(sip, &sip_w)) {
+ // XX is u3z necessary here?
+ // does memory get freed on bail?
+ //
+ u3l_log("bytestream: sip fail");
+ u3z(dal);
+ u3z(ext);
+ return u3_none;
+ }
+
+ if (c3n == u3r_safe_word(ken, &ken_w)) {
+ u3l_log("bytestream: ken fail");
+ u3z(dal);
+ u3z(ext);
+ return u3_none;
+ }
+
+ u3z(ext);
+
+ if (sip_w == 0 && ken_w == 0) {
+ break;
+ }
+
+ if (pos_w + sip_w > p_octs_w) {
+ u3z(dal);
+ return u3_none;
+ }
+
+ pos_w += sip_w;
+
+ if (ken_w == 0) {
+ continue;
+ }
+
+ u3_noun octs = _qe_peek_octs(ken_w, pos_w, p_octs_w, sea_y, len_w);
+ pos_w += ken_w;
+ dal = u3nc(octs, dal);
+ }
+
+ new_sea = u3nc(u3i_word(pos_w), u3k(octs));
+
+ return u3nc(u3kb_flop(dal), new_sea);
+}
+u3_noun
+u3we_bytestream_extract(u3_noun cor)
+{
+ u3_noun sea;
+ u3_noun rac;
+
+ u3x_mean(cor, u3x_sam_2, &sea,
+ u3x_sam_3, &rac, 0);
+
+ return _qe_bytestream_extract(sea, rac);
+}
+
+u3_noun
+_qe_bytestream_fuse_extract(u3_noun sea, u3_noun rac)
+{
+ u3_atom pos;
+ u3_noun octs;
+
+ u3x_mean(sea, 2, &pos, 3, &octs, 0);
+
+ c3_w pos_w;
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ u3_noun dal = u3_nul;
+
+ u3_noun new_sea = u3_none;
+
+ while (pos_w < p_octs_w) {
+ new_sea = u3nc(u3i_word(pos_w), u3k(octs));
+ u3_noun ext = u3x_good(u3n_slam_on(u3k(rac), new_sea));
+
+ u3_atom sip, ken;
+ c3_w sip_w, ken_w;
+
+ u3x_mean(ext, 2, &sip, 3, &ken, 0);
+
+ if (c3n == u3r_safe_word(sip, &sip_w)) {
+ // XX is u3z necessary here?
+ // does memory get freed on bail?
+ //
+ u3l_log("bytestream: sip fail");
+ u3z(dal);
+ u3z(ext);
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(ken, &ken_w)) {
+ u3l_log("bytestream: ken fail");
+ u3z(dal);
+ u3z(ext);
+ return u3_none;
+ }
+
+ u3z(ext);
+
+ if (sip_w == 0 && ken_w == 0) {
+ break;
+ }
+
+ if (pos_w + sip_w > p_octs_w) {
+ u3z(dal);
+ return u3_none;
+ }
+
+ pos_w += sip_w;
+
+ if (ken_w == 0) {
+ continue;
+ }
+
+ u3_noun octs = _qe_peek_octs(ken_w, pos_w, p_octs_w, sea_y, len_w);
+ pos_w += ken_w;
+ dal = u3nc(octs, dal);
+ }
+
+ u3_noun lad = u3kb_flop(dal);
+ u3_noun data = _qe_bytestream_can_octs(lad);
+ u3z(lad);
+
+ new_sea = u3nc(u3i_word(pos_w), u3k(octs));
+
+ return u3nc(data, new_sea);
+}
+
+u3_noun
+u3we_bytestream_fuse_extract(u3_noun cor)
+{
+ u3_noun sea;
+ u3_noun rac;
+
+ u3x_mean(cor, u3x_sam_2, &sea,
+ u3x_sam_3, &rac, 0);
+
+ return _qe_bytestream_fuse_extract(sea, rac);
+}
+
+#define BITS_D (sizeof(c3_d)*8)
+
+u3_noun
+_qe_bytestream_need_bits(u3_atom n, u3_noun bits)
+{
+ u3_atom num, bit;
+ u3_noun bays;
+
+ u3x_mean(bits, 2, &num,
+ 6, &bit,
+ 7, &bays, 0);
+
+
+ c3_w n_w, num_w;
+ c3_d bit_d;
+
+ if (c3n == u3r_safe_word(n, &n_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(num, &num_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_chub(bit, &bit_d)) {
+ return u3_none;
+ }
+
+ if (num_w >= n_w) {
+ return u3k(bits);
+ }
+
+ // How many bytes to read
+ //
+ c3_w need_bits_w = n_w - num_w;
+
+ // Requires indirect atom, drop to Hoon
+ //
+ if (need_bits_w > BITS_D) {
+ return u3_none;
+ }
+
+ c3_w need_bytes_w = need_bits_w / 8;
+
+ if (need_bits_w % 8) {
+ need_bytes_w += 1;
+ }
+
+ c3_w pos_w;
+ u3_atom pos;
+ u3_noun octs;
+
+
+ u3x_mean(bays, 2, &pos, 3, &octs, 0);
+
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ u3_atom p_octs, q_octs;
+
+ _x_octs(octs, &p_octs, &q_octs);
+
+ c3_w p_octs_w;
+ c3_w len_w, lead_w;
+
+ c3_y* sea_y;
+
+ if (c3n == _x_octs_buffer(&p_octs, &q_octs,
+ &p_octs_w, &sea_y,
+ &len_w, &lead_w)) {
+ return u3_none;
+ }
+
+ if (pos_w + need_bytes_w > p_octs_w) {
+ u3m_bail(c3__exit);
+ }
+
+ while (need_bytes_w--) {
+
+ if (pos_w < len_w) {
+ bit_d += *(sea_y + pos_w) << num_w;
+ }
+ num_w += 8;
+ pos_w++;
+
+ u3_assert(num_w <= BITS_D);
+ }
+
+ u3_noun new_bays = u3nc(u3i_word(pos_w), u3k(octs));
+
+ return u3nt(u3i_word(num_w), u3i_chub(bit_d), new_bays);
+}
+// +$ bits $+ bits
+// $: num=@ud
+// bit=@ub
+// =bays
+// ==
+u3_noun
+u3we_bytestream_need_bits(u3_noun cor)
+{
+ u3_atom n;
+ u3_noun bits;
+
+ u3x_mean(cor, u3x_sam_2, &n,
+ u3x_sam_3, &bits, 0);
+
+ return _qe_bytestream_need_bits(n, bits);
+}
+
+u3_noun
+_qe_bytestream_drop_bits(u3_atom n, u3_noun bits)
+{
+
+ u3_atom num, bit;
+ u3_noun bays;
+
+ u3x_mean(bits, 2, &num,
+ 6, &bit,
+ 7, &bays, 0);
+
+ c3_w n_w, num_w;
+ c3_d bit_d;
+
+ if (c3n == u3r_safe_word(n, &n_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(num, &num_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_chub(bit, &bit_d)) {
+ return u3_none;
+ }
+
+ if(n_w == 0) {
+ return u3k(bits);
+ }
+
+ c3_w dop_w = n_w;
+
+ if (dop_w > num_w) {
+ dop_w = num_w;
+ }
+
+ bit_d >>= dop_w;
+ num_w -= dop_w;
+
+ return u3nt(u3i_word(num_w), u3i_chub(bit_d), u3k(bays));
+}
+u3_noun
+u3we_bytestream_drop_bits(u3_noun cor)
+{
+ u3_atom n;
+ u3_noun bits;
+
+ u3x_mean(cor, u3x_sam_2, &n,
+ u3x_sam_3, &bits, 0);
+
+ return _qe_bytestream_drop_bits(n, bits);
+}
+
+u3_noun
+_qe_bytestream_peek_bits(u3_atom n, u3_noun bits)
+{
+
+ u3_atom num, bit;
+ u3_noun bays;
+
+ u3x_mean(bits, 2, &num,
+ 6, &bit,
+ 7, &bays, 0);
+
+ c3_w n_w, num_w;
+ c3_d bit_d;
+
+ if (c3n == u3r_safe_word(n, &n_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(num, &num_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_chub(bit, &bit_d)) {
+ return u3_none;
+ }
+
+ if (n_w == 0) {
+ return u3i_word(0);
+ }
+
+ if (n_w > num_w) {
+ u3m_bail(c3__exit);
+ }
+
+ if (n_w > BITS_D) {
+ return u3_none;
+ }
+
+ if (n_w == BITS_D) {
+ return u3i_chub(bit_d);
+ }
+ else {
+ c3_d mak_d = ((c3_d)1 << n_w) - 1;
+
+ return u3i_chub(bit_d & mak_d);
+ }
+}
+u3_noun
+u3we_bytestream_peek_bits(u3_noun cor)
+{
+ u3_atom n;
+ u3_noun bits;
+
+ u3x_mean(cor, u3x_sam_2, &n,
+ u3x_sam_3, &bits, 0);
+
+ return _qe_bytestream_peek_bits(n, bits);
+}
+
+u3_noun
+_qe_bytestream_read_bits(u3_atom n, u3_noun bits)
+{
+
+ u3_atom num, bit;
+ u3_noun bays;
+
+ u3x_mean(bits, 2, &num,
+ 6, &bit,
+ 7, &bays, 0);
+
+ c3_w n_w, num_w;
+ c3_d bit_d;
+
+ if (c3n == u3r_safe_word(n, &n_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(num, &num_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_chub(bit, &bit_d)) {
+ return u3_none;
+ }
+
+ if (n_w > num_w) {
+ u3m_bail(c3__exit);
+ }
+
+ if (n_w > BITS_D) {
+ return u3_none;
+ }
+
+ c3_d bet_d = 0;
+
+ if (n_w == BITS_D) {
+ bet_d = bit_d;
+ }
+ else {
+ c3_d mak_d = ((c3_d)1 << n_w) - 1;
+ bet_d = bit_d & mak_d;
+ }
+
+ bit_d >>= n_w;
+ num_w -= n_w;
+
+ u3_noun new_bits = u3nt(u3i_word(num_w), u3i_chub(bit_d), u3k(bays));
+
+ return u3nc(u3i_chub(bet_d), new_bits);
+}
+
+u3_noun
+u3we_bytestream_read_bits(u3_noun cor)
+{
+ u3_atom n;
+ u3_noun bits;
+
+ u3x_mean(cor, u3x_sam_2, &n,
+ u3x_sam_3, &bits, 0);
+
+ return _qe_bytestream_read_bits(n, bits);
+}
+
+u3_noun
+_qe_bytestream_byte_bits(u3_noun bits)
+{
+
+ u3_atom num, bit;
+ u3_noun bays;
+
+ u3x_mean(bits, 2, &num,
+ 6, &bit,
+ 7, &bays, 0);
+
+ c3_w num_w;
+ c3_d bit_d;
+
+ if (c3n == u3r_safe_word(num, &num_w)) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_chub(bit, &bit_d)) {
+ return u3_none;
+ }
+
+ c3_y rem_y = num_w & 0x7;
+
+ if (rem_y == 0) {
+ return u3k(bits);
+ }
+
+ u3_noun new_bits = u3nt(u3i_word(num_w - rem_y),
+ u3i_chub(bit_d >> rem_y),
+ u3k(bays));
+
+ return new_bits;
+}
+
+u3_noun
+u3we_bytestream_byte_bits(u3_noun cor)
+{
+ u3_noun bits;
+
+ u3x_mean(cor, u3x_sam, &bits, 0);
+
+ return _qe_bytestream_byte_bits(bits);
+}
diff --git a/vere/pkg/noun/jets/e/chacha.c b/vere/pkg/noun/jets/e/chacha.c
new file mode 100644
index 0000000..e42f8e2
--- /dev/null
+++ b/vere/pkg/noun/jets/e/chacha.c
@@ -0,0 +1,74 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqe_chacha_crypt(u3_atom rounds, u3_atom key, u3_atom nonce, u3_atom counter, u3_atom wid, u3_atom dat)
+ {
+ c3_w rounds_w, wid_w;
+ c3_d counter_d;
+ if ( !u3r_word_fit(&rounds_w, rounds) || !u3r_word_fit(&wid_w, wid) || c3n == u3r_safe_chub(counter, &counter_d) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y key_y[32], nonce_y[8];
+ u3r_bytes(0, 32, key_y, key);
+ u3r_bytes(0, 8, nonce_y, nonce);
+ c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat);
+ urcrypt_chacha_crypt(rounds_w, key_y, nonce_y, counter_d, wid_w, dat_y);
+ u3_noun cry = u3i_bytes(wid_w, dat_y);
+ u3a_free(dat_y);
+ return u3i_cell(wid, cry);
+ }
+ }
+
+ u3_noun
+ u3we_chacha_crypt(u3_noun cor)
+ {
+ u3_noun sam = u3x_at(u3x_sam, cor);
+ u3_noun rounds, key, nonce, counter, msg;
+ u3_noun wid, dat;
+
+ if ( u3r_quil(sam, &rounds, &key, &nonce, &counter, &msg) ||
+ u3ud(rounds) || u3ud(key) || u3ud(nonce) || u3ud(counter) || u3r_cell(msg, &wid, &dat) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("chacha_crypt", _cqe_chacha_crypt(rounds, key, nonce, counter, wid, dat));
+ }
+ }
+
+
+ static u3_noun
+ _cqe_chacha_xchacha(u3_atom rounds, u3_atom key, u3_atom nonce)
+ {
+ c3_w rounds_w;
+ if ( !u3r_word_fit(&rounds_w, rounds) ) {
+ return u3m_bail(c3__fail);
+ }
+ c3_y key_y[32], nonce_y[64], xkey_y[32], xnonce_y[8];
+ u3r_bytes(0, 32, key_y, key);
+ u3r_bytes(0, 24, nonce_y, nonce);
+ urcrypt_chacha_xchacha(rounds, key_y, nonce_y, xkey_y, xnonce_y);
+ return u3i_cell(u3i_bytes(32, xkey_y), u3i_bytes(8, xnonce_y));
+ }
+
+ u3_noun
+ u3we_chacha_xchacha(u3_noun cor)
+ {
+ u3_noun sam = u3x_at(u3x_sam, cor);
+ u3_noun rounds, key, nonce;
+ if ( c3n == u3r_trel(sam, &rounds, &key, &nonce) ||
+ c3n == u3ud(rounds) ||
+ c3n == u3ud(key) ||
+ c3n == u3ud(nonce) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3l_punt("chacha_xchacha", _cqe_chacha_xchacha(rounds, key, nonce));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/crc.c b/vere/pkg/noun/jets/e/crc.c
new file mode 100644
index 0000000..496b8d5
--- /dev/null
+++ b/vere/pkg/noun/jets/e/crc.c
@@ -0,0 +1,59 @@
+/// @file
+
+#include <stdio.h>
+#include <allocate.h>
+#include "zlib.h"
+
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_crc32(u3_noun input_octs)
+{
+ u3_atom head = u3h(input_octs);
+ u3_atom tail = u3t(input_octs);
+ c3_w tel_w = u3r_met(3, tail);
+ c3_w hed_w;
+ if ( c3n == u3r_safe_word(head, &hed_w) ) {
+ return u3m_bail(c3__fail);
+ }
+ c3_y* input;
+
+ if (c3y == u3a_is_cat(tail)) {
+ input = (c3_y*)&tail;
+ }
+ else {
+ u3a_atom* vat_u = u3a_to_ptr(tail);
+ input = (c3_y*)vat_u->buf_w;
+ }
+
+ if ( tel_w > hed_w ) {
+ return u3m_error("subtract-underflow");
+ }
+
+ c3_w led_w = hed_w - tel_w;
+ c3_w crc_w = 0;
+
+ crc_w = crc32(crc_w, input, tel_w);
+
+ while ( led_w > 0 ) {
+ c3_y byt_y = 0;
+ crc_w = crc32(crc_w, &byt_y, 1);
+ led_w--;
+ }
+
+ return u3i_word(crc_w);
+}
+
+u3_noun
+u3we_crc32(u3_noun cor)
+{
+ u3_noun a = u3r_at(u3x_sam, cor);
+
+ if ( (u3du(a) == c3y) && (u3ud(u3h(a)) == c3y) && (u3ud(u3t(a)) == c3y) ) {
+ return u3qe_crc32(a);
+ } else {
+ return u3m_bail(c3__exit);
+ }
+}
diff --git a/vere/pkg/noun/jets/e/cue.c b/vere/pkg/noun/jets/e/cue.c
new file mode 100644
index 0000000..643b408
--- /dev/null
+++ b/vere/pkg/noun/jets/e/cue.c
@@ -0,0 +1,27 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_cue(u3_atom a)
+{
+ return u3s_cue_atom(a);
+}
+
+u3_noun
+u3we_cue(u3_noun cor)
+{
+ return u3qe_cue(u3x_atom(u3x_at(u3x_sam, cor)));
+}
+
+u3_noun
+u3ke_cue(u3_atom a)
+{
+ u3_noun b = u3qe_cue(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c b/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c
new file mode 100644
index 0000000..6512919
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_add_double_scalarmult.c
@@ -0,0 +1,72 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_add_double_scalarmult(u3_atom a,
+ u3_atom a_point,
+ u3_atom b,
+ u3_atom b_point)
+ {
+ c3_y a_y[32], a_point_y[32],
+ b_y[32], b_point_y[32],
+ out_y[32];
+ c3_w met_w;
+
+ met_w = u3r_met(3, a);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, a)) )
+ ) {
+ u3_noun a_recs = u3qee_recs(a);
+ u3r_bytes(0, 32, a_y, a_recs);
+ u3z(a_recs);
+ } else {
+ u3r_bytes(0, 32, a_y, a);
+ }
+
+ met_w = u3r_met(3, b);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, b)) )
+ ) {
+ u3_noun b_recs = u3qee_recs(b);
+ u3r_bytes(0, 32, b_y, b_recs);
+ u3z(b_recs);
+ } else {
+ u3r_bytes(0, 32, b_y, b);
+ }
+
+ if ( (0 != u3r_bytes_fit(32, a_point_y, a_point)) ||
+ (0 != u3r_bytes_fit(32, b_point_y, b_point)) ||
+ (0 != urcrypt_ed_add_double_scalarmult(a_y, a_point_y, b_y, b_point_y, out_y)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ u3_noun
+ u3wee_add_double_scalarmult(u3_noun cor)
+ {
+ u3_noun a, b, c, d;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_6, &b,
+ u3x_sam_14, &c,
+ u3x_sam_15, &d, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) ||
+ (c3n == u3ud(d)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_add_double_scalarmult(a, b, c, d);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c b/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c
new file mode 100644
index 0000000..39eda53
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_add_scalarmult_scalarmult_base.c
@@ -0,0 +1,66 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_add_scalarmult_scalarmult_base(u3_atom a,
+ u3_atom a_point,
+ u3_atom b)
+ {
+ c3_y a_y[32], a_point_y[32], b_y[32], out_y[32];
+ c3_w met_w;
+
+ met_w = u3r_met(3, a);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, a)) )
+ ) {
+ u3_noun a_recs = u3qee_recs(a);
+ u3r_bytes(0, 32, a_y, a_recs);
+ u3z(a_recs);
+ } else {
+ u3r_bytes(0, 32, a_y, a);
+ }
+
+ met_w = u3r_met(3, b);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, b)) )
+ ) {
+ u3_noun b_recs = u3qee_recs(b);
+ u3r_bytes(0, 32, b_y, b_recs);
+ u3z(b_recs);
+ } else {
+ u3r_bytes(0, 32, b_y, b);
+ }
+
+ if ( (0 != u3r_bytes_fit(32, a_point_y, a_point)) ||
+ (0 != urcrypt_ed_add_scalarmult_scalarmult_base(a_y, a_point_y, b_y, out_y)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ u3_noun
+ u3wee_add_scalarmult_scalarmult_base(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_6, &b,
+ u3x_sam_7, &c, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_add_scalarmult_scalarmult_base(a, b, c);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_luck.c b/vere/pkg/noun/jets/e/ed_luck.c
new file mode 100644
index 0000000..c21889e
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_luck.c
@@ -0,0 +1,37 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_luck(u3_atom sed)
+ {
+ c3_y sed_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y pub_y[32];
+ c3_y sec_y[64];
+ urcrypt_ed_luck(sed_y, pub_y, sec_y);
+ return u3nc(u3i_bytes(32, pub_y), u3i_bytes(64, sec_y));
+ }
+ }
+
+ u3_noun
+ u3wee_luck(u3_noun cor)
+ {
+ u3_noun a = u3r_at(u3x_sam, cor);
+
+ if ( (u3_none == a) || (c3n == u3ud(a)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_luck(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_point_add.c b/vere/pkg/noun/jets/e/ed_point_add.c
new file mode 100644
index 0000000..70fe563
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_point_add.c
@@ -0,0 +1,40 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+
+ static u3_atom
+ _cqee_point_add(u3_atom a,
+ u3_atom b)
+ {
+ c3_y a_y[32], b_y[32], out_y[32];
+
+ if ( (0 != u3r_bytes_fit(32, a_y, a)) ||
+ (0 != u3r_bytes_fit(32, b_y, b)) ||
+ (0 != urcrypt_ed_point_add(a_y, b_y, out_y)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ u3_noun
+ u3wee_point_add(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_point_add(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_point_neg.c b/vere/pkg/noun/jets/e/ed_point_neg.c
new file mode 100644
index 0000000..5a1a5bd
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_point_neg.c
@@ -0,0 +1,37 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+
+ static u3_atom
+ _cqee_point_neg(u3_atom a)
+ {
+ c3_y a_y[32];
+
+ if ( (0 != u3r_bytes_fit(32, a_y, a)) ||
+ (0 != urcrypt_ed_point_neg(a_y)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, a_y);
+ }
+ }
+
+ u3_noun
+ u3wee_point_neg(u3_noun cor)
+ {
+
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_point_neg(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_puck.c b/vere/pkg/noun/jets/e/ed_puck.c
new file mode 100644
index 0000000..98581d7
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_puck.c
@@ -0,0 +1,36 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_puck(u3_atom sed)
+ {
+ c3_y sed_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y pub_y[32];
+ urcrypt_ed_puck(sed_y, pub_y);
+ return u3i_bytes(32, pub_y);
+ }
+ }
+
+ u3_noun
+ u3wee_puck(u3_noun cor)
+ {
+ u3_noun a = u3r_at(u3x_sam, cor);
+
+ if ( (u3_none == a) || (c3n == u3ud(a)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_puck(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_recs.c b/vere/pkg/noun/jets/e/ed_recs.c
new file mode 100644
index 0000000..bdcf224
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_recs.c
@@ -0,0 +1,48 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ // `@ux`(rev 3 32 l:ed:crypto)
+ static c3_y _cqee_l_prime[] = {
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ };
+
+ u3_atom
+ u3qee_recs(u3_atom a)
+ {
+ c3_w met_w = u3r_met(3, a);
+
+ if ( 64 < met_w ) {
+ u3_atom l_prime = u3i_bytes(32, _cqee_l_prime);
+ u3_atom pro = u3qa_mod(a, l_prime);
+ u3z(l_prime);
+ return pro;
+ }
+
+ c3_y a_y[64];
+
+ u3r_bytes(0, 64, a_y, a);
+ urcrypt_ed_scalar_reduce(a_y);
+ return u3i_bytes(32, a_y);
+ }
+
+ u3_noun
+ u3wee_recs(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qee_recs(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_scad.c b/vere/pkg/noun/jets/e/ed_scad.c
new file mode 100644
index 0000000..af95563
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_scad.c
@@ -0,0 +1,124 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_scad(u3_atom pub, u3_atom sek, u3_atom sca)
+ {
+ c3_y pub_y[32];
+ c3_y sek_y[64];
+ c3_y sca_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ urcrypt_ed_add_scalar_public_private(pub_y, sek_y, sca_y);
+ return u3nc(u3i_bytes(32, pub_y), u3i_bytes(64, sek_y));
+ }
+ }
+
+ u3_noun
+ u3wee_scad(u3_noun cor)
+ {
+ u3_noun pub, sek, sca;
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &pub,
+ u3x_sam_6, &sek,
+ u3x_sam_7, &sca, 0)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(sek)) ||
+ (c3n == u3ud(sca)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_scad(pub, sek, sca);
+ }
+ }
+
+ static u3_atom
+ _cqee_scas(u3_atom sek, u3_atom sca)
+ {
+ c3_y sek_y[64];
+ c3_y sca_y[32];
+
+ if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ urcrypt_ed_add_scalar_private(sek_y, sca_y);
+ return u3i_bytes(64, sek_y);
+ }
+ }
+
+ u3_noun
+ u3wee_scas(u3_noun cor)
+ {
+ u3_noun sek, sca;
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &sek,
+ u3x_sam_3, &sca, 0)) ||
+ (c3n == u3ud(sek)) ||
+ (c3n == u3ud(sca)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_scas(sek, sca);
+ }
+ }
+
+ static u3_atom
+ _cqee_scap(u3_atom pub, u3_atom sca)
+ {
+ c3_y pub_y[32];
+ c3_y sca_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(32, sca_y, sca) ) {
+ // hoon explicitly crashes on mis-size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ urcrypt_ed_add_scalar_public(pub_y, sca_y);
+ return u3i_bytes(32, pub_y);
+ }
+ }
+
+ u3_noun
+ u3wee_scap(u3_noun cor)
+ {
+ u3_noun pub, sca;
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &pub,
+ u3x_sam_3, &sca, 0)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(sca)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_scap(pub, sca);
+ }
+ }
+
+
diff --git a/vere/pkg/noun/jets/e/ed_scalarmult.c b/vere/pkg/noun/jets/e/ed_scalarmult.c
new file mode 100644
index 0000000..8585c29
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_scalarmult.c
@@ -0,0 +1,54 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_scalarmult(u3_atom a,
+ u3_atom b)
+ {
+ c3_y a_y[32], b_y[32], out_y[32];
+ if (0 != u3r_bytes_fit(32, b_y, b)) {
+ return u3m_bail(c3__exit);
+ }
+
+ c3_w met_w = u3r_met(3, a);
+ // scalarmult expects a_y[31] <= 127
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, a)) )
+ ) {
+ u3_noun a_recs = u3qee_recs(a);
+ u3r_bytes(0, 32, a_y, a_recs);
+ u3z(a_recs);
+ } else {
+ u3r_bytes(0, 32, a_y, a);
+ }
+
+ if ( (0 != urcrypt_ed_scalarmult(a_y, b_y, out_y)) ) {
+ // at this point, will only fail if b is bad point
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ u3_noun
+ u3wee_scalarmult(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_scalarmult(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_scalarmult_base.c b/vere/pkg/noun/jets/e/ed_scalarmult_base.c
new file mode 100644
index 0000000..6193584
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_scalarmult_base.c
@@ -0,0 +1,46 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_scalarmult_base(u3_atom a)
+ {
+ c3_y a_y[32], out_y[32];
+ c3_w met_w = u3r_met(3, a);
+ // scalarmult_base expects a_y[31] <= 127
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, a)) )
+ ) {
+ u3_noun a_recs = u3qee_recs(a);
+ u3r_bytes(0, 32, a_y, a_recs);
+ u3z(a_recs);
+ } else {
+ u3r_bytes(0, 32, a_y, a);
+ }
+
+ if (0 != urcrypt_ed_scalarmult_base(a_y, out_y)) {
+ // should be unreachable, as scalar already reduced
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ u3_noun
+ u3wee_scalarmult_base(u3_noun cor)
+ {
+ u3_noun a = u3r_at(u3x_sam, cor);
+
+ if ( (u3_none == a) || (c3n == u3ud(a)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqee_scalarmult_base(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_shar.c b/vere/pkg/noun/jets/e/ed_shar.c
new file mode 100644
index 0000000..ed293f7
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_shar.c
@@ -0,0 +1,74 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_shar(u3_atom pub, u3_atom sed)
+ {
+ c3_y pub_y[32], sed_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) {
+ // hoon calls luck, which crashes
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y shr_y[32];
+ urcrypt_ed_shar(pub_y, sed_y, shr_y);
+ return u3i_bytes(32, shr_y);
+ }
+ }
+
+ u3_noun
+ u3wee_shar(u3_noun cor)
+ {
+ u3_noun pub, sed;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &pub, u3x_sam_3, &sed, 0)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(sed)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_shar(pub, sed);
+ }
+ }
+
+ static u3_atom
+ _cqee_slar(u3_atom pub, u3_atom sek)
+ {
+ c3_y pub_y[32], sek_y[64];
+
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ return u3m_bail(c3__exit);
+ }
+ else if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y shr_y[32];
+ urcrypt_ed_slar(pub_y, sek_y, shr_y);
+ return u3i_bytes(32, shr_y);
+ }
+ }
+
+ u3_noun
+ u3wee_slar(u3_noun cor)
+ {
+ u3_noun pub, sek;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &pub, u3x_sam_3, &sek, 0)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(sek)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_slar(pub, sek);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_sign.c b/vere/pkg/noun/jets/e/ed_sign.c
new file mode 100644
index 0000000..cd1797d
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_sign.c
@@ -0,0 +1,166 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+#include <retrieve.h>
+#include <types.h>
+
+ static u3_atom
+ _cqee_sign_octs(u3_noun len, u3_noun dat, u3_noun sed)
+ {
+ c3_y sed_y[32];
+ c3_w len_w;
+ if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) {
+ // hoon calls luck, which crashes
+ return u3m_bail(c3__exit);
+ }
+ else if ( !u3r_word_fit(&len_w, len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y sig_y[64];
+ c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat);
+ urcrypt_ed_sign(dat_y, len_w, sed_y, sig_y);
+ u3a_free(dat_y);
+ return u3i_bytes(64, sig_y);
+ }
+ }
+
+ u3_noun
+ u3wee_sign_octs(u3_noun cor)
+ {
+ u3_noun msg, sed;
+ u3_noun len, dat;
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, u3x_sam_3, &sed, 0) ||
+ c3n == u3r_cell(msg, &len, &dat) ||
+ c3n == u3ud(sed) ||
+ c3n == u3ud(len) ||
+ c3n == u3ud(dat) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_sign_octs(len, dat, sed);
+ }
+ }
+
+ static u3_atom
+ _cqee_sign_octs_raw(u3_noun len, u3_noun dat, u3_noun pub, u3_noun sek)
+ {
+ c3_y pub_y[32], sek_y[64];
+ c3_w len_w;
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ // hoon asserts size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) {
+ // hoon asserts size
+ return u3m_bail(c3__exit);
+ }
+ else if ( !u3r_word_fit(&len_w, len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y sig_y[64];
+ c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat);
+ urcrypt_ed_sign_raw(dat_y, len_w, pub_y, sek_y, sig_y);
+ u3a_free(dat_y);
+ return u3i_bytes(64, sig_y);
+ }
+ }
+
+ u3_noun
+ u3wee_sign_octs_raw(u3_noun cor)
+ {
+ u3_noun msg, pub, sek;
+ u3_noun len, dat;
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, u3x_sam_6, &pub, u3x_sam_7, &sek, 0) ||
+ c3n == u3r_cell(msg, &len, &dat) ||
+ c3n == u3ud(pub) ||
+ c3n == u3ud(sek) ||
+ c3n == u3ud(len) ||
+ c3n == u3ud(dat) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_sign_octs_raw(len, dat, pub, sek);
+ }
+ }
+
+ static u3_atom
+ _cqee_sign(u3_noun msg,
+ u3_noun sed)
+ {
+ c3_y sed_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) {
+ // hoon calls luck, which crashes
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y sig_y[64];
+ c3_w met_w;
+ c3_y* msg_y = u3r_bytes_all(&met_w, msg);
+
+ urcrypt_ed_sign(msg_y, met_w, sed_y, sig_y);
+ u3a_free(msg_y);
+
+ return u3i_bytes(64, sig_y);
+ }
+ }
+
+ u3_noun
+ u3wee_sign(u3_noun cor)
+ {
+ u3_noun msg, sed;
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &msg, u3x_sam_3, &sed, 0) ||
+ c3n == u3ud(msg) ||
+ c3n == u3ud(sed) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_sign(msg, sed);
+ }
+ }
+
+ static u3_atom
+ _cqee_sign_raw(u3_noun msg,
+ u3_noun pub,
+ u3_noun sek)
+ {
+ c3_y pub_y[32], sek_y[64];
+
+ if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) {
+ // hoon asserts size
+ return u3m_bail(c3__exit);
+ }
+ if ( 0 != u3r_bytes_fit(64, sek_y, sek) ) {
+ // hoon asserts size
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y sig_y[64];
+ c3_w met_w;
+ c3_y* msg_y = u3r_bytes_all(&met_w, msg);
+
+ urcrypt_ed_sign_raw(msg_y, met_w, pub_y, sek_y, sig_y);
+ u3a_free(msg_y);
+
+ return u3i_bytes(64, sig_y);
+ }
+ }
+
+ u3_noun
+ u3wee_sign_raw(u3_noun cor)
+ {
+ u3_noun msg, pub, sek;
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &msg, u3x_sam_6, &pub, u3x_sam_7, &sek, 0) ||
+ c3n == u3ud(msg) ||
+ c3n == u3ud(pub) ||
+ c3n == u3ud(sek) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_sign_raw(msg, pub, sek);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_smac.c b/vere/pkg/noun/jets/e/ed_smac.c
new file mode 100644
index 0000000..ce0ffac
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_smac.c
@@ -0,0 +1,73 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_smac(u3_atom a,
+ u3_atom b,
+ u3_atom c)
+ {
+ c3_y a_y[32], b_y[32], c_y[32], out_y[32];
+ c3_w met_w;
+
+ met_w = u3r_met(3, a);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, a)) )
+ ) {
+ u3_noun a_recs = u3qee_recs(a);
+ u3r_bytes(0, 32, a_y, a_recs);
+ u3z(a_recs);
+ } else {
+ u3r_bytes(0, 32, a_y, a);
+ }
+
+ met_w = u3r_met(3, b);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, b)) )
+ ) {
+ u3_noun b_recs = u3qee_recs(b);
+ u3r_bytes(0, 32, b_y, b_recs);
+ u3z(b_recs);
+ } else {
+ u3r_bytes(0, 32, b_y, b);
+ }
+
+ met_w = u3r_met(3, c);
+ if ( (32 < met_w) ||
+ ( (32 == met_w) &&
+ (127 < u3r_byte(31, c)) )
+ ) {
+ u3_noun c_recs = u3qee_recs(c);
+ u3r_bytes(0, 32, c_y, c_recs);
+ u3z(c_recs);
+ } else {
+ u3r_bytes(0, 32, c_y, c);
+ }
+
+ urcrypt_ed_scalar_muladd(a_y, b_y, c_y, out_y);
+ return u3i_bytes(32, out_y);
+ }
+
+ u3_noun
+ u3wee_smac(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
+ u3x_sam_6, &b,
+ u3x_sam_7, &c, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqee_smac(a, b, c);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ed_veri.c b/vere/pkg/noun/jets/e/ed_veri.c
new file mode 100644
index 0000000..6d7b750
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ed_veri.c
@@ -0,0 +1,85 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqee_veri_octs(u3_noun sig,
+ u3_noun len,
+ u3_noun dat,
+ u3_noun pub)
+ {
+ c3_y sig_y[64], pub_y[32];
+ c3_w len_w;
+ if ( (0 != u3r_bytes_fit(64, sig_y, sig)) ||
+ (0 != u3r_bytes_fit(32, pub_y, pub)) ||
+ !u3r_word_fit(&len_w, len) ) {
+ return c3n;
+ }
+ else {
+ c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat);
+ c3_t val_t = urcrypt_ed_veri(dat_y, len_w, pub_y, sig_y);
+ u3a_free(dat_y);
+
+ return val_t ? c3y : c3n;
+ }
+ }
+
+ u3_noun
+ u3wee_veri_octs(u3_noun cor)
+ {
+ u3_noun sig, msg, pub;
+ u3_noun len, dat;
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &sig, u3x_sam_6, &msg,
+ u3x_sam_7, &pub, 0) ||
+ c3n == u3r_cell(msg, &len, &dat) ||
+ (c3n == u3ud(sig)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(len)) ||
+ (c3n == u3ud(dat)) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_veri_octs(sig, len, dat, pub);
+ }
+ }
+
+ static u3_atom
+ _cqee_veri(u3_noun s,
+ u3_noun m,
+ u3_noun pk)
+ {
+ c3_y sig_y[64], pub_y[32];
+
+ if ( (0 != u3r_bytes_fit(64, sig_y, s)) ||
+ (0 != u3r_bytes_fit(32, pub_y, pk)) ) {
+ return c3n;
+ }
+ else {
+ c3_w met_w;
+ c3_y* mes_y = u3r_bytes_all(&met_w, m);
+ c3_t val_t = urcrypt_ed_veri(mes_y, met_w, pub_y, sig_y);
+ u3a_free(mes_y);
+
+ return val_t ? c3y : c3n;
+ }
+ }
+
+ u3_noun
+ u3wee_veri(u3_noun cor)
+ {
+ u3_noun a, b, c;
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &a, u3x_sam_6, &b,
+ u3x_sam_7, &c, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) ||
+ (c3n == u3ud(c)) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqee_veri(a, b, c);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/fein_ob.c b/vere/pkg/noun/jets/e/fein_ob.c
new file mode 100644
index 0000000..65d0f3a
--- /dev/null
+++ b/vere/pkg/noun/jets/e/fein_ob.c
@@ -0,0 +1,90 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "murmur3.h"
+
+// +feis:ob constant parameters to +fe:ob
+//
+static const c3_w a_w = 0xffff;
+static const c3_w b_w = 0x10000;
+static const c3_w k_w = 0xffff0000;
+
+// +raku:ob
+//
+static const c3_w rak_w[4] = { 0xb76d5eed, 0xee281300, 0x85bcae01, 0x4b387af7 };
+
+/* _fe_ob(): +fe:ob, with constant parameters factored out.
+** correct over the domain [0x0, 0xfffe.ffff]
+*/
+static c3_w
+_fe_ob(c3_w m_w)
+{
+ c3_w l_w = m_w % a_w;
+ c3_w r_w = m_w / a_w;
+ c3_w f_w, t_w;
+ c3_y j_y, k_y[2];
+
+ for ( j_y = 0; j_y < 4; j_y++ ) {
+ k_y[0] = r_w & 0xff;
+ k_y[1] = (r_w >> 8) & 0xff;
+
+ MurmurHash3_x86_32(k_y, 2, rak_w[j_y], &f_w);
+
+ // NB: this addition can overflow a c3_w (before mod)
+ //
+ t_w = ((c3_d)f_w + l_w) % (!(j_y & 1) ? a_w : b_w);
+ l_w = r_w;
+ r_w = t_w;
+ }
+
+ // legendary @max19
+ //
+ return ( a_w == r_w )
+ ? (r_w * a_w) + l_w
+ : (l_w * a_w) + r_w;
+}
+
+/* _feis_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fein:ob).
+** correct over the domain [0x1.0000, 0xffff.ffff]
+*/
+static c3_w
+_feis_ob(c3_w m_w)
+{
+ c3_w c_w = _fe_ob(m_w - b_w);
+ return b_w + (( c_w < k_w ) ? c_w : _fe_ob(c_w));
+}
+
+u3_atom
+u3qe_fein_ob(u3_atom pyn)
+{
+ c3_w sor_w = u3r_met(4, pyn);
+
+ if ( (sor_w < 2) || (sor_w > 4) ) {
+ return u3k(pyn);
+ }
+
+ if ( 2 == sor_w ) {
+ return u3i_word(_feis_ob(u3r_word(0, pyn)));
+ }
+ else {
+ c3_w pyn_w[2];
+ u3r_words(0, 2, pyn_w, pyn);
+
+ if ( pyn_w[0] < b_w ) {
+ return u3k(pyn);
+ }
+ else {
+ pyn_w[0] = _feis_ob(pyn_w[0]);
+ return u3i_words(2, pyn_w);
+ }
+ }
+}
+
+u3_noun
+u3we_fein_ob(u3_noun cor)
+{
+ return u3qe_fein_ob(u3x_atom(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/e/fl.c b/vere/pkg/noun/jets/e/fl.c
new file mode 100644
index 0000000..c52309e
--- /dev/null
+++ b/vere/pkg/noun/jets/e/fl.c
@@ -0,0 +1,441 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* structures
+*/
+ typedef struct _flOptions {
+ c3_w precision;
+ mpz_t minExp;
+ mpz_t expWidth;
+ c3_w rMode;
+ c3_w eMode;
+ } flOptions;
+
+ typedef struct _ea {
+ mpz_t e;
+ mpz_t a;
+ } ea;
+
+ static void
+ _satom_to_mp(mpz_t a_mp,
+ u3_atom b)
+ {
+ if ( _(u3a_is_cat(b)) ) {
+ c3_ws c = (b + 1) >> 1;
+ if ( (b & 1) ) {
+ c = -c;
+ }
+ mpz_init_set_si(a_mp, c);
+ }
+ else {
+ u3r_mp(a_mp, b);
+ c3_t x = mpz_odd_p(a_mp);
+ mpz_add_ui(a_mp, a_mp, 1);
+ mpz_tdiv_q_2exp(a_mp, a_mp, 1);
+ if ( x ) {
+ mpz_neg(a_mp, a_mp);
+ }
+ }
+ }
+
+ static u3_noun
+ _mp_to_satom(mpz_t a_mp)
+ {
+ c3_ws b = mpz_sgn(a_mp);
+ switch ( b ) {
+ default: return u3m_bail(c3__fail);
+ case 0: {
+ mpz_clear(a_mp);
+ return 0;
+ }
+ case 1: {
+ mpz_mul_2exp(a_mp, a_mp, 1);
+ return u3i_mp(a_mp);
+ }
+ case -1: {
+ mpz_abs(a_mp, a_mp);
+ mpz_mul_2exp(a_mp, a_mp, 1);
+ mpz_sub_ui(a_mp, a_mp, 1);
+ return u3i_mp(a_mp);
+ }
+ }
+ }
+
+ static void
+ _noun_to_flOptions(flOptions* a,
+ u3_noun b)
+ {
+ u3_noun c;
+ u3_atom d, e, f, g, h;
+ u3x_trel(b, &c, &d, &e);
+ u3x_trel(c, &f, &g, &h);
+
+ mpz_t i;
+ u3r_mp(i, f);
+ if ( !mpz_fits_uint_p(i) ) {
+ mpz_clear(i);
+ u3m_bail(c3__exit);
+ }
+ a->precision = mpz_get_ui(i);
+ mpz_clear(i);
+
+ if ( a->precision < 2 ) u3m_bail(c3__exit);
+
+ _satom_to_mp(a->minExp, g);
+ u3r_mp(a->expWidth, h);
+
+ if ( !(_(u3a_is_cat(d)) && _(u3a_is_cat(e))) ) {
+ mpz_clear(a->minExp);
+ mpz_clear(a->expWidth);
+ u3m_bail(c3__exit);
+ }
+ a->rMode = d;
+ a->eMode = e;
+ }
+
+ static void
+ _noun_to_ea(ea* a,
+ u3_noun b)
+ {
+ u3_atom c, d;
+ u3x_cell(b, &c, &d);
+
+ if ( !(_(u3a_is_cat(c))) ) {
+ u3m_bail(c3__exit);
+ }
+
+ _satom_to_mp(a->e, c);
+ u3r_mp(a->a, d);
+ }
+
+ static u3_noun
+ _ea_to_noun(ea* a)
+ {
+ u3_atom b = _mp_to_satom(a->e);
+ u3_atom c = u3i_mp(a->a);
+
+ return u3nc(b, c);
+ }
+
+ static void
+ _xpd(ea* a,
+ flOptions* b)
+ {
+ size_t z = mpz_sizeinbase(a->a, 2);
+ if ( z >= b->precision ) return;
+ c3_w c = b->precision - z;
+
+ if ( b->eMode != c3__i ) {
+ mpz_t i;
+ mpz_init_set(i, a->e);
+ mpz_sub(i, i, b->minExp);
+ if ( mpz_sgn(i) < 0 ) {
+ c = 0;
+ }
+ else if ( mpz_fits_uint_p(i) )
+ {
+ c3_w d = mpz_get_ui(i);
+ c = c3_min(c, d);
+ }
+ mpz_clear(i);
+ }
+
+ mpz_mul_2exp(a->a, a->a, c);
+ mpz_sub_ui(a->e, a->e, c);
+ }
+
+ /* a: floating point number, b: flOptions, i: rounding mode, j: sticky bit */
+ u3_noun
+ u3qef_lug(u3_noun a,
+ u3_noun b,
+ u3_atom i,
+ u3_atom j)
+ {
+ mpz_t v, g, h;
+ ea c;
+ flOptions d;
+ _noun_to_ea(&c, a);
+ _noun_to_flOptions(&d, b);
+ if ( mpz_sgn(c.a) == 0 ) {
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3m_bail(c3__exit);
+ }
+ size_t m = mpz_sizeinbase(c.a, 2);
+ if ( !_(j) && (m <= d.precision) ) {
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3m_bail(c3__exit);
+ }
+ c3_w q = 0;
+ c3_w f = (m > d.precision) ? m - d.precision : 0;
+ mpz_init(g);
+ if ( (d.eMode != c3__i) &&
+ (mpz_cmp(c.e, d.minExp) < 0) ) {
+ mpz_sub(g, d.minExp, c.e);
+ if ( !mpz_fits_uint_p(g) ) {
+ mpz_clear(g);
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3m_bail(c3__exit);
+ }
+ q = mpz_get_ui(g);
+ }
+ q = c3_max(f, q);
+ mpz_init(v);
+ mpz_tdiv_r_2exp(v, c.a, q);
+ mpz_tdiv_q_2exp(c.a, c.a, q);
+ mpz_add_ui(c.e, c.e, q);
+ mpz_init_set_ui(h, 1);
+ if ( q > 0 ) mpz_mul_2exp(h, h, q - 1);
+
+ if ( mpz_sgn(c.a) == 0 ) {
+ c3_t y;
+ switch ( i ) {
+ default:
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3m_bail(c3__exit);
+ case c3__fl:
+ case c3__sm:
+ mpz_set_ui(c.a, 0);
+ mpz_set_ui(c.e, 0);
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ break;
+ case c3__ce:
+ case c3__lg:
+ mpz_set_ui(c.a, 1);
+ mpz_set(c.e, d.minExp);
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ break;
+ case c3__ne:
+ case c3__nt:
+ case c3__na:
+ if ( (i != c3__na) && _(j) ) {
+ y = (mpz_cmp(v, h) <= 0);
+ } else {
+ y = (mpz_cmp(v, h) < 0);
+ }
+ if ( y ) {
+ mpz_set_ui(c.a, 0);
+ mpz_set_ui(c.e, 0);
+ } else {
+ mpz_set_ui(c.a, 1);
+ mpz_set(c.e, d.minExp);
+ }
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ break;
+ }
+ goto end;
+ }
+ _xpd(&c, &d);
+ switch ( i ) {
+ c3_ws x;
+ default:
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3m_bail(c3__exit);
+ case c3__fl:
+ break;
+ case c3__lg:
+ mpz_add_ui(c.a, c.a, 1);
+ break;
+ case c3__sm:
+ if ( (mpz_sgn(v) != 0) || !_(j) ) break;
+ if ( (mpz_cmp(c.e, d.minExp) == 0) && (d.eMode != c3__i) ) {
+ mpz_sub_ui(c.a, c.a, 1);
+ break;
+ }
+ mpz_mul_2exp(g, c.a, 1);
+ mpz_sub_ui(g, g, 1);
+ if ( mpz_sizeinbase(g, 2) <= d.precision ) {
+ mpz_sub_ui(c.e, c.e, 1);
+ mpz_set(c.a, g);
+ } else {
+ mpz_sub_ui(c.a, c.a, 1);
+ }
+ break;
+ case c3__ce:
+ if ( (mpz_sgn(v) != 0) || !_(j) ) {
+ mpz_add_ui(c.a, c.a, 1);
+ }
+ break;
+ case c3__ne:
+ if ( mpz_sgn(v) == 0 ) break;
+ x = mpz_cmp(v, h);
+ if ( (x == 0) && _(j) ) {
+ if ( mpz_odd_p(c.a) ) {
+ mpz_add_ui(c.a, c.a, 1);
+ }
+ }
+ else if ( x >= 0 ) {
+ mpz_add_ui(c.a, c.a, 1);
+ }
+ break;
+ case c3__na:
+ case c3__nt:
+ if ( mpz_sgn(v) == 0 ) break;
+ x = mpz_cmp(v, h);
+ if ( (x < 0) ) break;
+ if ( (i == c3__nt) && (x == 0) ) {
+ if (!_(j)) mpz_add_ui(c.a, c.a, 1);
+ } else {
+ mpz_add_ui(c.a, c.a, 1);
+ }
+ break;
+ }
+ if ( mpz_sizeinbase(c.a, 2) == (d.precision + 1) ) {
+ mpz_tdiv_q_2exp(c.a, c.a, 1);
+ mpz_add_ui(c.e, c.e, 1);
+ }
+ if ( mpz_sgn(c.a) == 0 ) {
+ mpz_set_ui(c.e, 0);
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ goto end;
+ }
+ mpz_set(g, d.minExp);
+ mpz_add(g, g, d.expWidth);
+ if ( (d.eMode != c3__i) && (mpz_cmp(g, c.e) < 0) ) {
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ return u3nc(c3__i, c3y);
+ }
+ mpz_clear(v); mpz_clear(h); mpz_clear(g);
+
+ // all mpz except in c, d structures cleared; c contains result
+ end:
+ if ( d.eMode == c3__f ) {
+ if ( mpz_sizeinbase(c.a, 2) != d.precision ) {
+ mpz_set_ui(c.a, 0);
+ mpz_set_ui(c.e, 0);
+ }
+ }
+ u3_noun ret = u3nq(c3__f, c3y, _mp_to_satom(c.e), u3i_mp(c.a));
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ return ret;
+ }
+
+ u3_noun
+ u3wef_lug(u3_noun cor)
+ {
+ u3_noun a, b, c, d, e;
+ a = u3x_at(u3x_sam, cor);
+ b = u3x_at(30, cor);
+ u3x_trel(a, &c, &d, &e);
+
+ return u3qef_lug(d, b, c, e);
+ }
+
+ u3_noun
+ u3qef_drg(u3_noun a,
+ u3_noun b)
+ {
+ ea c;
+ flOptions d;
+ _noun_to_ea(&c, a);
+ _noun_to_flOptions(&d, b);
+ if ( mpz_sgn(c.a) == 0 ) {
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ u3m_bail(c3__exit);
+ }
+ _xpd(&c, &d);
+ if ( !mpz_fits_sint_p(c.e) ) {
+ mpz_clear(d.minExp); mpz_clear(d.expWidth);
+ mpz_clear(c.a); mpz_clear(c.e);
+ u3m_bail(c3__exit);
+ }
+ mpz_t r, s, mn, mp, i, j, u, o;
+ mpz_init_set(r, c.a);
+ mpz_init_set_ui(s, 1);
+ mpz_init_set_ui(mn, 1);
+ mpz_init(i);
+ mpz_init(j);
+ c3_w se = mpz_sgn(c.e);
+ if ( se == 1 ) {
+ mpz_mul_2exp(r, r, mpz_get_ui(c.e));
+ mpz_mul_2exp(mn, mn, mpz_get_ui(c.e));
+ }
+ else if ( se == -1 ) {
+ mpz_mul_2exp(s, s, mpz_get_ui(c.e));
+ }
+ mpz_init_set(mp, mn);
+ mpz_set_ui(i, 1);
+ mpz_mul_2exp(i, i, d.precision - 1);
+ if ( (mpz_cmp(c.a, i) == 0) &&
+ ((mpz_cmp(c.e, d.minExp) != 0 ) ||
+ (d.eMode == c3__i)) ) {
+ mpz_mul_2exp(mp, mp, 1);
+ mpz_mul_2exp(r, r, 1);
+ mpz_mul_2exp(s, s, 1);
+ }
+ mpz_cdiv_q_ui(i, s, 10);
+ mpz_set_ui(c.e, 0);
+ while ( mpz_cmp(r, i) < 0 ) {
+ mpz_sub_ui(c.e, c.e, 1);
+ mpz_mul_ui(r, r, 10);
+ mpz_mul_ui(mn, mn, 10);
+ mpz_mul_ui(mp, mp, 10);
+ }
+ while ( 1 ) {
+ mpz_mul_2exp(i, r, 1);
+ mpz_add(i, i, mp);
+ mpz_mul_2exp(j, s, 1);
+ if ( mpz_cmp(i, j) < 0 ) {
+ break;
+ }
+ mpz_mul_ui(s, s, 10);
+ mpz_add_ui(c.e, c.e, 1);
+ }
+ mpz_init(u);
+ mpz_init_set_ui(o, 0);
+ while ( 1 ) {
+ mpz_sub_ui(c.e, c.e, 1);
+ mpz_mul_ui(r, r, 10);
+ mpz_mul_ui(mn, mn, 10);
+ mpz_mul_ui(mp, mp, 10);
+ mpz_tdiv_qr(u, r, r, s);
+ mpz_mul_2exp(i, r, 1);
+ mpz_mul_2exp(j, s, 1);
+ c3_t l = mpz_cmp(i, mn) < 0;
+ c3_t h = mpz_cmp(j, mp) < 0;
+ if ( !h ) {
+ mpz_sub(j, j, mp);
+ h = mpz_cmp(i, j) > 0;
+ }
+ if ( l || h ) {
+ mpz_mul_ui(o, o, 10);
+ mpz_add(o, o, u);
+ if ( h && (!l || (mpz_cmp(i, s) > 0)) ) {
+ mpz_add_ui(o, o, 1);
+ }
+ break;
+ }
+ mpz_mul_ui(o, o, 10);
+ mpz_add(o, o, u);
+ }
+ mpz_set(c.a, o);
+ mpz_clear(r); mpz_clear(s);
+ mpz_clear(mn); mpz_clear(mp);
+ mpz_clear(i); mpz_clear(j); mpz_clear(u);
+ mpz_clear(o); mpz_clear(d.minExp); mpz_clear(d.expWidth);
+
+ return _ea_to_noun(&c);
+ }
+
+ u3_noun
+ u3wef_drg(u3_noun cor)
+ {
+ u3_noun a, b;
+ a = u3x_at(u3x_sam, cor);
+ b = u3x_at(30, cor);
+
+ return u3qef_drg(a, b);
+ }
diff --git a/vere/pkg/noun/jets/e/fynd_ob.c b/vere/pkg/noun/jets/e/fynd_ob.c
new file mode 100644
index 0000000..62e65d1
--- /dev/null
+++ b/vere/pkg/noun/jets/e/fynd_ob.c
@@ -0,0 +1,94 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "murmur3.h"
+
+// +tail:ob constant parameters to +fe:ob
+//
+static const c3_w a_w = 0xffff;
+static const c3_w b_w = 0x10000;
+static const c3_w k_w = 0xffff0000;
+
+// (flop raku:ob)
+//
+static const c3_w kar_w[4] = { 0x4b387af7, 0x85bcae01, 0xee281300, 0xb76d5eed };
+
+/* _fen_ob(): +fen:ob, with constant parameters factored out.
+** correct over the domain [0x0 ... 0xfffe.ffff]
+*/
+static c3_w
+_fen_ob(c3_w m_w)
+{
+ c3_w l_w = m_w / a_w;
+ c3_w r_w = m_w % a_w;
+ c3_w f_w, t_w;
+ c3_y j_y, k_y[2];
+
+ // legendary @max19
+ //
+ if ( a_w == l_w ) {
+ t_w = l_w;
+ l_w = r_w;
+ r_w = t_w;
+ }
+
+ for ( j_y = 0; j_y < 4; j_y++ ) {
+ k_y[0] = l_w & 0xff;
+ k_y[1] = (l_w >> 8) & 0xff;
+
+ MurmurHash3_x86_32(k_y, 2, kar_w[j_y], &f_w);
+
+ t_w = ( j_y & 1 )
+ ? ((r_w + a_w) - (f_w % a_w)) % a_w
+ : ((r_w + b_w) - (f_w % b_w)) % b_w;
+ r_w = l_w;
+ l_w = t_w;
+ }
+
+ return (r_w * a_w) + l_w;
+}
+
+/* _tail_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fynd:ob).
+** correct over the domain [0x1.0000, 0xffff.ffff]
+*/
+static c3_w
+_tail_ob(c3_w m_w)
+{
+ c3_w c_w = _fen_ob(m_w - b_w);
+ return b_w + (( c_w < k_w ) ? c_w : _fen_ob(c_w));
+}
+
+u3_atom
+u3qe_fynd_ob(u3_atom pyn)
+{
+ c3_w sor_w = u3r_met(4, pyn);
+
+ if ( (sor_w < 2) || (sor_w > 4) ) {
+ return u3k(pyn);
+ }
+
+ if ( 2 == sor_w ) {
+ return u3i_word(_tail_ob(u3r_word(0, pyn)));
+ }
+ else {
+ c3_w pyn_w[2];
+ u3r_words(0, 2, pyn_w, pyn);
+
+ if ( pyn_w[0] < b_w ) {
+ return u3k(pyn);
+ }
+ else {
+ pyn_w[0] = _tail_ob(pyn_w[0]);
+ return u3i_words(2, pyn_w);
+ }
+ }
+}
+
+u3_noun
+u3we_fynd_ob(u3_noun cor)
+{
+ return u3qe_fynd_ob(u3x_atom(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/e/hmac.c b/vere/pkg/noun/jets/e/hmac.c
new file mode 100644
index 0000000..b14ec1e
--- /dev/null
+++ b/vere/pkg/noun/jets/e/hmac.c
@@ -0,0 +1,94 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qe_hmac(u3_noun haj,
+ u3_atom boq,
+ u3_atom out,
+ u3_atom wik,
+ u3_atom key,
+ u3_atom wid,
+ u3_atom dat)
+ {
+ u3_assert(_(u3a_is_cat(boq)) && _(u3a_is_cat(wik)) && _(u3a_is_cat(wid)));
+
+ // prep the hashing gate
+ u3j_site sit_u;
+ u3j_gate_prep(&sit_u, u3k(haj));
+
+ // ensure key and message fit signaled lengths
+ key = u3qc_end(3, wik, key);
+ dat = u3qc_end(3, wid, dat);
+
+ // keys longer than block size are shortened by hashing
+ if (wik > boq) {
+ key = u3j_gate_slam(&sit_u, u3nc(wik, key));
+ wik = out;
+ }
+
+ // keys shorter than block size are right-padded
+ if (wik < boq) {
+ key = u3kc_lsh(3, (boq - wik), key);
+ }
+
+ // pad key, inner and outer
+ c3_y trail = (boq % 4);
+ c3_y padwords = (boq / 4) + (trail == 0 ? 0 : 1);
+ c3_w innpad[padwords], outpad[padwords];
+ memset(innpad, 0x36, padwords * 4);
+ memset(outpad, 0x5c, padwords * 4);
+ if ( trail > 0 ) {
+ innpad[padwords-1] = 0x36363636 >> (8 * (4 - trail));
+ outpad[padwords-1] = 0x5c5c5c5c >> (8 * (4 - trail));
+ }
+ u3_atom innkey = u3kc_mix(u3k(key), u3i_words(padwords, innpad));
+ u3_atom outkey = u3kc_mix( key , u3i_words(padwords, outpad));
+
+ // append inner padding to message, then hash
+ u3_atom innmsg = u3ka_add(u3kc_lsh(3, wid, innkey), dat);
+ u3_atom innhaj = u3j_gate_slam(&sit_u, u3nc((wid + boq), innmsg));
+
+ // prepend outer padding to result, hash again
+ u3_atom outmsg = u3ka_add(u3kc_lsh(3, out, outkey), innhaj);
+ u3_atom outhaj = u3j_gate_slam(&sit_u, u3nc((out + boq), outmsg));
+
+ u3j_gate_lose(&sit_u);
+ return outhaj;
+ }
+
+ u3_noun
+ u3we_hmac(u3_noun cor)
+ {
+ u3_noun haj, boq, out, wik, key, wid, dat;
+
+ // sample is [[haj boq out] [wik key] [wid dat]]
+ if ( (c3n == u3r_mean(cor, u3x_sam_4, &haj,
+ 50, &boq, // +<->-
+ 51, &out, // +<->+
+ u3x_sam_12, &wik,
+ u3x_sam_13, &key,
+ u3x_sam_14, &wid,
+ u3x_sam_15, &dat, 0)) ||
+ (c3n == u3ud(boq)) ||
+ (c3n == u3a_is_cat(boq)) ||
+ (c3n == u3ud(out)) ||
+ (c3n == u3a_is_cat(out)) ||
+ (c3n == u3ud(wik)) ||
+ (c3n == u3a_is_cat(wik)) ||
+ (c3n == u3ud(key)) ||
+ (c3n == u3ud(wid)) ||
+ (c3n == u3a_is_cat(wid)) ||
+ (c3n == u3ud(dat)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qe_hmac(haj, boq, out, wik, key, wid, dat);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/jam.c b/vere/pkg/noun/jets/e/jam.c
new file mode 100644
index 0000000..2291bc0
--- /dev/null
+++ b/vere/pkg/noun/jets/e/jam.c
@@ -0,0 +1,60 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_jam(u3_atom a)
+{
+#if 0
+ if (c3y == u3du(a) && 1337 == u3h(a)) {
+ c3_w siz_w, tot_w = 0;
+ u3_noun som;
+ for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) {
+ siz_w = u3a_count_noun(u3h(som));
+ tot_w += siz_w;
+ if ( 0 == siz_w ) {
+ u3l_log("item: B/0");
+ }
+ else {
+ u3a_print_memory(stderr, "item", siz_w);
+ }
+ }
+ if ( u3_blip != som ) {
+ u3l_log("forgot to terminate list!");
+ }
+ c3_w mem_w = u3h_count(u3R->cax.har_p);
+
+ for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) u3a_discount_noun(u3h(som));
+ u3h_discount(u3R->cax.har_p);
+
+ u3a_print_memory(stderr, "total", tot_w);
+ u3a_print_memory(stderr, "memoization cache", mem_w);
+ u3h_root* har_u = u3to(u3h_root, u3R->cax.har_p);
+ u3l_log("memoization entries: %d", har_u->use_w);
+ u3a_print_memory(stderr, "unused free", u3a_open(u3R));
+ return tot_w;
+ }
+#endif
+
+ u3i_slab sab_u;
+ u3s_jam_fib(&sab_u, a);
+ return u3i_slab_mint(&sab_u);
+}
+
+u3_noun
+u3we_jam(u3_noun cor)
+{
+ return u3qe_jam(u3x_at(u3x_sam, cor));
+}
+
+u3_atom
+u3ke_jam(u3_noun a)
+{
+ u3_atom b = u3qe_jam(a);
+ u3z(a);
+ return b;
+}
diff --git a/vere/pkg/noun/jets/e/json_de.c b/vere/pkg/noun/jets/e/json_de.c
new file mode 100644
index 0000000..e54393a
--- /dev/null
+++ b/vere/pkg/noun/jets/e/json_de.c
@@ -0,0 +1,258 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+#include "pdjson.h"
+
+/*
+** custom code for interfacing with external parser:
+** https://github.com/skeeto/pdjson
+*/
+
+typedef struct _u3qedj_coll {
+ u3_noun col; // collection (list for array, map for object)
+ union { // store context for recursive arrays/objects:
+ u3_noun* tel; // - pointer to tail for array
+ u3_atom key; // - key for object
+ };
+} u3qedj_coll;
+
+static u3qedj_coll*
+_push_stack(const u3a_pile *pil_u)
+{
+ u3qedj_coll *res_u = u3a_push(pil_u);
+ u3a_pile_done(pil_u);
+
+ res_u->col = u3_nul;
+ res_u->key = u3_none;
+
+ return res_u;
+}
+
+static u3qedj_coll*
+_pop_stack(const u3a_pile *pil_u)
+{
+ return u3a_pop(pil_u);
+}
+
+static void
+_close_stack(const u3a_pile *pil_u)
+{
+ while ( c3n == u3a_pile_done(pil_u) ) {
+ u3qedj_coll *tak_u = u3a_peek(pil_u);
+
+ u3z(tak_u->col);
+ if ( u3_none != tak_u->key ) {
+ u3z(tak_u->key);
+ }
+
+ u3a_drop(pil_u);
+ }
+}
+
+static void
+_close_on_error(json_stream *sam_u, const u3a_pile *pil_u)
+{
+ _close_stack(pil_u);
+ json_close(sam_u);
+}
+
+static u3_atom
+_json_get_string_as_atom(json_stream *sam_u) {
+ // length returned by json_get_string includes the trailing null byte
+ // it's possible for json_get_string to return a length of 0, but only if:
+ // - it's called directly after init
+ // - it's called directly after init_string
+ size_t len_i;
+ const c3_c *str_c = json_get_string(sam_u, &len_i);
+ return (len_i <= 1) ?
+ u3_nul :
+ u3i_bytes(len_i - 1, (const c3_y *)str_c);
+}
+
+static u3_noun
+_parse(u3_atom txt)
+{
+ //
+ // vars
+ //
+
+ u3qedj_coll *tak_u;
+
+ json_allocator loc_u = {u3a_malloc, u3a_realloc, u3a_free};
+ json_stream sem_u;
+ json_stream* sam_u = &sem_u;
+
+ u3a_pile pel_u;
+ u3a_pile *pil_u = &pel_u;
+
+ u3_noun res = u3_none;
+ u3_noun val;
+
+ const c3_y *byt_y;
+ c3_z cnt_z;
+ c3_w len_w = u3r_met(3, txt);
+
+ //
+ // initialization
+ //
+
+ // XX assumes little-endian
+ //
+ if ( c3y == u3a_is_cat(txt) ) {
+ byt_y = (c3_y*)&txt;
+ }
+ else {
+ u3a_atom* vat_u = u3a_to_ptr(txt);
+ byt_y = (c3_y*)vat_u->buf_w;
+ }
+ json_open_buffer(sam_u, byt_y, len_w);
+ json_set_allocator(sam_u, &loc_u);
+ u3a_pile_prep(pil_u, sizeof(u3qedj_coll));
+
+ //
+ // core logic
+ //
+
+ while ( json_peek(sam_u) != JSON_DONE ) {
+ switch ( json_next(sam_u) ) {
+ // unreachable barring programming error
+ default: u3_assert(0);
+
+ case JSON_ARRAY:
+ case JSON_OBJECT: {
+ tak_u = _push_stack(pil_u);
+ } continue;
+
+ case JSON_ARRAY_END: {
+ val = u3nc(c3__a, tak_u->col);
+ tak_u = _pop_stack(pil_u);
+ } break;
+
+ case JSON_OBJECT_END: {
+ val = u3nc(c3__o, tak_u->col);
+ tak_u = _pop_stack(pil_u);
+ } break;
+
+ case JSON_STRING: {
+ if ( (json_get_context(sam_u, &cnt_z) == JSON_OBJECT) && (cnt_z & 1) ) {
+ // since object key must be followed by value, skip ahead
+ tak_u->key = _json_get_string_as_atom(sam_u);
+ continue;
+ }
+ else {
+ val = u3nc(c3__s, _json_get_string_as_atom(sam_u));
+ break;
+ }
+ }
+
+ case JSON_NUMBER: {
+ // read number from string in the JSON reparser
+ val = u3nc(c3__n, _json_get_string_as_atom(sam_u));
+ } break;
+
+ case JSON_TRUE: {
+ val = u3nc(c3__b, c3y);
+ } break;
+
+ case JSON_FALSE: {
+ val = u3nc(c3__b, c3n);
+ } break;
+
+ case JSON_NULL: {
+ val = u3_nul;
+ } break;
+
+ case JSON_ERROR: {
+ _close_on_error(sam_u, pil_u);
+ return u3_nul;
+ } break;
+ }
+
+ switch ( json_get_context(sam_u, &cnt_z) ) {
+ // unreachable barring programming error
+ default: u3_assert(0);
+
+ case JSON_DONE: {
+ res = val;
+ } break;
+
+ case JSON_ARRAY: {
+ u3_noun* nex;
+ u3_noun* hed;
+
+ if ( tak_u->col == u3_nul ) {
+ nex = &(tak_u->col);
+ }
+ else {
+ nex = tak_u->tel;
+ }
+
+ *nex = u3i_defcons(&hed, &(tak_u->tel));
+ *hed = val;
+ *(tak_u->tel) = u3_nul;
+ } break;
+
+ case JSON_OBJECT: {
+ // odd cnt_z and unset key weeded out by continue command on key
+ u3_assert(!(cnt_z & 1));
+ u3_assert(tak_u->key != u3_none);
+ // cnt_z == 0 weeded out by continue command on array/object open
+ u3_assert(cnt_z);
+
+ tak_u->col = u3kdb_put(tak_u->col, tak_u->key, val);
+ tak_u->key = u3_none;
+ } break;
+ }
+ }
+
+ //
+ // clean up
+ //
+
+ u3_assert(c3y == u3a_pile_done(pil_u));
+
+ // skip over whitespce
+ while ( json_isspace(json_source_peek(sam_u)) ) {
+ json_source_get(sam_u);
+ }
+
+ json_close(sam_u);
+
+ // return null if trailing trash/multiple JSON objects
+ if ( json_get_position(sam_u) != len_w ) {
+ u3z(res);
+ return u3_nul;
+ }
+ else {
+ return u3nc(u3_nul, res);
+ }
+}
+
+/*
+** jet interface functions
+*/
+
+u3_noun
+u3qe_json_de(u3_atom a)
+{
+ return _parse(a);
+}
+
+u3_noun
+u3ke_json_de(u3_atom a)
+{
+ u3_noun res = u3qe_json_de(a);
+ u3z(a);
+ return res;
+}
+
+u3_noun
+u3we_json_de(u3_noun cor)
+{
+ return u3qe_json_de(u3x_atom(u3x_at(u3x_sam, cor)));
+}
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));
+}
diff --git a/vere/pkg/noun/jets/e/keccak.c b/vere/pkg/noun/jets/e/keccak.c
new file mode 100644
index 0000000..6149c55
--- /dev/null
+++ b/vere/pkg/noun/jets/e/keccak.c
@@ -0,0 +1,42 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+#define defw(bits,byts) \
+ u3_atom \
+ _kecc_##bits(c3_w len_w, u3_atom a) \
+ { \
+ c3_y out[byts]; \
+ c3_y* buf_y = u3r_bytes_alloc(0, len_w, a); \
+ if ( 0 != urcrypt_keccak_##bits(buf_y, len_w, out) ) { \
+ /* urcrypt_keccac_##bits always succeeds when called correctly */ \
+ return u3m_bail(c3__oops); \
+ } \
+ else { \
+ u3_atom pro = u3i_bytes(byts, out); \
+ u3a_free(buf_y); \
+ return pro; \
+ } \
+ } \
+ \
+ u3_weak \
+ u3we_kecc##bits(u3_noun cor) \
+ { \
+ c3_w len_w; \
+ u3_noun len, tom; \
+ u3x_mean(cor, u3x_sam_2, &len, u3x_sam_3, &tom, 0); \
+ return ( (c3n == u3ud(len)) || (c3n == u3ud(tom)) ) \
+ ? u3m_bail(c3__exit) \
+ : (!u3r_word_fit(&len_w, len)) \
+ ? u3m_bail(c3__fail) \
+ : _kecc_##bits(len_w, tom); \
+ }
+
+defw(224, 28)
+defw(256, 32)
+defw(384, 48)
+defw(512, 64)
diff --git a/vere/pkg/noun/jets/e/leer.c b/vere/pkg/noun/jets/e/leer.c
new file mode 100644
index 0000000..8ffe372
--- /dev/null
+++ b/vere/pkg/noun/jets/e/leer.c
@@ -0,0 +1,131 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_atom
+_leer_cut(c3_w pos_w, c3_w len_w, u3_atom src)
+{
+ if ( 0 == len_w ) {
+ return 0;
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 3, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ u3r_bytes(pos_w, len_w, sab_u.buf_y, src);
+
+ return u3i_slab_mint_bytes(&sab_u);
+ }
+}
+
+// Leaving the lore jet in place for backwards compatibility.
+// TODO: remove u3[qw]e_lore (also from jet tree)
+
+u3_noun
+u3qe_lore(u3_atom lub)
+{
+ c3_w len_w = u3r_met(3, lub);
+ c3_w pos_w = 0;
+ u3_noun tez = u3_nul;
+
+ while ( 1 ) {
+ c3_w meg_w = 0;
+ c3_y end_y;
+
+ c3_y byt_y;
+ while ( 1 ) {
+ if ( pos_w >= len_w ) {
+ byt_y = 0;
+ end_y = c3y;
+ break;
+ }
+ byt_y = u3r_byte(pos_w + meg_w, lub);
+
+ if ( (10 == byt_y) || (0 == byt_y) ) {
+ end_y = __(byt_y == 0);
+ break;
+ } else meg_w++;
+ }
+
+ if ((byt_y == 0) && ((pos_w + meg_w + 1) < len_w)) {
+ return u3m_bail(c3__exit);
+ }
+
+ if ( !_(end_y) && pos_w >= len_w ) {
+ return u3kb_flop(tez);
+ }
+ else {
+ tez = u3nc(_leer_cut(pos_w, meg_w, lub), tez);
+ if ( _(end_y) ) {
+ return u3kb_flop(tez);
+ }
+ pos_w += (meg_w + 1);
+ }
+ }
+}
+
+u3_noun
+u3we_lore(u3_noun cor)
+{
+ u3_noun lub;
+
+ if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(lub)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_lore(lub);
+ }
+}
+
+u3_noun
+u3qe_leer(u3_atom txt)
+{
+ u3_noun pro;
+ u3_noun* lit = &pro;
+
+ {
+ c3_w pos_w, i_w = 0, len_w = u3r_met(3, txt);
+ u3_noun* hed;
+ u3_noun* tel;
+
+ while ( i_w < len_w ) {
+ // scan till end or newline
+ //
+ for ( pos_w = i_w; i_w < len_w; ++i_w ) {
+ if ( 10 == u3r_byte(i_w, txt) ) {
+ break;
+ }
+ }
+
+ // append to list
+ //
+ *lit = u3i_defcons(&hed, &tel);
+ *hed = _leer_cut(pos_w, i_w - pos_w, txt);
+ lit = tel;
+
+ i_w++;
+ }
+ }
+
+ *lit = u3_nul;
+
+ return pro;
+}
+
+u3_noun
+u3we_leer(u3_noun cor)
+{
+ u3_noun txt = u3x_at(u3x_sam, cor);
+
+ if ( c3n == u3ud(txt) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ return u3qe_leer(txt);
+}
diff --git a/vere/pkg/noun/jets/e/loss.c b/vere/pkg/noun/jets/e/loss.c
new file mode 100644
index 0000000..35cdc4e
--- /dev/null
+++ b/vere/pkg/noun/jets/e/loss.c
@@ -0,0 +1,297 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ typedef struct _u3_loss { // loss problem
+ u3_noun hel; // a as a list
+ c3_w lel_w; // length of a
+ c3_w lev_w; // length of b
+ u3_noun* hev; // b as an array
+ u3_noun sev; // b as a set of lists
+ c3_w kct_w; // candidate count
+ u3_noun* kad; // candidate array
+ } u3_loss;
+
+ // free loss object
+ //
+ static void
+ _flem(u3_loss* loc_u)
+ {
+ u3z(loc_u->sev);
+ {
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < loc_u->kct_w; i_w++ ) {
+ u3z(loc_u->kad[i_w]);
+ }
+ }
+ u3a_free(loc_u->hev);
+ u3a_free(loc_u->kad);
+ }
+
+ // extract lcs - XX don't use the stack like this
+ //
+ static u3_noun
+ _lext(u3_loss* loc_u,
+ u3_noun kad)
+ {
+ if ( u3_nul == kad ) {
+ return u3_nul;
+ } else {
+ return u3nc(u3k(loc_u->hev[u3r_word(0, u3h(kad))]),
+ _lext(loc_u, u3t(kad)));
+ }
+ }
+
+ // extract lcs
+ //
+ static u3_noun
+ _lexs(u3_loss* loc_u)
+ {
+ if ( 0 == loc_u->kct_w ) {
+ return u3_nul;
+ } else return u3kb_flop(_lext(loc_u, loc_u->kad[loc_u->kct_w - 1]));
+ }
+
+ // initialize loss object
+ //
+ static void
+ _lemp(u3_loss* loc_u,
+ u3_noun hel,
+ u3_noun hev)
+ {
+ loc_u->hel = hel;
+ loc_u->lel_w = u3kb_lent(u3k(hel));
+
+ // Read hev into array.
+ {
+ c3_w i_w;
+
+ loc_u->hev = u3a_malloc(u3kb_lent(u3k(hev)) * sizeof(u3_noun));
+
+ for ( i_w = 0; u3_nul != hev; i_w++ ) {
+ loc_u->hev[i_w] = u3h(hev);
+ hev = u3t(hev);
+ }
+ loc_u->lev_w = i_w;
+ }
+ loc_u->kct_w = 0;
+ loc_u->kad = u3a_malloc((1 + c3_min(loc_u->lev_w, loc_u->lel_w)) *
+ sizeof(u3_noun));
+
+ // Compute equivalence classes.
+ //
+ loc_u->sev = u3_nul;
+ {
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < loc_u->lev_w; i_w++ ) {
+ u3_noun how = loc_u->hev[i_w];
+ u3_noun hav;
+ u3_noun teg;
+
+ hav = u3kdb_get(u3k(loc_u->sev), u3k(how));
+ teg = u3nc(u3i_words(1, &i_w),
+ (hav == u3_none) ? u3_nul : hav);
+ loc_u->sev = u3kdb_put(loc_u->sev, u3k(how), teg);
+ }
+ }
+ }
+
+ // apply
+ //
+ static void
+ _lune(u3_loss* loc_u,
+ c3_w inx_w,
+ c3_w goy_w)
+ {
+ u3_noun kad;
+
+ kad = u3nc(u3i_words(1, &goy_w),
+ (inx_w == 0) ? u3_nul
+ : u3k(loc_u->kad[inx_w - 1]));
+ if ( loc_u->kct_w == inx_w ) {
+ u3_assert(loc_u->kct_w < (1 << 31));
+ loc_u->kct_w++;
+ } else {
+ u3z(loc_u->kad[inx_w]);
+ }
+ loc_u->kad[inx_w] = kad;
+ }
+
+ // extend fits top
+ //
+ static u3_noun
+ _hink(u3_loss* loc_u,
+ c3_w inx_w,
+ c3_w goy_w)
+ {
+ return __
+ ( (loc_u->kct_w == inx_w) ||
+ (u3r_word(0, u3h(loc_u->kad[inx_w])) > goy_w) );
+ }
+
+ // extend fits bottom
+ //
+ static u3_noun
+ _lonk(u3_loss* loc_u,
+ c3_w inx_w,
+ c3_w goy_w)
+ {
+ return __
+ ( (0 == inx_w) ||
+ (u3r_word(0, u3h(loc_u->kad[inx_w - 1])) < goy_w) );
+ }
+
+#if 0
+ // search for first index >= inx_w and <= max_w that fits
+ // the hink and lonk criteria.
+ //
+ static u3_noun
+ _binka(u3_loss* loc_u,
+ c3_w* inx_w,
+ c3_w max_w,
+ c3_w goy_w)
+ {
+ while ( *inx_w <= max_w ) {
+ if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) {
+ return c3n;
+ }
+ if ( c3y == _hink(loc_u, *inx_w, goy_w) ) {
+ return c3y;
+ }
+ else ++*inx_w;
+ }
+ return c3n;
+ }
+#endif
+
+ // search for lowest index >= inx_w and <= max_w for which
+ // both hink(inx_w) and lonk(inx_w) are true. lonk is false
+ // if inx_w is too high, hink is false if it is too low.
+ //
+ static u3_noun
+ _bink(u3_loss* loc_u,
+ c3_w* inx_w,
+ c3_w max_w,
+ c3_w goy_w)
+ {
+ u3_assert(max_w >= *inx_w);
+
+ if ( max_w == *inx_w ) {
+ if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) {
+ return c3n;
+ }
+ if ( c3y == _hink(loc_u, *inx_w, goy_w) ) {
+ return c3y;
+ }
+ else {
+ ++*inx_w;
+ return c3n;
+ }
+ }
+ else {
+ c3_w mid_w = *inx_w + ((max_w - *inx_w) / 2);
+
+ if ( (c3n == _lonk(loc_u, mid_w, goy_w)) ||
+ (c3y == _hink(loc_u, mid_w, goy_w)) )
+ {
+ return _bink(loc_u, inx_w, mid_w, goy_w);
+ } else {
+ *inx_w = mid_w + 1;
+ return _bink(loc_u, inx_w, max_w, goy_w);
+ }
+ }
+ }
+
+
+ static void
+ _merg(u3_loss* loc_u,
+ c3_w inx_w,
+ u3_noun gay)
+ {
+ if ( (u3_nul == gay) || (inx_w > loc_u->kct_w) ) {
+ return;
+ }
+ else {
+ u3_noun i_gay = u3h(gay);
+ c3_w goy_w = u3r_word(0, i_gay);
+ u3_noun bik;
+
+ bik = _bink(loc_u, &inx_w, loc_u->kct_w, goy_w);
+
+ if ( c3y == bik ) {
+ _merg(loc_u, inx_w + 1, u3t(gay));
+ _lune(loc_u, inx_w, goy_w);
+ }
+ else {
+ _merg(loc_u, inx_w, u3t(gay));
+ }
+ }
+ }
+
+ // compute lcs
+ //
+ static void
+ _loss(u3_loss* loc_u)
+ {
+ while ( u3_nul != loc_u->hel ) {
+ u3_noun i_hel = u3h(loc_u->hel);
+ u3_noun guy = u3kdb_get(u3k(loc_u->sev), u3k(i_hel));
+
+ if ( u3_none != guy ) {
+ u3_noun gay = u3kb_flop(guy);
+
+ _merg(loc_u, 0, gay);
+ u3z(gay);
+ }
+
+ loc_u->hel = u3t(loc_u->hel);
+ }
+ }
+
+ u3_noun
+ u3qe_loss(u3_noun hel,
+ u3_noun hev)
+ {
+ u3_loss loc_u;
+ u3_noun lcs;
+
+ _lemp(&loc_u, hel, hev);
+ _loss(&loc_u);
+ lcs = _lexs(&loc_u);
+
+ _flem(&loc_u);
+ return lcs;
+ }
+
+ static u3_noun
+ _listp(u3_noun lix)
+ {
+ while ( 1 ) {
+ if ( u3_nul == lix ) return c3y;
+ if ( c3n == u3du(lix) ) return c3n;
+ lix = u3t(lix);
+ }
+ }
+
+ u3_noun
+ u3we_loss(u3_noun cor)
+ {
+ u3_noun hel, hev;
+
+ if ( (u3_none == (hel = u3r_at(u3x_sam_2, cor))) ||
+ (u3_none == (hev = u3r_at(u3x_sam_3, cor))) ||
+ (c3n == _listp(hel)) ||
+ (c3n == _listp(hev)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_loss(hel, hev);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/lune.c b/vere/pkg/noun/jets/e/lune.c
new file mode 100644
index 0000000..1187073
--- /dev/null
+++ b/vere/pkg/noun/jets/e/lune.c
@@ -0,0 +1,57 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qe_lune(u3_atom lub)
+ {
+ if (lub == 0) {
+ return u3_nul;
+ }
+
+ {
+ c3_w end_w = u3r_met(3, lub) - 1;
+ c3_w pos_w = end_w;
+ u3_noun lin = u3_nul;
+
+ if (u3r_byte(pos_w, lub) != 10) {
+ return u3m_error("noeol");
+ }
+
+ if (pos_w == 0) {
+ return u3nc(u3_nul, lin);
+ }
+
+ while (--pos_w) {
+ if (u3r_byte(pos_w, lub) == 10) {
+ lin = u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin);
+ end_w = pos_w;
+ }
+ }
+
+ if (u3r_byte(pos_w, lub) == 10) {
+ return u3nc(u3_nul,
+ u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin));
+ }
+
+ return u3nc(u3qc_cut(3, pos_w, (end_w - pos_w), lub), lin);
+ }
+ }
+
+ u3_noun
+ u3we_lune(u3_noun cor)
+ {
+ u3_noun lub;
+
+ if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(lub)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_lune(lub);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/mat.c b/vere/pkg/noun/jets/e/mat.c
new file mode 100644
index 0000000..89de386
--- /dev/null
+++ b/vere/pkg/noun/jets/e/mat.c
@@ -0,0 +1,49 @@
+ /// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3qe_mat(u3_atom a)
+ {
+ if ( 0 == a ) {
+ return u3nc(1, 1);
+ } else {
+ u3_atom b = u3qc_met(0, a);
+ u3_atom c = u3qc_met(0, b);
+ u3_atom u, v, w, x, y, z;
+ u3_atom p, q;
+
+ u = u3qa_dec(c);
+ v = u3qa_add(c, c);
+ w = u3qc_bex(c);
+ x = u3qc_end(0, u, b);
+ y = u3qc_lsh(0, u, a);
+ z = u3qc_mix(x, y);
+
+ p = u3qa_add(v, b);
+ q = u3qc_cat(0, w, z);
+
+ u3z(u);
+ u3z(v);
+ u3z(w);
+ u3z(x);
+ u3z(y);
+ u3z(z);
+
+ return u3nc(p, q);
+ }
+ }
+ u3_noun
+ u3we_mat(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_mat(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/mice.c b/vere/pkg/noun/jets/e/mice.c
new file mode 100644
index 0000000..81b4a33
--- /dev/null
+++ b/vere/pkg/noun/jets/e/mice.c
@@ -0,0 +1,23 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+/* variant of u3we_mink() / u3m_soft_run(). caching, no scry.
+*/
+u3_noun
+u3we_mice(u3_noun cor) {
+ u3_noun bus, fol;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &bus,
+ u3x_sam_3, &fol,
+ 0) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3m_soft_cax(u3n_nock_on, u3k(bus), u3k(fol));
+ }
+}
diff --git a/vere/pkg/noun/jets/e/mink.c b/vere/pkg/noun/jets/e/mink.c
new file mode 100644
index 0000000..4caa208
--- /dev/null
+++ b/vere/pkg/noun/jets/e/mink.c
@@ -0,0 +1,27 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ u3_noun
+ u3we_mink(u3_noun cor)
+ {
+ u3_noun bus, fol, gul;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_4, &bus,
+ u3x_sam_5, &fol,
+ u3x_sam_3, &gul,
+ 0) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun som;
+
+ som = u3n_nock_et(u3k(gul), u3k(bus), u3k(fol));
+
+ return som;
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/mole.c b/vere/pkg/noun/jets/e/mole.c
new file mode 100644
index 0000000..a318390
--- /dev/null
+++ b/vere/pkg/noun/jets/e/mole.c
@@ -0,0 +1,18 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3we_mole(u3_noun cor)
+{
+ u3_noun hok = u3j_cook("u3we_mole-mure", u3k(cor), "mure");
+
+ // just like +mule and +mute, this takes advantage of the fact that
+ // +mure's result is identical to that of +mole, and safely produces
+ // a statically-typed value while only evaluating the trap once.
+ //
+ return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/e/mule.c b/vere/pkg/noun/jets/e/mule.c
new file mode 100644
index 0000000..79e4656
--- /dev/null
+++ b/vere/pkg/noun/jets/e/mule.c
@@ -0,0 +1,19 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3we_mule(u3_noun cor)
+{
+ u3_noun hok = u3j_cook("u3we_mule-mute", u3k(cor), "mute");
+
+
+ // this takes advantage of the fact that +mute's result is
+ // identical to that of +mule, and safely produces a statically-typed
+ // value while only evaluating the trap once.
+ //
+ return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor)));
+}
diff --git a/vere/pkg/noun/jets/e/parse.c b/vere/pkg/noun/jets/e/parse.c
new file mode 100644
index 0000000..4ae8ab0
--- /dev/null
+++ b/vere/pkg/noun/jets/e/parse.c
@@ -0,0 +1,1052 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+ // get p.u.q.vex from an $edge, assumes that the unit is non-empty
+ // RETAIN [vex]
+ //
+ static inline u3_noun
+ _puq(u3_noun vex)
+ {
+ u3_weak pro = u3r_at(14, vex);
+ c3_dessert(u3_none != pro);
+ return (u3_noun)pro;
+ }
+
+ // get q.u.q.vex from an $edge, assumes that the unit is non-empty
+ // RETAIN [vex]
+ //
+ static inline u3_noun
+ _quq(u3_noun vex)
+ {
+ u3_weak pro = u3r_at(15, vex);
+ c3_dessert(u3_none != pro);
+ return (u3_noun)pro;
+ }
+
+ #define _p u3h
+ #define _q u3t
+
+ static u3_noun
+ _slip(u3_noun weq,
+ u3_noun naz)
+ {
+ u3_noun p_naz, q_naz;
+
+ u3x_cell(naz, &p_naz, &q_naz);
+ if ( 10 == weq ) {
+ return u3nc(u3i_vint(u3k(p_naz)), 1);
+ } else {
+ return u3nc(u3k(p_naz), u3i_vint(u3k(q_naz)));
+ }
+ }
+
+ static u3_noun
+ _fail(u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+ return u3nc(u3k(p_tub), u3_nul);
+ }
+
+ static u3_noun
+ _last(u3_noun zyc,
+ u3_noun naz)
+ {
+ u3_noun p_zyc, q_zyc, p_naz, q_naz;
+
+ u3x_cell(zyc, &p_zyc, &q_zyc);
+ u3x_cell(naz, &p_naz, &q_naz);
+
+ if ( !_(u3a_is_cat(p_zyc)) || !_(u3a_is_cat(q_zyc)) ||
+ !_(u3a_is_cat(p_naz)) || !_(u3a_is_cat(q_naz)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ if ( p_zyc == p_naz ) {
+ return (q_zyc > q_naz) ? u3k(zyc) : u3k(naz);
+ }
+ else {
+ return (p_zyc > p_naz) ? u3k(zyc) : u3k(naz);
+ }
+ }
+ }
+
+ static u3_noun
+ _last_k(u3_noun zyc, u3_noun naz)
+ {
+ u3_noun pro = _last(zyc, naz);
+ u3z(zyc); u3z(naz);
+ return pro;
+ }
+
+ static u3_noun
+ _next(u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+ u3_noun zac;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+ if ( c3n == u3du(q_tub) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun iq_tub = u3h(q_tub);
+ u3_noun tq_tub = u3t(q_tub);
+
+ zac = _slip(iq_tub, p_tub);
+
+ return u3nc(zac,
+ u3nq(u3_nul,
+ u3k(iq_tub),
+ u3k(zac),
+ u3k(tq_tub)));
+ }
+ }
+
+/* bend
+*/
+ static u3_noun
+ _cqe_bend_fun(u3_noun raq,
+ u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ } else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun quq_vex;
+ u3_noun yit, yur;
+ u3_noun p_yit, q_yit;
+ u3_noun ret;
+
+ quq_vex = u3t(uq_vex);
+
+ yit = u3n_slam_on(u3k(sab), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ yur = _last(_p(vex), p_yit);
+
+ if ( c3n == u3du(q_yit) ) {
+ ret = u3nc(yur, u3k(q_vex));
+ }
+ else {
+ u3_noun uq_yit = u3t(q_yit);
+ u3_noun puq_yit;
+ u3_noun vux;
+
+ puq_yit = u3h(uq_yit);
+
+ vux = u3n_slam_on(u3k(raq),
+ u3nc(u3k(_puq(vex)),
+ u3k(puq_yit)));
+ if ( u3_nul == vux ) {
+ ret = u3nc(yur, u3k(_q(vex)));
+ }
+ else {
+ ret = u3nq(yur,
+ u3_nul,
+ u3k(u3t(vux)),
+ u3k(_quq(yit)));
+ u3z(vux);
+ }
+ }
+ u3z(yit);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_bend_fun(u3_noun cor)
+ {
+ u3_noun van, raq, vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex,
+ u3x_sam_3, &sab,
+ u3x_con, &van, 0)) ||
+ (u3_none == (raq = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_bend_fun(raq, vex, sab);
+ }
+ }
+
+/* cold
+*/
+ static u3_noun
+ _cqe_cold_fun(u3_noun cus,
+ u3_noun sef,
+ u3_noun tub)
+ {
+ u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub));
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+
+ if ( c3n == u3du(q_vex) ) {
+ return vex;
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun quq_vex;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, 0, &quq_vex);
+ ret = u3nq(u3k(p_vex),
+ u3_nul,
+ u3k(cus),
+ u3k(quq_vex));
+
+ u3z(vex);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_cold_fun(u3_noun cor)
+ {
+ u3_noun van, cus, sef, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (c3n == u3r_mean(van, u3x_sam_2, &cus, u3x_sam_3, &sef, 0)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_cold_fun(cus, sef, tub);
+ }
+ }
+
+/* cook
+*/
+ static u3_noun
+ _cqe_cook_fun(u3_noun poq,
+ u3_noun sef,
+ u3_noun tub)
+ {
+ u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub));
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+
+ if ( c3n == u3du(q_vex) ) {
+ return vex;
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun puq_vex, quq_vex;
+ u3_noun wag;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+
+ u3k(quq_vex);
+ u3k(p_vex);
+ wag = u3n_slam_on(u3k(poq), u3k(puq_vex));
+
+ ret = u3nq(p_vex,
+ u3_nul,
+ wag,
+ quq_vex);
+
+ u3z(vex);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_cook_fun(u3_noun cor)
+ {
+ u3_noun van, poq, sef, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (c3n == u3r_mean(van, u3x_sam_2, &poq, u3x_sam_3, &sef, 0)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_cook_fun(poq, sef, tub);
+ }
+ }
+
+/* comp
+*/
+ static u3_noun
+ _cqe_comp_fun(u3_noun raq,
+ u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ } else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun puq_vex, quq_vex;
+ u3_noun yit, yur;
+ u3_noun p_yit, q_yit;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+ yit = u3n_slam_on(u3k(sab), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ yur = _last(_p(vex), p_yit);
+
+ if ( c3n == u3du(q_yit) ) {
+ ret = u3nc(yur, u3k(q_yit));
+ }
+ else {
+ u3_noun uq_yit = u3t(q_yit);
+ u3_noun puq_yit, quq_yit;
+
+ u3x_cell(uq_yit, &puq_yit, &quq_yit);
+
+ u3k(quq_yit);
+ ret = u3nq(yur,
+ u3_nul,
+ u3n_slam_on(u3k(raq),
+ u3nc(u3k(_puq(vex)),
+ u3k(puq_yit))),
+ quq_yit);
+ }
+ u3z(yit);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_comp_fun(u3_noun cor)
+ {
+ u3_noun van, raq, vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex,
+ u3x_sam_3, &sab,
+ u3x_con, &van, 0)) ||
+ (u3_none == (raq = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_comp_fun(raq, vex, sab);
+ }
+ }
+
+/* easy
+*/
+ static u3_noun
+ _cqe_easy_fun(u3_noun huf,
+ u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+ return u3nq(u3k(p_tub),
+ u3_nul,
+ u3k(huf),
+ u3k(tub));
+ }
+
+ u3_noun
+ u3we_easy_fun(u3_noun cor)
+ {
+ u3_noun van, huf, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (u3_none == (huf = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_easy_fun(huf, tub);
+ }
+ }
+
+/* glue
+*/
+ static u3_noun
+ _cqe_glue_fun(u3_noun bus,
+ u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun puq_vex, quq_vex;
+ u3_noun yit, yur;
+ u3_noun p_yit, q_yit;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+ yit = u3n_slam_on(u3k(bus), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ yur = _last(_p(vex), p_yit);
+
+ if ( c3n == u3du(q_yit) ) {
+ ret = u3nc(yur, u3_nul);
+ }
+ else {
+ u3_noun uq_yit = u3t(q_yit);
+ u3_noun puq_yit, quq_yit;
+ u3_noun wam, p_wam, q_wam, goy;
+
+ u3x_cell(uq_yit, &puq_yit, &quq_yit);
+ wam = u3n_slam_on(u3k(sab), u3k(quq_yit));
+
+ u3x_cell(wam, &p_wam, &q_wam);
+ goy = _last(yur, p_wam);
+ u3z(yur);
+
+ if ( c3n == u3du(q_wam) ) {
+ ret = u3nc(goy, u3_nul);
+ } else {
+ u3_noun uq_wam = u3t(q_wam);
+ u3_noun puq_wam, quq_wam;
+
+ u3x_cell(uq_wam, &puq_wam, &quq_wam);
+ ret = u3nq(goy,
+ u3_nul,
+ u3nc(u3k(_puq(vex)),
+ u3k(puq_wam)),
+ u3k(quq_wam));
+ }
+ u3z(wam);
+ }
+ u3z(yit);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_glue_fun(u3_noun cor)
+ {
+ u3_noun van, bus, vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex,
+ u3x_sam_3, &sab,
+ u3x_con, &van, 0)) ||
+ (u3_none == (bus = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_glue_fun(bus, vex, sab);
+ }
+ }
+
+/* here
+*/
+ static u3_noun
+ _cqe_here_fun(u3_noun hez,
+ u3_noun sef,
+ u3_noun tub)
+ {
+ u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub));
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+
+ if ( c3n == u3du(q_vex) ) {
+ return vex;
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun p_tub, q_tub;
+ u3_noun puq_vex, quq_vex, pquq_vex;
+ u3_noun gud, wag;
+ u3_noun ret;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+ u3x_cell(quq_vex, &pquq_vex, 0);
+ gud = u3nc(
+ u3nc(u3k(p_tub),
+ u3k(pquq_vex)),
+ u3k(puq_vex));
+
+ u3k(p_vex);
+ u3k(quq_vex);
+ wag = u3n_slam_on(u3k(hez), gud);
+ ret = u3nq(p_vex,
+ u3_nul,
+ wag,
+ quq_vex);
+
+ u3z(vex);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_here_fun(u3_noun cor)
+ {
+ u3_noun van, hez, sef, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (c3n == u3r_mean(van, u3x_sam_2, &hez, u3x_sam_3, &sef, 0)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return _cqe_here_fun(hez, sef, tub);
+ }
+ }
+
+/* just
+*/
+ static u3_noun
+ _cqe_just_fun(u3_noun daf,
+ u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+
+ if ( c3n == u3du(q_tub) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun iq_tub = u3h(q_tub);
+
+ if ( c3y == u3r_sing(daf, iq_tub) ) {
+ return _next(tub);
+ }
+ else return _fail(tub);
+ }
+ }
+ u3_noun
+ u3we_just_fun(u3_noun cor)
+ {
+ u3_noun van, daf, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (u3_none == (daf = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_just_fun(daf, tub);
+ }
+ }
+
+/* mask
+*/
+ static u3_noun
+ _cqe_mask_fun(u3_noun bud,
+ u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+
+ if ( c3n == u3du(q_tub) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun iq_tub = u3h(q_tub);
+
+ while ( c3y == u3du(bud) ) {
+ if ( c3y == u3r_sing(u3h(bud), iq_tub) ) {
+ return _next(tub);
+ }
+ bud = u3t(bud);
+ }
+ return _fail(tub);
+ }
+ }
+ u3_noun
+ u3we_mask_fun(u3_noun cor)
+ {
+ u3_noun van, bud, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (u3_none == (bud = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_mask_fun(bud, tub);
+ }
+ }
+/* pfix
+*/
+ static u3_noun
+ _cqe_pfix(u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun q_vex;
+
+ q_vex = u3t(vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun quq_vex;
+ u3_noun yit, p_yit, q_yit;
+ u3_noun ret;
+
+ quq_vex = u3t(uq_vex);
+
+ yit = u3n_slam_on(u3k(sab), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ ret = u3nc(_last(_p(vex), p_yit),
+ u3k(q_yit));
+
+ u3z(yit);
+ return ret;
+ }
+ }
+ u3_noun
+ u3we_pfix(u3_noun cor)
+ {
+ u3_noun vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_pfix(vex, sab);
+ }
+ }
+
+/* plug
+*/
+ static u3_noun
+ _cqe_plug(u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun puq_vex, quq_vex;
+ u3_noun yit, yur;
+ u3_noun p_yit, q_yit;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+ yit = u3n_slam_on(u3k(sab), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ yur = _last(_p(vex), p_yit);
+
+ if ( c3n == u3du(q_yit) ) {
+ ret = u3nc(yur, u3k(q_yit));
+ }
+ else {
+ u3_noun uq_yit = u3t(q_yit);
+ u3_noun puq_yit, quq_yit;
+
+ u3x_cell(uq_yit, &puq_yit, &quq_yit);
+ ret = u3nq(yur,
+ u3_nul,
+ u3nc(u3k(_puq(vex)),
+ u3k(puq_yit)),
+ u3k(quq_yit));
+ }
+ u3z(yit);
+ return ret;
+ }
+ }
+ u3_noun
+ u3we_plug(u3_noun cor)
+ {
+ u3_noun vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_plug(vex, sab);
+ }
+ }
+
+/* pose
+*/
+ u3_noun
+ u3qe_pose(u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun q_vex;
+
+ q_vex = u3t(vex);
+ if ( c3y == u3du(q_vex) ) {
+ return u3k(vex);
+ } else {
+ u3_noun roq = u3n_kick_on(u3k(sab));
+ u3_noun p_roq, q_roq;
+ u3_noun ret;
+
+ u3x_cell(roq, &p_roq, &q_roq);
+ ret = u3nc(_last(_p(vex), p_roq),
+ u3k(q_roq));
+
+ u3z(roq);
+ return ret;
+ }
+ }
+ u3_noun
+ u3we_pose(u3_noun cor)
+ {
+ u3_noun vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qe_pose(vex, sab);
+ }
+ }
+
+/* sfix
+*/
+ static u3_noun
+ _cqe_sfix(u3_noun vex,
+ u3_noun sab)
+ {
+ u3_noun q_vex;
+
+ q_vex = u3t(vex);
+ if ( c3n == u3du(q_vex) ) {
+ return u3k(vex);
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun quq_vex;
+ u3_noun yit, p_yit, q_yit, yur;
+ u3_noun ret;
+
+ quq_vex = u3t(uq_vex);
+
+ yit = u3n_slam_on(u3k(sab), u3k(quq_vex));
+
+ u3x_cell(yit, &p_yit, &q_yit);
+ yur = _last(_p(vex), p_yit);
+
+ if ( c3n == u3du(q_yit) ) {
+ ret = u3nc(yur, u3_nul);
+ }
+ else {
+ u3_noun uq_yit = u3t(q_yit);
+ u3_noun puq_yit, quq_yit;
+
+ u3x_cell(uq_yit, &puq_yit, &quq_yit);
+
+ ret = u3nq(yur,
+ u3_nul,
+ u3k(_puq(vex)),
+ u3k(quq_yit));
+ }
+ u3z(yit);
+ return ret;
+ }
+ }
+ u3_noun
+ u3we_sfix(u3_noun cor)
+ {
+ u3_noun vex, sab;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_sfix(vex, sab);
+ }
+ }
+
+/* shim
+*/
+ static u3_noun
+ _cqe_shim_fun(u3_noun zep,
+ u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+
+ if ( c3n == u3du(q_tub) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun p_zep, q_zep;
+ u3_noun iq_tub = u3h(q_tub);
+
+ u3x_cell(zep, &p_zep, &q_zep);
+ if ( _(u3a_is_cat(p_zep)) &&
+ _(u3a_is_cat(q_zep)) &&
+ _(u3a_is_cat(iq_tub)) )
+ {
+ if ( (iq_tub >= p_zep) && (iq_tub <= q_zep) ) {
+ return _next(tub);
+ }
+ else return _fail(tub);
+ }
+ else {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ u3_noun
+ u3we_shim_fun(u3_noun cor)
+ {
+ u3_noun van, zep, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (u3_none == (zep = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_shim_fun(zep, tub);
+ }
+ }
+
+/* stag
+*/
+ static u3_noun
+ _cqe_stag_fun(u3_noun gob,
+ u3_noun sef,
+ u3_noun tub)
+ {
+ u3_noun vex = u3n_slam_on(u3k(sef), u3k(tub));
+ u3_noun p_vex, q_vex;
+
+ u3x_cell(vex, &p_vex, &q_vex);
+
+ if ( c3n == u3du(q_vex) ) {
+ return vex;
+ }
+ else {
+ u3_noun uq_vex = u3t(q_vex);
+ u3_noun puq_vex, quq_vex;
+ u3_noun wag;
+ u3_noun ret;
+
+ u3x_cell(uq_vex, &puq_vex, &quq_vex);
+ wag = u3nc(u3k(gob), u3k(puq_vex));
+ ret = u3nq(u3k(p_vex),
+ u3_nul,
+ wag,
+ u3k(quq_vex));
+
+ u3z(vex);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_stag_fun(u3_noun cor)
+ {
+ u3_noun van, gob, sef, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (c3n == u3r_mean(van, u3x_sam_2, &gob, u3x_sam_3, &sef, 0)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_stag_fun(gob, sef, tub);
+ }
+ }
+
+/* stew
+*/
+ static u3_noun
+ _stew_wor(u3_noun ort,
+ u3_noun wan)
+ {
+ if ( !_(u3a_is_cat(ort)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ if ( c3n == u3du(wan) ) {
+ if ( !_(u3a_is_cat(wan)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else return (ort < wan) ? c3y : c3n;
+ }
+ else {
+ u3_noun h_wan = u3h(wan);
+
+ if ( !_(u3a_is_cat(h_wan)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else return (ort < h_wan) ? c3y : c3n;
+ }
+ }
+ }
+
+ static u3_noun
+ _cqe_stew_fun(u3_noun hel,
+ u3_noun tub)
+ {
+ u3_noun p_tub, q_tub;
+
+ u3x_cell(tub, &p_tub, &q_tub);
+ if ( c3n == u3du(q_tub) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun iq_tub = u3h(q_tub);
+
+ if ( !_(u3a_is_cat(iq_tub)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else while ( 1 ) {
+ if ( c3n == u3du(hel) ) {
+ return _fail(tub);
+ }
+ else {
+ u3_noun n_hel, l_hel, r_hel;
+ u3_noun pn_hel, qn_hel;
+ c3_o bit_o;
+
+ u3x_trel(hel, &n_hel, &l_hel, &r_hel);
+ u3x_cell(n_hel, &pn_hel, &qn_hel);
+
+ if ( (c3n == u3du(pn_hel)) ) {
+ bit_o = __((iq_tub == pn_hel));
+ }
+ else {
+ u3_noun hpn_hel = u3h(pn_hel);
+ u3_noun tpn_hel = u3t(pn_hel);
+
+ if ( !_(u3a_is_cat(hpn_hel)) ||
+ !_(u3a_is_cat(tpn_hel)) ) {
+ return _fail(tub);
+ }
+ else bit_o = __((iq_tub >= hpn_hel) && (iq_tub <= tpn_hel));
+ }
+
+ if ( c3y == bit_o ) {
+ return u3n_slam_on(u3k(qn_hel), u3k(tub));
+ } else {
+ if ( c3y == _stew_wor(iq_tub, pn_hel) ) {
+ hel = l_hel;
+ }
+ else hel = r_hel;
+ }
+ }
+ }
+ }
+ }
+ u3_noun
+ u3we_stew_fun(u3_noun cor)
+ {
+ u3_noun con, hel, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &con, 0)) ||
+ (u3_none == (hel = u3r_at(2, con))) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_stew_fun(hel, tub);
+ }
+ }
+
+/* _stir_pair(): stack frame recording intermediate parse results
+*/
+ typedef struct {
+ u3_noun har; // hair, p_vex
+ u3_noun res; // parse-result, puq_vex
+ } _stir_pair;
+
+/* stir
+*/
+ static u3_noun
+ _cqe_stir_fun(u3_noun rud,
+ u3_noun raq,
+ u3_noun fel,
+ u3_noun tub)
+ {
+ // pil_u: stack control structure
+ // par_u: frame pointer
+ // wag: initial accumulator (deconstructed)
+ //
+ u3a_pile pil_u;
+ _stir_pair* par_u;
+ u3_noun p_wag, puq_wag, quq_wag;
+
+ u3a_pile_prep(&pil_u, sizeof(*par_u));
+
+ // push incremental, successful [fel] parse results onto road stack
+ //
+ {
+ u3_noun vex, p_vex, q_vex, puq_vex, quq_vex;
+ u3j_site fel_u;
+ u3j_gate_prep(&fel_u, u3k(fel));
+
+ vex = u3j_gate_slam(&fel_u, u3k(tub));
+ u3x_cell(vex, &p_vex, &q_vex);
+
+ u3k(tub);
+
+ while ( u3_nul != q_vex ) {
+ u3x_trel(q_vex, 0, &puq_vex, &quq_vex);
+
+ par_u = u3a_push(&pil_u);
+ par_u->har = u3k(p_vex);
+ par_u->res = u3k(puq_vex);
+
+ u3z(tub);
+ tub = u3k(quq_vex);
+
+ u3z(vex);
+ vex = u3j_gate_slam(&fel_u, u3k(tub));
+ u3x_cell(vex, &p_vex, &q_vex);
+ }
+
+ p_wag = u3k(p_vex);
+ puq_wag = u3k(rud);
+ quq_wag = tub;
+
+ u3z(vex);
+ u3j_gate_lose(&fel_u);
+ }
+
+ // unwind the stack, folding parse results into [wag] by way of [raq]
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ u3j_site raq_u;
+ u3j_gate_prep(&raq_u, u3k(raq));
+
+ while ( c3n == u3a_pile_done(&pil_u) ) {
+ p_wag = _last_k(par_u->har, p_wag);
+ puq_wag = u3j_gate_slam(&raq_u, u3nc(par_u->res, puq_wag));
+ par_u = u3a_pop(&pil_u);
+ }
+
+ u3j_gate_lose(&raq_u);
+ }
+
+ return u3nq(p_wag, u3_nul, puq_wag, quq_wag);
+ }
+
+ u3_noun
+ u3we_stir_fun(u3_noun cor)
+ {
+ u3_noun van, rud, raq, fel, tub;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) ||
+ (c3n == u3r_mean(van, u3x_sam_2, &rud,
+ u3x_sam_6, &raq,
+ u3x_sam_7, &fel,
+ 0)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return _cqe_stir_fun(rud, raq, fel, tub);
+ }
+ }
+
+ #undef _p
+ #undef _q
+ \ No newline at end of file
diff --git a/vere/pkg/noun/jets/e/rd.c b/vere/pkg/noun/jets/e/rd.c
new file mode 100644
index 0000000..a693e3f
--- /dev/null
+++ b/vere/pkg/noun/jets/e/rd.c
@@ -0,0 +1,390 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "softfloat.h"
+
+#define DOUBNAN 0x7ff8000000000000
+
+ union doub {
+ float64_t d;
+ c3_d c;
+ };
+
+ static inline c3_t
+ _nan_test(float64_t a)
+ {
+ return !f64_eq(a, a);
+ }
+
+ static inline float64_t
+ _nan_unify(float64_t a)
+ {
+ if ( _nan_test(a) )
+ {
+ *(c3_d*)(&a) = DOUBNAN;
+ }
+ return a;
+ }
+
+ static inline void
+ _set_rounding(c3_w a)
+ {
+ switch ( a )
+ {
+ default:
+ u3m_bail(c3__fail);
+ break;
+ case c3__n:
+ softfloat_roundingMode = softfloat_round_near_even;
+ break;
+ case c3__z:
+ softfloat_roundingMode = softfloat_round_minMag;
+ break;
+ case c3__u:
+ softfloat_roundingMode = softfloat_round_max;
+ break;
+ case c3__d:
+ softfloat_roundingMode = softfloat_round_min;
+ break;
+ }
+ }
+
+/* add
+*/
+ u3_noun
+ u3qer_add(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union doub c, d, e;
+ _set_rounding(r);
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+ e.d = _nan_unify(f64_add(c.d, d.d));
+
+ return u3i_chubs(1, &e.c);
+ }
+
+ u3_noun
+ u3wer_add(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_add(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sub
+*/
+ u3_noun
+ u3qer_sub(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union doub c, d, e;
+ _set_rounding(r);
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+ e.d = _nan_unify(f64_sub(c.d, d.d));
+
+ return u3i_chubs(1, &e.c);
+ }
+
+ u3_noun
+ u3wer_sub(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_sub(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* mul
+*/
+ u3_noun
+ u3qer_mul(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union doub c, d, e;
+ _set_rounding(r);
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+ e.d = _nan_unify(f64_mul(c.d, d.d));
+
+ return u3i_chubs(1, &e.c);
+ }
+
+ u3_noun
+ u3wer_mul(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_mul(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* div
+*/
+ u3_noun
+ u3qer_div(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union doub c, d, e;
+ _set_rounding(r);
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+ e.d = _nan_unify(f64_div(c.d, d.d));
+
+ return u3i_chubs(1, &e.c);
+ }
+
+ u3_noun
+ u3wer_div(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_div(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sqt
+*/
+ u3_noun
+ u3qer_sqt(u3_atom a,
+ u3_atom r)
+ {
+ union doub c, d;
+ _set_rounding(r);
+ c.c = u3r_chub(0, a);
+ d.d = _nan_unify(f64_sqrt(c.d));
+
+ return u3i_chubs(1, &d.c);
+ }
+
+ u3_noun
+ u3wer_sqt(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( c3n == (a = u3r_at(u3x_sam, cor)) ||
+ c3n == u3ud(a) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_sqt(a, u3x_at(30, cor));
+ }
+ }
+
+/* fma
+*/
+ u3_noun
+ u3qer_fma(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom r)
+ {
+ union doub d, e, f, g;
+ _set_rounding(r);
+ d.c = u3r_chub(0, a);
+ e.c = u3r_chub(0, b);
+ f.c = u3r_chub(0, c);
+ g.d = _nan_unify(f64_mulAdd(d.d, e.d, f.d));
+
+ return u3i_chubs(1, &g.c);
+ }
+
+ u3_noun
+ u3wer_fma(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ||
+ c3n == u3ud(c) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_fma(a, b, c, u3x_at(30, cor));
+ }
+ }
+
+/* lth
+*/
+ u3_noun
+ u3qer_lth(u3_atom a,
+ u3_atom b)
+ {
+ union doub c, d;
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+
+ return __(f64_lt(c.d, d.d));
+ }
+
+ u3_noun
+ u3wer_lth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_lth(a, b);
+ }
+ }
+
+/* lte
+*/
+ u3_noun
+ u3qer_lte(u3_atom a,
+ u3_atom b)
+ {
+ union doub c, d;
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+
+ return __(f64_le(c.d, d.d));
+ }
+
+ u3_noun
+ u3wer_lte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_lte(a, b);
+ }
+ }
+
+/* equ
+*/
+ u3_noun
+ u3qer_equ(u3_atom a,
+ u3_atom b)
+ {
+ union doub c, d;
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+
+ return __(f64_eq(c.d, d.d));
+ }
+
+ u3_noun
+ u3wer_equ(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_equ(a, b);
+ }
+ }
+
+/* gte
+*/
+ u3_noun
+ u3qer_gte(u3_atom a,
+ u3_atom b)
+ {
+ union doub c, d;
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+
+ return __(f64_le(d.d, c.d));
+ }
+
+ u3_noun
+ u3wer_gte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_gte(a, b);
+ }
+ }
+
+/* gth
+*/
+ u3_noun
+ u3qer_gth(u3_atom a,
+ u3_atom b)
+ {
+ union doub c, d;
+ c.c = u3r_chub(0, a);
+ d.c = u3r_chub(0, b);
+
+ return __(f64_lt(d.d, c.d));
+ }
+
+ u3_noun
+ u3wer_gth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qer_gth(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/rh.c b/vere/pkg/noun/jets/e/rh.c
new file mode 100644
index 0000000..3bbb8d4
--- /dev/null
+++ b/vere/pkg/noun/jets/e/rh.c
@@ -0,0 +1,390 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "softfloat.h"
+
+#define HALFNAN 0x7e00
+
+ union half {
+ float16_t h;
+ c3_s c;
+ };
+
+ static inline c3_t
+ _nan_test(float16_t a)
+ {
+ return !f16_eq(a, a);
+ }
+
+ static inline float16_t
+ _nan_unify(float16_t a)
+ {
+ if ( _nan_test(a) )
+ {
+ *(c3_s*)(&a) = HALFNAN;
+ }
+ return a;
+ }
+
+ static inline void
+ _set_rounding(c3_w a)
+ {
+ switch ( a )
+ {
+ default:
+ u3m_bail(c3__fail);
+ break;
+ case c3__n:
+ softfloat_roundingMode = softfloat_round_near_even;
+ break;
+ case c3__z:
+ softfloat_roundingMode = softfloat_round_minMag;
+ break;
+ case c3__u:
+ softfloat_roundingMode = softfloat_round_max;
+ break;
+ case c3__d:
+ softfloat_roundingMode = softfloat_round_min;
+ break;
+ }
+ }
+
+/* add
+*/
+ u3_noun
+ u3qes_add(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union half c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.h = _nan_unify(f16_add(c.h, d.h));
+
+ return e.c;
+ }
+
+ u3_noun
+ u3wes_add(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_add(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sub
+*/
+ u3_noun
+ u3qes_sub(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union half c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.h = _nan_unify(f16_sub(c.h, d.h));
+
+ return e.c;
+ }
+
+ u3_noun
+ u3wes_sub(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_sub(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* mul
+*/
+ u3_noun
+ u3qes_mul(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union half c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.h = _nan_unify(f16_mul(c.h, d.h));
+
+ return e.c;
+ }
+
+ u3_noun
+ u3wes_mul(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_mul(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* div
+*/
+ u3_noun
+ u3qes_div(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union half c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.h = _nan_unify(f16_div(c.h, d.h));
+
+ return e.c;
+ }
+
+ u3_noun
+ u3wes_div(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_div(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sqt
+*/
+ u3_noun
+ u3qes_sqt(u3_atom a,
+ u3_atom r)
+ {
+ union half c, d;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.h = _nan_unify(f16_sqrt(c.h));
+
+ return d.c;
+ }
+
+ u3_noun
+ u3wes_sqt(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( c3n == (a = u3r_at(u3x_sam, cor)) ||
+ c3n == u3ud(a) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_sqt(a, u3x_at(30, cor));
+ }
+ }
+
+/* fma
+*/
+ u3_noun
+ u3qes_fma(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom r)
+ {
+ union half d, e, f, g;
+ _set_rounding(r);
+ d.c = u3r_word(0, a);
+ e.c = u3r_word(0, b);
+ f.c = u3r_word(0, c);
+ g.h = _nan_unify(f16_mulAdd(d.h, e.h, f.h));
+
+ return g.c;
+ }
+
+ u3_noun
+ u3wes_fma(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ||
+ c3n == u3ud(c) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_fma(a, b, c, u3x_at(30, cor));
+ }
+ }
+
+/* lth
+*/
+ u3_noun
+ u3qes_lth(u3_atom a,
+ u3_atom b)
+ {
+ union half c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f16_lt(c.h, d.h));
+ }
+
+ u3_noun
+ u3wes_lth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_lth(a, b);
+ }
+ }
+
+/* lte
+*/
+ u3_noun
+ u3qes_lte(u3_atom a,
+ u3_atom b)
+ {
+ union half c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f16_le(c.h, d.h));
+ }
+
+ u3_noun
+ u3wes_lte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_lte(a, b);
+ }
+ }
+
+/* equ
+*/
+ u3_noun
+ u3qes_equ(u3_atom a,
+ u3_atom b)
+ {
+ union half c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f16_eq(c.h, d.h));
+ }
+
+ u3_noun
+ u3wes_equ(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_equ(a, b);
+ }
+ }
+
+/* gte
+*/
+ u3_noun
+ u3qes_gte(u3_atom a,
+ u3_atom b)
+ {
+ union half c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f16_le(d.h, c.h));
+ }
+
+ u3_noun
+ u3wes_gte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_gte(a, b);
+ }
+ }
+
+/* gth
+*/
+ u3_noun
+ u3qes_gth(u3_atom a,
+ u3_atom b)
+ {
+ union half c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f16_lt(d.h, c.h));
+ }
+
+ u3_noun
+ u3wes_gth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qes_gth(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/ripe.c b/vere/pkg/noun/jets/e/ripe.c
new file mode 100644
index 0000000..5d08a9d
--- /dev/null
+++ b/vere/pkg/noun/jets/e/ripe.c
@@ -0,0 +1,45 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_atom
+ _cqe_ripe(u3_atom wid, u3_atom dat)
+ {
+ c3_w len_w;
+ if ( !u3r_word_fit(&len_w, wid) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_atom ret;
+ c3_y out_y[20];
+ c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat);
+
+ ret = ( 0 == urcrypt_ripemd160(dat_y, len_w, out_y) )
+ ? u3i_bytes(20, out_y)
+ : u3_none;
+
+ u3a_free(dat_y);
+ return ret;
+ }
+ }
+
+ u3_noun
+ u3we_ripe(u3_noun cor)
+ {
+ u3_noun wid, dat;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid,
+ u3x_sam_3, &dat, 0) ||
+ u3ud(wid) || u3ud(dat))
+ )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("ripe", _cqe_ripe(wid, dat));
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/rq.c b/vere/pkg/noun/jets/e/rq.c
new file mode 100644
index 0000000..e26a4de
--- /dev/null
+++ b/vere/pkg/noun/jets/e/rq.c
@@ -0,0 +1,446 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "softfloat.h"
+
+#define QUADNAN 0x7fff800000000000
+
+ union quad {
+ float128_t* q;
+ c3_w* c;
+ };
+
+ static inline c3_t
+ _nan_test(float128_t* a)
+ {
+ return !f128M_eq(a, a);
+ }
+
+ static inline void
+ _nan_unify(float128_t* a)
+ {
+ if ( _nan_test(a) )
+ {
+ *( (c3_d*)a) = 0;
+ *(((c3_d*)a)+1) = QUADNAN;
+ }
+ }
+
+ static inline void
+ _set_rounding(c3_w a)
+ {
+ switch ( a )
+ {
+ default:
+ u3m_bail(c3__fail);
+ break;
+ case c3__n:
+ softfloat_roundingMode = softfloat_round_near_even;
+ break;
+ case c3__z:
+ softfloat_roundingMode = softfloat_round_minMag;
+ break;
+ case c3__u:
+ softfloat_roundingMode = softfloat_round_max;
+ break;
+ case c3__d:
+ softfloat_roundingMode = softfloat_round_min;
+ break;
+ }
+ }
+
+/* add
+*/
+ u3_noun
+ u3qeq_add(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union quad c, d, e;
+ _set_rounding(r);
+ c.c = alloca(16);
+ d.c = alloca(16);
+ e.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ f128M_add(c.q, d.q, e.q);
+ _nan_unify(e.q);
+
+ u3_atom f = u3i_words(4, e.c);
+ return f;
+ }
+
+ u3_noun
+ u3weq_add(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_add(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sub
+*/
+ u3_noun
+ u3qeq_sub(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union quad c, d, e;
+ _set_rounding(r);
+ c.c = alloca(16);
+ d.c = alloca(16);
+ e.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ f128M_sub(c.q, d.q, e.q);
+ _nan_unify(e.q);
+
+ u3_atom f = u3i_words(4, e.c);
+ return f;
+ }
+
+ u3_noun
+ u3weq_sub(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_sub(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* mul
+*/
+ u3_noun
+ u3qeq_mul(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union quad c, d, e;
+ _set_rounding(r);
+ c.c = alloca(16);
+ d.c = alloca(16);
+ e.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ f128M_mul(c.q, d.q, e.q);
+ _nan_unify(e.q);
+
+ u3_atom f = u3i_words(4, e.c);
+ return f;
+ }
+
+ u3_noun
+ u3weq_mul(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_mul(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* div
+*/
+ u3_noun
+ u3qeq_div(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union quad c, d, e;
+ _set_rounding(r);
+ c.c = alloca(16);
+ d.c = alloca(16);
+ e.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ f128M_div(c.q, d.q, e.q);
+ _nan_unify(e.q);
+
+ u3_atom f = u3i_words(4, e.c);
+ return f;
+ }
+
+ u3_noun
+ u3weq_div(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_div(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sqt
+*/
+ u3_noun
+ u3qeq_sqt(u3_atom a,
+ u3_atom r)
+ {
+ union quad c, d;
+ _set_rounding(r);
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ f128M_sqrt(c.q, d.q);
+ _nan_unify(d.q);
+
+ u3_atom e = u3i_words(4, d.c);
+ return e;
+ }
+
+ u3_noun
+ u3weq_sqt(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( c3n == (a = u3r_at(u3x_sam, cor)) ||
+ c3n == u3ud(a) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_sqt(a, u3x_at(30, cor));
+ }
+ }
+
+/* fma
+*/
+ u3_noun
+ u3qeq_fma(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom r)
+ {
+ union quad d, e, f, g;
+ _set_rounding(r);
+ d.c = alloca(16);
+ e.c = alloca(16);
+ f.c = alloca(16);
+ g.c = alloca(16);
+
+ u3r_words(0, 4, d.c, a);
+ u3r_words(0, 4, e.c, b);
+ u3r_words(0, 4, f.c, c);
+ f128M_mulAdd(d.q, e.q, f.q, g.q);
+ _nan_unify(g.q);
+
+ u3_atom h = u3i_words(4, g.c);
+ return h;
+ }
+
+ u3_noun
+ u3weq_fma(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ||
+ c3n == u3ud(c) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_fma(a, b, c, u3x_at(30, cor));
+ }
+ }
+
+/* lth
+*/
+ u3_noun
+ u3qeq_lth(u3_atom a,
+ u3_atom b)
+ {
+ union quad c, d;
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ c3_o e = __(f128M_lt(c.q, d.q));
+
+ return e;
+ }
+
+ u3_noun
+ u3weq_lth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_lth(a, b);
+ }
+ }
+
+/* lte
+*/
+ u3_noun
+ u3qeq_lte(u3_atom a,
+ u3_atom b)
+ {
+ union quad c, d;
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ c3_o e = __(f128M_le(c.q, d.q));
+
+ return e;
+ }
+
+ u3_noun
+ u3weq_lte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_lte(a, b);
+ }
+ }
+
+/* equ
+*/
+ u3_noun
+ u3qeq_equ(u3_atom a,
+ u3_atom b)
+ {
+ union quad c, d;
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ c3_o e = __(f128M_eq(c.q, d.q));
+
+ return e;
+ }
+
+ u3_noun
+ u3weq_equ(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_equ(a, b);
+ }
+ }
+
+/* gte
+*/
+ u3_noun
+ u3qeq_gte(u3_atom a,
+ u3_atom b)
+ {
+ union quad c, d;
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ c3_o e = __(f128M_le(d.q, c.q));
+
+ return e;
+ }
+
+ u3_noun
+ u3weq_gte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_gte(a, b);
+ }
+ }
+
+/* gth
+*/
+ u3_noun
+ u3qeq_gth(u3_atom a,
+ u3_atom b)
+ {
+ union quad c, d;
+ c.c = alloca(16);
+ d.c = alloca(16);
+
+ u3r_words(0, 4, c.c, a);
+ u3r_words(0, 4, d.c, b);
+ c3_o e = __(f128M_lt(d.q, c.q));
+
+ return e;
+ }
+
+ u3_noun
+ u3weq_gth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qeq_gth(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/rs.c b/vere/pkg/noun/jets/e/rs.c
new file mode 100644
index 0000000..360d1c9
--- /dev/null
+++ b/vere/pkg/noun/jets/e/rs.c
@@ -0,0 +1,390 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "softfloat.h"
+
+#define SINGNAN 0x7fc00000
+
+ union sing {
+ float32_t s;
+ c3_w c;
+ };
+
+ static inline c3_t
+ _nan_test(float32_t a)
+ {
+ return !f32_eq(a, a);
+ }
+
+ static inline float32_t
+ _nan_unify(float32_t a)
+ {
+ if ( _nan_test(a) )
+ {
+ *(c3_w*)(&a) = SINGNAN;
+ }
+ return a;
+ }
+
+ static inline void
+ _set_rounding(c3_w a)
+ {
+ switch ( a )
+ {
+ default:
+ u3m_bail(c3__fail);
+ break;
+ case c3__n:
+ softfloat_roundingMode = softfloat_round_near_even;
+ break;
+ case c3__z:
+ softfloat_roundingMode = softfloat_round_minMag;
+ break;
+ case c3__u:
+ softfloat_roundingMode = softfloat_round_max;
+ break;
+ case c3__d:
+ softfloat_roundingMode = softfloat_round_min;
+ break;
+ }
+ }
+
+/* add
+*/
+ u3_noun
+ u3qet_add(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union sing c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.s = _nan_unify(f32_add(c.s, d.s));
+
+ return u3i_words(1, &e.c);
+ }
+
+ u3_noun
+ u3wet_add(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_add(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sub
+*/
+ u3_noun
+ u3qet_sub(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union sing c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.s = _nan_unify(f32_sub(c.s, d.s));
+
+ return u3i_words(1, &e.c);
+ }
+
+ u3_noun
+ u3wet_sub(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_sub(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* mul
+*/
+ u3_noun
+ u3qet_mul(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union sing c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.s = _nan_unify(f32_mul(c.s, d.s));
+
+ return u3i_words(1, &e.c);
+ }
+
+ u3_noun
+ u3wet_mul(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_mul(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* div
+*/
+ u3_noun
+ u3qet_div(u3_atom a,
+ u3_atom b,
+ u3_atom r)
+ {
+ union sing c, d, e;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+ e.s = _nan_unify(f32_div(c.s, d.s));
+
+ return u3i_words(1, &e.c);
+ }
+
+ u3_noun
+ u3wet_div(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_div(a, b, u3x_at(30, cor));
+ }
+ }
+
+/* sqt
+*/
+ u3_noun
+ u3qet_sqt(u3_atom a,
+ u3_atom r)
+ {
+ union sing c, d;
+ _set_rounding(r);
+ c.c = u3r_word(0, a);
+ d.s = _nan_unify(f32_sqrt(c.s));
+
+ return u3i_words(1, &d.c);
+ }
+
+ u3_noun
+ u3wet_sqt(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( c3n == (a = u3r_at(u3x_sam, cor)) ||
+ c3n == u3ud(a) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_sqt(a, u3x_at(30, cor));
+ }
+ }
+
+/* fma
+*/
+ u3_noun
+ u3qet_fma(u3_atom a,
+ u3_atom b,
+ u3_atom c,
+ u3_atom r)
+ {
+ union sing d, e, f, g;
+ _set_rounding(r);
+ d.c = u3r_word(0, a);
+ e.c = u3r_word(0, b);
+ f.c = u3r_word(0, c);
+ g.s = _nan_unify(f32_mulAdd(d.s, e.s, f.s));
+
+ return u3i_words(1, &g.c);
+ }
+
+ u3_noun
+ u3wet_fma(u3_noun cor)
+ {
+ u3_noun a, b, c;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) ||
+ c3n == u3ud(c) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_fma(a, b, c, u3x_at(30, cor));
+ }
+ }
+
+/* lth
+*/
+ u3_noun
+ u3qet_lth(u3_atom a,
+ u3_atom b)
+ {
+ union sing c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f32_lt(c.s, d.s));
+ }
+
+ u3_noun
+ u3wet_lth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_lth(a, b);
+ }
+ }
+
+/* lte
+*/
+ u3_noun
+ u3qet_lte(u3_atom a,
+ u3_atom b)
+ {
+ union sing c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f32_le(c.s, d.s));
+ }
+
+ u3_noun
+ u3wet_lte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_lte(a, b);
+ }
+ }
+
+/* equ
+*/
+ u3_noun
+ u3qet_equ(u3_atom a,
+ u3_atom b)
+ {
+ union sing c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f32_eq(c.s, d.s));
+ }
+
+ u3_noun
+ u3wet_equ(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_equ(a, b);
+ }
+ }
+
+/* gte
+*/
+ u3_noun
+ u3qet_gte(u3_atom a,
+ u3_atom b)
+ {
+ union sing c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f32_le(d.s, c.s));
+ }
+
+ u3_noun
+ u3wet_gte(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_gte(a, b);
+ }
+ }
+
+/* gth
+*/
+ u3_noun
+ u3qet_gth(u3_atom a,
+ u3_atom b)
+ {
+ union sing c, d;
+ c.c = u3r_word(0, a);
+ d.c = u3r_word(0, b);
+
+ return __(f32_lt(d.s, c.s));
+ }
+
+ u3_noun
+ u3wet_gth(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ||
+ c3n == u3ud(a) ||
+ c3n == u3ud(b) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3qet_gth(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/rub.c b/vere/pkg/noun/jets/e/rub.c
new file mode 100644
index 0000000..81739be
--- /dev/null
+++ b/vere/pkg/noun/jets/e/rub.c
@@ -0,0 +1,85 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qe_rub(u3_atom a,
+ u3_atom b)
+ {
+ u3_atom c, d, e;
+ u3_atom w, x, y, z;
+ u3_atom p, q;
+
+ u3_atom m;
+ {
+ c3_w bit_w = u3r_met(0, b);
+ u3_noun bit = u3i_words(1, &bit_w);
+ m = u3qa_add(a, bit);
+ u3z(bit);
+ }
+
+ // Compute c and d.
+ {
+ x = u3k(a);
+
+ while ( 0 == u3qc_cut(0, x, 1, b) ) {
+ u3_atom y = u3qa_inc(x);
+
+ // Sanity check: crash if decoding more bits than available
+ if ( c3y == u3qa_gth(x, m)) {
+ // u3l_log("[%%rub-hard %d %d %d]", a, x, m);
+ return u3m_bail(c3__exit);
+ }
+
+ u3z(x);
+ x = y;
+ }
+ if ( c3y == u3r_sing(x, a) ) {
+ u3z(x);
+ return u3nc(1, 0);
+ }
+ c = u3qa_sub(x, a);
+ d = u3qa_inc(x);
+
+ u3z(x);
+ }
+
+ // Compute e, p, q.
+ {
+ x = u3qa_dec(c);
+ y = u3qc_bex(x);
+ z = u3qc_cut(0, d, x, b);
+
+ e = u3qa_add(y, z);
+ u3z(y); u3z(z);
+
+ w = u3qa_add(c, c);
+ y = u3qa_add(w, e);
+ z = u3qa_add(d, x);
+
+ p = u3qa_add(w, e);
+ q = u3qc_cut(0, z, e, b);
+
+ u3z(w); u3z(x); u3z(y); u3z(z);
+
+ return u3nc(p, q);
+ }
+ }
+ u3_noun
+ u3we_rub(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_rub(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/scot.c b/vere/pkg/noun/jets/e/scot.c
new file mode 100644
index 0000000..f39c46b
--- /dev/null
+++ b/vere/pkg/noun/jets/e/scot.c
@@ -0,0 +1,30 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+#include <ctype.h>
+
+u3_atom
+u3qe_scot(u3_atom a, u3_atom b)
+{
+ switch (a) {
+ case c3__tas: return u3k(b);
+ case c3__ud: return u3s_etch_ud(b);
+ case c3__ux: return u3s_etch_ux(b);
+ case c3__uv: return u3s_etch_uv(b);
+ case c3__uw: return u3s_etch_uw(b);
+ default: return u3_none;
+ }
+}
+
+u3_noun
+u3we_scot(u3_noun cor)
+{
+ u3_atom a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qe_scot(u3x_atom(a), u3x_atom(b));
+}
diff --git a/vere/pkg/noun/jets/e/scow.c b/vere/pkg/noun/jets/e/scow.c
new file mode 100644
index 0000000..986dc41
--- /dev/null
+++ b/vere/pkg/noun/jets/e/scow.c
@@ -0,0 +1,251 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+#include <ctype.h>
+
+static
+c3_y to_digit(c3_y tig)
+{
+ if (tig >= 10) {
+ return 87 + tig;
+ } else {
+ return '0' + tig;
+ }
+}
+
+// gives the characters for a four 'digit' small hex atom.
+static
+void
+_x_co_four(c3_w src, c3_y* a, c3_y* b, c3_y* c, c3_y* d)
+{
+ *d = to_digit(src & 0xF);
+ src >>= 4;
+ *c = to_digit(src & 0xF);
+ src >>= 4;
+ *b = to_digit(src & 0xF);
+ src >>= 4;
+ *a = to_digit(src & 0xF);
+}
+
+// The parser always prints two digits on 0 in y-co.
+static
+void
+_y_co_two(c3_w src, c3_y* a, c3_y* b)
+{
+ *b = to_digit(src % 10);
+ *a = to_digit(src / 10);
+}
+
+//
+static
+u3_noun
+_add_year(c3_w year, u3_noun out)
+{
+ while (year > 0) {
+ out = u3nc(to_digit(year % 10), out);
+ year = year / 10;
+ }
+
+ return out;
+}
+
+static
+u3_noun
+_print_da(u3_noun cor, u3_atom raw_da)
+{
+ u3_noun hok = u3j_cook("u3we_scow_print_da", u3k(cor), "yore");
+ u3_noun yod = u3n_slam_on(hok, u3k(raw_da));
+
+ u3_noun out = 0;
+
+ u3_atom age, year, month, day, hour, min, sec, f;
+ if (c3n == u3r_mean(yod, 4, &age,
+ 5, &year,
+ 6, &month,
+ 14, &day,
+ 30, &hour,
+ 62, &min,
+ 126, &sec,
+ 127, &f,
+ 0)) {
+ return u3m_bail(c3__exit);
+ }
+
+ if (f != 0) {
+ u3_noun f_list = u3qb_flop(f);
+
+ for (u3_noun cur = f_list;
+ _(u3a_is_cell(cur));
+ cur = u3t(cur)) {
+ if (_(u3a_is_cat(u3h(cur)))) {
+ c3_y a, b, c, d;
+ _x_co_four(u3h(cur), &a, &b, &c, &d);
+ out = u3nq('.', a, b, u3nt(c, d, out));
+ } else {
+ // No way to deal with big atoms. fall back.
+ u3z(yod);
+ u3z(out);
+ u3z(f_list);
+ return u3_none;
+ }
+ }
+
+ u3z(f_list);
+ out = u3nc('.', out);
+ }
+
+ // if there isn't a hex list and the h/m/s are all 0, skip printing hours.
+ if (f != 0 || hour != 0 || min != 0 || sec != 0) {
+ if (!_(u3a_is_cat(hour)) ||
+ !_(u3a_is_cat(min)) ||
+ !_(u3a_is_cat(sec))) {
+ // Input is weird, fallback to nock.
+ u3z(yod);
+ u3z(out);
+ return u3_none;
+ }
+
+ c3_y sa, sb, ma, mb, ha, hb;
+ _y_co_two(sec, &sa, &sb);
+ out = u3nq('.', sa, sb, out);
+
+ _y_co_two(min, &ma, &mb);
+ out = u3nq('.', ma, mb, out);
+
+ _y_co_two(hour, &ha, &hb);
+ out = u3nq('.', ha, hb, out);
+
+ out = u3nc('.', out);
+ }
+
+ // We always print the Y.M.D. Unlike others, these numbers are unconstrained
+ // by length, but in practice, the month number and day number can only be up
+ // to two digits because of +yore. We still need to remove 0 prefixes,
+ // though.
+ if (!_(u3a_is_cat(day)) || day > 99 ||
+ !_(u3a_is_cat(month)) || month > 99 ||
+ !_(u3a_is_cat(year))) {
+ // Input is weird, fallback to nock.
+ u3z(yod);
+ u3z(out);
+ return u3_none;
+ }
+
+ c3_y da, db;
+ _y_co_two(day, &da, &db);
+ out = u3nc(db, out);
+ if (da != '0') {
+ out = u3nc(da, out);
+ }
+ out = u3nc('.', out);
+
+ c3_y ma, mb;
+ _y_co_two(month, &ma, &mb);
+ out = u3nc(mb, out);
+ if (ma != '0') {
+ out = u3nc(ma, out);
+ }
+ out = u3nc('.', out);
+
+ // suffix the year with a '-' for BC dates
+ if (age == c3n) {
+ out = u3nc('-', out);
+ }
+
+ // The year part is the only place where we have to explicitly loop over the
+ // input because it can be arbitrarily large or small.
+ out = _add_year(year, out);
+
+ out = u3nc('~', out);
+
+ u3z(yod);
+ return out;
+}
+
+static
+u3_noun
+_print_p(u3_atom cor, u3_atom p)
+{
+ // Scramble the raw number to the concealed version.
+ u3_noun ob = u3j_cook("u3we_scow_ob_p", u3k(cor), "ob");
+ u3_noun hok = u3j_cook("u3we_scow_fein_p", ob, "fein");
+ u3_atom sxz = u3n_slam_on(hok, u3k(p));
+
+ // Simple galaxy case
+ if (c3y == u3qa_lth(sxz, 256)) {
+ c3_y a, b, c;
+ u3_po_to_suffix(sxz, &a, &b, &c);
+ u3z(sxz);
+ return u3nq('~', a, b, u3nc(c, 0));
+ }
+
+ u3_atom dyy = u3qc_met(4, sxz);
+ if (!_(u3a_is_cat(dyy))) {
+ u3z(sxz);
+ u3z(dyy);
+ return u3_none;
+ }
+
+ u3_noun list = 0;
+ for (c3_w imp = 0; imp != dyy; ++imp) {
+ c3_w log = u3qc_end(4, 1, sxz);
+ c3_w prefix = u3qc_rsh(3, 1, log);
+ c3_w suffix = u3qc_end(3, 1, log);
+
+ c3_y a, b, c, d, e, f;
+ u3_po_to_prefix(prefix, &a, &b, &c);
+ u3_po_to_suffix(suffix, &d, &e, &f);
+
+ if (imp % 4 == 0) {
+ if (imp != 0) {
+ list = u3nt('-', '-', list);
+ }
+ } else {
+ list = u3nc('-', list);
+ }
+
+ list = u3nq(a, b, c, u3nq(d, e, f, list));
+
+ sxz = u3qc_rsh(4, 1, sxz);
+ }
+
+ u3z(sxz);
+ return u3nc('~', list);
+}
+
+u3_atom
+u3qe_scow(u3_atom a, u3_atom b)
+{
+ switch (a) {
+ // XX disabled due to memory corruption
+ // rewrite for +scot jet and test there
+ //
+ // case c3__da: return _print_da(cor, atom);
+ // case 'p': return _print_p(cor, atom);
+
+ default: {
+ u3_weak dat = u3qe_scot(a, b);
+ u3_weak pro = u3_none;
+
+ if ( u3_none != dat ) {
+ pro = u3qc_rip(3, 1, dat);
+ u3z(dat);
+ }
+
+ return pro;
+ }
+ }
+}
+
+u3_noun
+u3we_scow(u3_noun cor)
+{
+ u3_atom a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qe_scow(u3x_atom(a), u3x_atom(b));
+}
diff --git a/vere/pkg/noun/jets/e/scr.c b/vere/pkg/noun/jets/e/scr.c
new file mode 100644
index 0000000..e9d0725
--- /dev/null
+++ b/vere/pkg/noun/jets/e/scr.c
@@ -0,0 +1,227 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_weak
+ _cqes_hs(u3_atom p, c3_w pwd_w,
+ u3_atom s, c3_w sal_w,
+ u3_atom n,
+ u3_atom r,
+ u3_atom z,
+ u3_atom d)
+ {
+ u3_noun chk;
+ c3_w out_w;
+
+ if ( !u3r_word_fit(&out_w, d) ) {
+ return u3m_bail(c3__fail);
+ }
+ if ( 0 == r || 0 == z ) {
+ return u3m_bail(c3__exit);
+ }
+ chk = u3qc_bex(31);
+ if ( (c3n == u3qa_lth(pwd_w, chk)) ||
+ (c3n == u3qa_lth(sal_w, chk)) ) {
+ return u3m_bail(c3__exit);
+ }
+ u3z(chk);
+ chk = u3kc_bex(u3ka_dec(u3qc_xeb(n)));
+ if ( c3n == u3r_sing(n, chk) ) {
+ return u3m_bail(c3__exit);
+ }
+ u3z(chk);
+ if ( c3n == u3ka_lte(
+ u3ka_mul(u3qa_mul(128, r), u3ka_dec(u3qa_add(n, z))),
+ u3qc_bex(30)) ) {
+ return u3m_bail(c3__exit);
+ }
+
+ if ( (u3r_met(6, n) > 1) ||
+ (u3r_met(5, r) > 1) ||
+ (u3r_met(5, z) > 1) ) {
+ return u3_none;
+ }
+ else {
+ u3_noun pro;
+ c3_d n_d = u3r_chub(0, n);
+ c3_w r_w = u3r_word(0, r),
+ z_w = u3r_word(0, z);
+ c3_y *pwd_y = u3a_malloc(pwd_w),
+ *sal_y = u3a_malloc(sal_w),
+ *out_y = u3a_malloc(d);
+ u3r_bytes(0, pwd_w, pwd_y, p);
+ u3r_bytes(0, sal_w, sal_y, s);
+ pro = ( 0 == urcrypt_scrypt(pwd_y, pwd_w,
+ sal_y, sal_w,
+ n_d, r_w, z_w,
+ out_w, out_y) )
+ ? u3i_bytes(out_w, out_y)
+ : u3_none;
+ u3a_free(pwd_y);
+ u3a_free(sal_y);
+ u3a_free(out_y);
+ return pro;
+ }
+ }
+
+ static u3_weak
+ _cqes_hsl(u3_atom p, u3_atom pl,
+ u3_atom s, u3_atom sl,
+ u3_atom n,
+ u3_atom r,
+ u3_atom z,
+ u3_atom d)
+ {
+ c3_w pwd_w, sal_w;
+ if ( !(u3r_word_fit(&pwd_w, pl) &&
+ u3r_word_fit(&sal_w, sl)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return _cqes_hs(p, pwd_w, s, sal_w, n, r, z, d);
+ }
+ }
+
+ u3_noun
+ u3wes_hsl(u3_noun cor)
+ {
+ u3_noun p, pl, s, sl, n, r, z, d;
+ u3_noun q;
+
+ u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q);
+ u3x_qual(q, &n, &r, &z, &d);
+
+ if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(pl)) &&
+ _(u3a_is_atom(s)) && _(u3a_is_atom(sl)) &&
+ _(u3a_is_atom(n)) && _(u3a_is_atom(r)) &&
+ _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("scr-hsl", _cqes_hsl(p, pl, s, sl, n, r, z, d));
+ }
+ }
+
+ static u3_weak
+ _cqes_hsh(u3_atom p,
+ u3_atom s,
+ u3_atom n,
+ u3_atom r,
+ u3_atom z,
+ u3_atom d)
+ {
+ return _cqes_hs(p, u3r_met(3, p),
+ s, u3r_met(3, s),
+ n, r, z, d);
+ }
+
+ u3_noun
+ u3wes_hsh(u3_noun cor)
+ {
+ u3_noun p, s, n, r, z, d;
+ u3_noun q;
+
+ u3x_quil(u3x_at(u3x_sam, cor), &p, &s, &n, &r, &q);
+ u3x_cell(q, &z, &d);
+
+ if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) &&
+ _(u3a_is_atom(n)) && _(u3a_is_atom(r)) &&
+ _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("scr-hsh", _cqes_hsh(p, s, n, r, z, d));
+ }
+ }
+
+ static u3_atom
+ _cqes_pb(u3_atom p, c3_w pwd_w,
+ u3_atom s, c3_w sal_w,
+ u3_atom c,
+ u3_atom d)
+ {
+ if ( (c > (1 << 28)) ||
+ (d > (1 << 30)) ) {
+ // max key length 1gb
+ // max iterations 2^28
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun pro;
+ c3_y *pwd_y = u3a_malloc(pwd_w),
+ *sal_y = u3a_malloc(sal_w),
+ *out_y = u3a_malloc(d);
+ u3r_bytes(0, pwd_w, pwd_y, p);
+ u3r_bytes(0, sal_w, sal_y, s);
+ urcrypt_scrypt_pbkdf_sha256(pwd_y, pwd_w, sal_y, sal_w, c, d, out_y);
+ pro = u3i_bytes(d, out_y);
+ u3a_free(pwd_y);
+ u3a_free(sal_y);
+ u3a_free(out_y);
+ return pro;
+ }
+ }
+
+ static u3_noun
+ _cqes_pbl(u3_atom p, u3_atom pl,
+ u3_atom s, u3_atom sl,
+ u3_atom c,
+ u3_atom d)
+ {
+ c3_w pwd_w, sal_w;
+ if ( !(u3r_word_fit(&pwd_w, pl) &&
+ u3r_word_fit(&sal_w, sl)) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ return _cqes_pb(p, pwd_w, s, sal_w, c, d);
+ }
+ }
+
+ u3_noun
+ u3wes_pbl(u3_noun cor)
+ {
+ u3_noun p, pl, s, sl, c, d;
+ u3_noun q;
+
+ u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q);
+ u3x_cell(q, &c, &d);
+
+ if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) &&
+ _(u3a_is_atom(pl)) && _(u3a_is_atom(sl)) &&
+ _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqes_pbl(p, pl, s, sl, c, d);
+ }
+ }
+
+ static u3_atom
+ _cqes_pbk(u3_atom p, u3_atom s, u3_atom c, u3_atom d)
+ {
+ return _cqes_pb(p, u3r_met(3, p),
+ s, u3r_met(3, s),
+ c, d);
+ }
+
+ u3_noun
+ u3wes_pbk(u3_noun cor)
+ {
+ u3_noun p, s, c, d;
+
+ u3x_qual(u3x_at(u3x_sam, cor), &p, &s, &c, &d);
+
+ if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) &&
+ _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqes_pbk(p, s, c, d);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/secp.c b/vere/pkg/noun/jets/e/secp.c
new file mode 100644
index 0000000..fa0fbd2
--- /dev/null
+++ b/vere/pkg/noun/jets/e/secp.c
@@ -0,0 +1,298 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+#include "ent/ent.h"
+
+static urcrypt_secp_context* sec_u;
+
+/* call at process start */
+void
+u3je_secp_init()
+{
+ c3_y ent_y[32];
+ ent_getentropy(ent_y, 32);
+ sec_u = malloc(urcrypt_secp_prealloc_size());
+
+ if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) {
+ u3l_log("u3e_secp_init failed");
+ abort();
+ }
+}
+
+/* call at process end */
+void
+u3je_secp_stop()
+{
+ urcrypt_secp_destroy(sec_u);
+ free(sec_u);
+ sec_u = NULL;
+}
+
+/* util funcs
+ */
+static c3_t
+_cqes_in_order(u3_atom a)
+{
+ // this is the "n" parameter of the secp256k1 curve
+ static const c3_w now_w[8] = {
+ 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6,
+ 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff
+ };
+
+ if ( 0 == a ) {
+ return 0;
+ }
+ else if ( c3y == u3a_is_cat(a) ) {
+ return 1;
+ }
+ else {
+ u3a_atom* a_u = u3a_to_ptr(a);
+ c3_w len_w = a_u->len_w;
+
+ if ( len_w < 8 ) {
+ return 1;
+ }
+ else if ( len_w > 8 ) {
+ return 0;
+ }
+ else {
+ c3_y i_y;
+ c3_w *buf_w = a_u->buf_w;
+ // loop from most to least significant words
+ for ( i_y = 8; i_y > 0; ) {
+ c3_w b_w = buf_w[i_y],
+ o_w = now_w[--i_y];
+ if ( b_w < o_w ) {
+ return 1;
+ }
+ else if ( b_w > o_w ) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ }
+}
+
+static void
+_cqes_unpack_fe(u3_atom k, c3_y out_y[32])
+{
+ if ( _cqes_in_order(k) ) {
+ u3r_bytes(0, 32, out_y, k);
+ }
+ else {
+ u3m_bail(c3__exit);
+ }
+}
+
+/* sign hash with priv key
+ */
+static u3_noun
+_cqes_sign(u3_atom has,
+ u3_atom prv)
+{
+ c3_y has_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, has_y, has) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y prv_y[32], v_y, r_y[32], s_y[32];
+ _cqes_unpack_fe(prv, prv_y);
+
+ return( 0 == urcrypt_secp_sign(sec_u, has_y, prv_y, &v_y, r_y, s_y) )
+ ? u3nt(v_y, u3i_bytes(32, r_y), u3i_bytes(32, s_y))
+ : u3_none;
+ }
+}
+
+u3_noun
+u3we_sign(u3_noun cor)
+{
+
+ u3_noun has, prv;
+
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &has,
+ u3x_sam_3, &prv,
+ 0)) ||
+ (c3n == u3ud(has)) ||
+ (c3n == u3ud(prv))) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("secp-sign", _cqes_sign(has, prv));
+ }
+}
+
+/* recover pubkey from signature (which is how we verify signatures)
+*/
+static u3_noun
+_cqes_reco(u3_atom has,
+ u3_atom siv, /* signature: v */
+ u3_atom sir, /* signature: r */
+ u3_atom sis) /* signature: s */
+{
+ c3_y has_y[32];
+ if ( !((siv < 4) && (0 == u3r_bytes_fit(32, has_y, has)) ) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y sir_y[32], sis_y[32], x_y[32], y_y[32];
+ _cqes_unpack_fe(sir, sir_y);
+ _cqes_unpack_fe(sis, sis_y);
+ return
+ ( 0 == urcrypt_secp_reco(sec_u, has_y, siv, sir_y, sis_y, x_y, y_y) )
+ ? u3nc(u3i_bytes(32, x_y), u3i_bytes(32, y_y))
+ : u3_none;
+ }
+}
+
+u3_noun
+u3we_reco(u3_noun cor)
+{
+ u3_noun has, /* hash */
+ siv, sir, sis; /* signature: v, r, s */
+
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &has,
+ u3x_sam_6, &siv,
+ u3x_sam_14, &sir,
+ u3x_sam_15, &sis,
+ 0)) ||
+ (c3n == u3ud(has)) ||
+ (c3n == u3ud(siv)) ||
+ (c3n == u3ud(sir)) ||
+ (c3n == u3ud(sis)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("secp-reco", _cqes_reco(has, siv, sir, sis));
+ }
+}
+
+static u3_atom
+_cqes_make(u3_atom has,
+ u3_atom prv)
+{
+ c3_y has_y[32];
+
+ if ( 0 != u3r_bytes_fit(32, has_y, has) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y prv_y[32], out_y[32];
+ _cqes_unpack_fe(prv, prv_y);
+ return ( 0 == urcrypt_secp_make(has_y, prv_y, out_y) )
+ ? u3i_bytes(32, out_y)
+ : u3_none;
+ }
+}
+
+u3_noun
+u3we_make(u3_noun cor)
+{
+ u3_noun has, prv;
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &has,
+ u3x_sam_3, &prv,
+ 0)) ||
+ (c3n == u3ud(has)) ||
+ (c3n == u3ud(prv)) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("secp-make", _cqes_make(has, prv));
+ }
+}
+
+/* create a schnorr signature
+*/
+static u3_weak
+_cqes_sosi(u3_atom sk, u3_atom m, u3_atom a)
+{
+ c3_y key_y[32];
+ c3_y mes_y[32];
+ c3_y aux_y[32];
+
+ if ( (0 != u3r_bytes_fit(32, key_y, sk)) ||
+ (0 != u3r_bytes_fit(32, mes_y, m)) ||
+ (0 != u3r_bytes_fit(32, aux_y, a)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ c3_y sig_y[64];
+
+ return
+ ( 0 == urcrypt_secp_schnorr_sign(sec_u, key_y, mes_y, aux_y, sig_y) )
+ ? u3i_bytes(64, sig_y)
+ : u3_none;
+ }
+}
+
+u3_noun
+u3we_sosi(u3_noun cor)
+{
+ u3_noun key, mes, aux;
+
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &key,
+ u3x_sam_6, &mes,
+ u3x_sam_7, &aux,
+ 0)) ||
+ (c3n == u3ud(key)) ||
+ (c3n == u3ud(mes)) ||
+ (c3n == u3ud(aux)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return u3l_punt("secp-sosi", _cqes_sosi(key, mes, aux));
+ }
+}
+
+/* verify a schnorr signature
+*/
+static u3_atom
+_cqes_sove(u3_atom pk, u3_atom m, u3_atom sig)
+{
+ c3_y pub_y[32];
+ c3_y mes_y[32];
+ c3_y sig_y[64];
+
+ if ( (0 != u3r_bytes_fit(32, pub_y, pk)) ||
+ (0 != u3r_bytes_fit(32, mes_y, m)) ||
+ (0 != u3r_bytes_fit(64, sig_y, sig)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return __(urcrypt_secp_schnorr_veri(sec_u, sig_y, mes_y, pub_y));
+ }
+}
+
+u3_noun
+u3we_sove(u3_noun cor)
+{
+ u3_noun pub, mes, sig;
+
+ if ( (c3n == u3r_mean(cor,
+ u3x_sam_2, &pub,
+ u3x_sam_6, &mes,
+ u3x_sam_7, &sig,
+ 0)) ||
+ (c3n == u3ud(pub)) ||
+ (c3n == u3ud(mes)) ||
+ (c3n == u3ud(sig)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqes_sove(pub, mes, sig);
+ }
+}
diff --git a/vere/pkg/noun/jets/e/sha1.c b/vere/pkg/noun/jets/e/sha1.c
new file mode 100644
index 0000000..729faf6
--- /dev/null
+++ b/vere/pkg/noun/jets/e/sha1.c
@@ -0,0 +1,40 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+ static u3_noun
+ _cqe_sha1(u3_atom wid, u3_atom dat)
+ {
+ c3_w len_w;
+ if ( !u3r_word_fit(&len_w, wid) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y out_y[20];
+ c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat);
+
+ urcrypt_sha1(dat_y, len_w, out_y);
+ u3a_free(dat_y);
+ return u3i_bytes(20, out_y);
+ }
+ }
+
+ u3_noun
+ u3we_sha1(u3_noun cor)
+ {
+ u3_noun wid, dat;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid, u3x_sam_3, &dat, 0)) ||
+ (c3n == u3ud(wid)) ||
+ (c3n == u3ud(dat)) )
+ {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ return _cqe_sha1(wid, dat);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/shax.c b/vere/pkg/noun/jets/e/shax.c
new file mode 100644
index 0000000..856d0fa
--- /dev/null
+++ b/vere/pkg/noun/jets/e/shax.c
@@ -0,0 +1,194 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+#include "urcrypt.h"
+
+
+ static u3_atom
+ _cqe_shay(u3_atom wid,
+ u3_atom dat)
+ {
+ c3_w len_w;
+ if ( !u3r_word_fit(&len_w, wid) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y out_y[32];
+ c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat);
+ urcrypt_shay(dat_y, len_w, out_y);
+ u3a_free(dat_y);
+ return u3i_bytes(32, out_y);
+ }
+ }
+
+ static u3_atom
+ _cqe_shax(u3_atom a)
+ {
+ c3_w len_w;
+ c3_y out_y[32];
+ c3_y* dat_y = u3r_bytes_all(&len_w, a);
+ urcrypt_shay(dat_y, len_w, out_y);
+ u3a_free(dat_y);
+ return u3i_bytes(32, out_y);
+ }
+
+ static u3_atom
+ _cqe_shal(u3_atom wid,
+ u3_atom dat)
+ {
+ c3_w len_w;
+ if ( !u3r_word_fit(&len_w, wid) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_y out_y[64];
+ c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat);
+ urcrypt_shal(dat_y, len_w, out_y);
+ u3a_free(dat_y);
+ return u3i_bytes(64, out_y);
+ }
+ }
+
+ static u3_atom
+ _cqe_shas(u3_atom sal,
+ u3_atom ruz)
+ {
+ c3_w sal_w, ruz_w;
+ c3_y *sal_y, *ruz_y, out_y[32];
+
+ sal_y = u3r_bytes_all(&sal_w, sal);
+ ruz_y = u3r_bytes_all(&ruz_w, ruz);
+ urcrypt_shas(sal_y, sal_w, ruz_y, ruz_w, out_y);
+ u3a_free(sal_y);
+ u3a_free(ruz_y);
+ return u3i_bytes(32, out_y);
+ }
+
+ u3_noun
+ u3we_shax(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ||
+ (c3n == u3ud(a)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_shax(a);
+ }
+ }
+
+ u3_noun
+ u3we_shay(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) ||
+ (u3_none == (b = u3r_at(u3x_sam_3, cor))) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_shay(a, b);
+ }
+ }
+
+ u3_noun
+ u3we_shal(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) ||
+ (u3_none == (b = u3r_at(u3x_sam_3, cor))) ||
+ (c3n == u3ud(a)) ||
+ (c3n == u3ud(b)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_shal(a, b);
+ }
+ }
+
+ u3_noun
+ u3we_shas(u3_noun cor)
+ {
+ u3_noun sal, ruz;
+
+ if ( (u3_none == (sal = u3r_at(u3x_sam_2, cor))) ||
+ (u3_none == (ruz = u3r_at(u3x_sam_3, cor))) ||
+ (c3n == u3ud(sal)) ||
+ (c3n == u3ud(ruz)) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ return _cqe_shas(sal, ruz);
+ }
+ }
+
+ static u3_noun
+ _og_list(u3_noun a,
+ u3_noun b,
+ u3_noun c)
+ {
+ u3_noun l = u3_nul;
+
+ if ( !_(u3a_is_cat(b)) ) {
+ return u3m_bail(c3__fail);
+ }
+ while ( 0 != b ) {
+ u3_noun x = u3qc_mix(a, c);
+ u3_noun y = u3qc_mix(b, x);
+ u3_noun d = _cqe_shas(c3_s4('o','g','-','b'), y);
+ u3_noun m;
+
+ u3z(x); u3z(y);
+
+ if ( b < 256 ) {
+ u3_noun e = u3qc_end(0, b, d);
+
+ u3z(d);
+ m = u3nc(b, e);
+ b = 0;
+ } else {
+ m = u3nc(256, d);
+ c = d;
+
+ b -= 256;
+ }
+ l = u3nc(m, l);
+ }
+ return u3kb_flop(l);
+ }
+
+ u3_noun
+ u3qeo_raw(u3_atom a,
+ u3_atom b)
+ {
+ u3_noun x = u3qc_mix(b, a);
+ u3_noun c = _cqe_shas(c3_s4('o','g','-','a'), x);
+ u3_noun l = _og_list(a, b, c);
+ u3_noun r = u3qc_can(0, l);
+
+ u3z(l);
+ u3z(c);
+ u3z(x);
+
+ return r;
+ }
+
+ u3_noun
+ u3weo_raw(u3_noun cor)
+ {
+ u3_noun a, b;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ) {
+ return u3m_bail(c3__exit);
+ } else {
+ return u3qeo_raw(a, b);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/slaw.c b/vere/pkg/noun/jets/e/slaw.c
new file mode 100644
index 0000000..906b0d7
--- /dev/null
+++ b/vere/pkg/noun/jets/e/slaw.c
@@ -0,0 +1,477 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+#include <ctype.h>
+
+static inline u3_noun
+_parse_ud(u3_noun a)
+{
+ u3_weak pro;
+
+ if ( u3_none == (pro = u3s_sift_ud(u3x_atom(a))) ) {
+ return u3_nul;
+ }
+
+ return u3nc(u3_nul, pro);
+}
+
+static
+u3_noun get_syllable(c3_c** cur_ptr, c3_c* one, c3_c* two, c3_c* three) {
+ if (islower((*cur_ptr)[0]) && islower((*cur_ptr)[1]) &&
+ islower((*cur_ptr)[2])) {
+ *one = (*cur_ptr)[0];
+ *two = (*cur_ptr)[1];
+ *three = (*cur_ptr)[2];
+ (*cur_ptr) += 3;
+ return c3y;
+ } else {
+ return c3n;
+ }
+}
+
+static u3_noun
+combine(u3_noun p, u3_noun q)
+{
+ if ( (c3y == u3a_is_atom(p)) || (c3y == u3a_is_atom(q)) ) {
+ return 0;
+ }
+
+ u3_noun lef = u3qa_mul(256, u3t(q));
+ u3_noun ret = u3nc(0, u3qa_add(u3t(p), lef));
+ u3z(lef);
+ u3z(p); u3z(q);
+
+ return ret;
+}
+
+#define ENSURE_NOT_END() do { \
+ if (*cur == 0) { \
+ u3a_free(c); \
+ return u3_none; \
+ } \
+ } while (0)
+
+#define CONSUME(x) do { \
+ if (*cur != x) { \
+ u3a_free(c); \
+ return u3_none; \
+ } \
+ cur++; \
+ } while (0)
+
+#define TRY_GET_SYLLABLE(prefix) \
+ c3_c prefix##_one, prefix##_two, prefix##_three; \
+ if (c3n == get_syllable(&cur, & prefix##_one, & prefix##_two, & prefix##_three)) { \
+ u3a_free(c); \
+ return u3_none; \
+ }
+
+u3_noun
+_parse_p(u3_noun cor, u3_noun txt) {
+ c3_c* c = u3a_string(txt);
+
+ c3_c* cur = c;
+ CONSUME('~');
+
+ // We at least have a sig prefix. We're now going to parse tuples of three
+ // lowercase letters. Our naming pattern for the pieces we read is [a b c d
+ // ...] as we read them.
+ TRY_GET_SYLLABLE(a);
+
+ // There was only one syllable. If it's a valid suffix syllable, then
+ // it's a galaxy. We don't even have to run this through the scrambler or
+ // check for validity since its already a (unit @).
+ if (*cur == 0) {
+ u3a_free(c);
+ return u3_po_find_suffix(a_one, a_two, a_three);
+ }
+
+ TRY_GET_SYLLABLE(b);
+
+ // There were only two syllables. If they are a valid prefix and suffix, then
+ // it's a star.
+ if (*cur == 0) {
+ u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three);
+ u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three);
+ u3_atom combined = combine(b_part, a_part);
+ u3a_free(c);
+ return combined;
+ }
+
+ // There must now be a - or it is invalid
+ CONSUME('-');
+
+ TRY_GET_SYLLABLE(c);
+
+ ENSURE_NOT_END();
+
+ TRY_GET_SYLLABLE(d);
+
+ if (*cur == 0) {
+ u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three);
+ u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three);
+ u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three);
+ u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three);
+
+ u3_noun m = combine(d_part, combine(c_part, combine(b_part, a_part)));
+ u3a_free(c);
+
+ if (_(u3a_is_atom(m))) {
+ return 0;
+ }
+
+ u3_atom raw = u3k(u3t(m));
+ u3z(m);
+
+ u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob");
+ u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd");
+ return u3nc(0, u3n_slam_on(hok, raw));
+ }
+
+ // There must now be a - or it is invalid.
+ CONSUME('-');
+
+ // The next possible case is a "short" moon. (~ab-cd-ef)
+ TRY_GET_SYLLABLE(e);
+
+ ENSURE_NOT_END();
+
+ TRY_GET_SYLLABLE(f);
+
+ if (*cur == 0) {
+ u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three);
+ u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three);
+ u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three);
+ u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three);
+ u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three);
+ u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three);
+
+ u3_noun m = combine(f_part, combine(e_part, combine(d_part,
+ combine(c_part, combine(b_part, a_part)))));
+ u3a_free(c);
+
+ if (_(u3a_is_atom(m))) {
+ return 0;
+ }
+
+ u3_atom raw = u3k(u3t(m));
+ u3z(m);
+ u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob");
+ u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd");
+ return u3nc(0, u3n_slam_on(hok, raw));
+ }
+
+ // There must now be a - or it is invalid.
+ CONSUME('-');
+
+ // The next possible case is a "long" moon. (~ab-cd-ef-gh)
+ TRY_GET_SYLLABLE(g);
+
+ ENSURE_NOT_END();
+
+ TRY_GET_SYLLABLE(h);
+
+ if (*cur == 0) {
+ u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three);
+ u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three);
+ u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three);
+ u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three);
+ u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three);
+ u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three);
+ u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three);
+ u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three);
+
+ u3_noun m = combine(h_part, combine(g_part, combine(f_part,
+ combine(e_part, combine(d_part, combine(c_part,
+ combine(b_part, a_part)))))));
+ u3a_free(c);
+
+ if (_(u3a_is_atom(m))) {
+ return 0;
+ }
+
+ u3_atom raw = u3k(u3t(m));
+ u3z(m);
+ u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob");
+ u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd");
+ return u3nc(0, u3n_slam_on(hok, raw));
+ }
+
+ // At this point, the only thing it could be is a long comet, of the form
+ // ~ab-cd-ef-gh--ij-kl-mn-op
+
+ CONSUME('-');
+ CONSUME('-');
+
+ TRY_GET_SYLLABLE(i);
+ ENSURE_NOT_END();
+ TRY_GET_SYLLABLE(j);
+ CONSUME('-');
+ TRY_GET_SYLLABLE(k);
+ ENSURE_NOT_END();
+ TRY_GET_SYLLABLE(l);
+ CONSUME('-');
+ TRY_GET_SYLLABLE(m);
+ ENSURE_NOT_END();
+ TRY_GET_SYLLABLE(n);
+ CONSUME('-');
+ TRY_GET_SYLLABLE(o);
+ ENSURE_NOT_END();
+ TRY_GET_SYLLABLE(p);
+
+ if (*cur != 0) {
+ // We've parsed all of a comet shape, and there's still more in the
+ // string. Bail back to the interpreter.
+ u3a_free(c);
+ return u3_none;
+ }
+
+ // We have a long comet. Time to jam it all together. We rely on combine()
+ // for the error checking and we don't have to scramble comet names.
+ u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three);
+ u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three);
+ u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three);
+ u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three);
+ u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three);
+ u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three);
+ u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three);
+ u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three);
+ u3_noun i_part = u3_po_find_prefix(i_one, i_two, i_three);
+ u3_noun j_part = u3_po_find_suffix(j_one, j_two, j_three);
+ u3_noun k_part = u3_po_find_prefix(k_one, k_two, k_three);
+ u3_noun l_part = u3_po_find_suffix(l_one, l_two, l_three);
+ u3_noun m_part = u3_po_find_prefix(m_one, m_two, m_three);
+ u3_noun n_part = u3_po_find_suffix(n_one, n_two, n_three);
+ u3_noun o_part = u3_po_find_prefix(o_one, o_two, o_three);
+ u3_noun p_part = u3_po_find_suffix(p_one, p_two, p_three);
+
+ u3a_free(c);
+
+ return combine(p_part, combine(o_part, combine(n_part, combine(m_part,
+ combine(l_part, combine(k_part, combine(j_part, combine(i_part,
+ combine(h_part, combine(g_part, combine(f_part, combine(e_part,
+ combine(d_part, combine(c_part, combine(b_part, a_part)))))))))))))));
+}
+
+#define PARSE_NONZERO_NUMBER(numname) \
+ c3_w numname = 0; \
+ do { \
+ if (cur[0] > '9' || cur[0] < '1') { \
+ u3a_free(c); \
+ return u3_none; \
+ } \
+ numname = cur[0] - '0'; \
+ cur++; \
+ while (isdigit(cur[0])) { \
+ numname = u3ka_mul(numname, 10); \
+ numname = u3ka_add(numname, cur[0] - '0'); \
+ cur++; \
+ } \
+ } while (0)
+
+#define PARSE_INCLUDING_ZERO_NUMBER(numname) \
+ c3_w numname = 0; \
+ do { \
+ if (cur[0] > '9' || cur[0] < '0') { \
+ u3a_free(c); \
+ return u3_none; \
+ } \
+ numname = cur[0] - '0'; \
+ cur++; \
+ while (isdigit(cur[0])) { \
+ numname = u3ka_mul(numname, 10); \
+ numname = u3ka_add(numname, cur[0] - '0'); \
+ cur++; \
+ } \
+ } while (0)
+
+#define PARSE_HEX_DIGIT(out) \
+ do { \
+ if (cur[0] >= '0' && cur[0] <= '9') { \
+ out = cur[0] - '0'; \
+ } else if (cur[0] >= 'a' && cur[0] <= 'f') { \
+ out = 10 + cur[0] - 'a'; \
+ } else { \
+ u3a_free(c); \
+ return u3_none; \
+ } \
+ cur++; \
+ } while(0)
+
+
+u3_noun
+_parse_da(u3_noun cor, u3_noun txt) {
+ c3_c* c = u3a_string(txt);
+
+ c3_c* cur = c;
+ CONSUME('~');
+
+ // Parse out an arbitrary year number. Starts with a nonzero digit followed
+ // by a series of any digits.
+ PARSE_NONZERO_NUMBER(year);
+
+ // Parse the optional negative sign for BC dates.
+ u3_noun bc = c3y;
+ if (cur[0] == '-') {
+ bc = c3n;
+ cur++;
+ }
+
+ CONSUME('.');
+
+ // Parse out a two digit month (mot:ag). Either a single digit 1-9 or 1[012].
+ c3_y month;
+ if (cur[0] == '1') {
+ if (cur[1] <= '2' && cur[1] >= '0') {
+ // This is a two number month.
+ month = 10 + cur[1] - '0';
+ cur += 2;
+ } else {
+ // This is January.
+ month = 1;
+ cur++;
+ }
+ } else if (cur[0] <= '9' && cur[0] >= '2') {
+ month = cur[0] - '0';
+ cur++;
+ } else {
+ u3a_free(c);
+ return u3_none;
+ }
+
+ CONSUME('.');
+
+ // Parse out a two digit day (dip:ag). This number can be really big, so we
+ // can track number of days since September 1993.
+ PARSE_NONZERO_NUMBER(day);
+
+ if (cur[0] == 0) {
+ u3a_free(c);
+ u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year");
+ u3_noun res = u3n_slam_on(hok,
+ u3nt(u3nc(bc, year), month,
+ u3nc(day, u3nq(0, 0, 0, 0))));
+ return u3nc(0, res);
+ }
+
+ CONSUME('.');
+ CONSUME('.');
+
+ PARSE_INCLUDING_ZERO_NUMBER(hour);
+ CONSUME('.');
+ PARSE_INCLUDING_ZERO_NUMBER(minute);
+ CONSUME('.');
+ PARSE_INCLUDING_ZERO_NUMBER(second);
+
+ if (cur[0] == 0) {
+ u3a_free(c);
+ u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year");
+ u3_noun res = u3n_slam_on(hok,
+ u3nt(u3nc(bc, year), month,
+ u3nc(day, u3nq(hour, minute, second, 0))));
+ return u3nc(0, res);
+ }
+
+ CONSUME('.');
+ CONSUME('.');
+
+ // Now we have to parse a list of hexidecimal numbers 0-f of length 4 only
+ // (zero padded otherwise) separated by dots.
+ u3_noun list = 0;
+ while (1) {
+ // Parse 4 hex digits
+ c3_y one, two, three, four;
+ PARSE_HEX_DIGIT(one);
+ PARSE_HEX_DIGIT(two);
+ PARSE_HEX_DIGIT(three);
+ PARSE_HEX_DIGIT(four);
+
+ c3_w current = (one << 12) + (two << 8) + (three << 4) + four;
+ list = u3nc(u3i_words(1, &current), list);
+
+ if (cur[0] == 0) {
+ u3a_free(c);
+
+ u3_noun flopped = u3qb_flop(list);
+ u3z(list);
+
+ u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year");
+ u3_noun res = u3n_slam_on(hok,
+ u3nt(u3nc(bc, year), month,
+ u3nc(day,
+ u3nq(hour, minute, second, flopped))));
+ return u3nc(0, res);
+ }
+
+ CONSUME('.');
+ }
+}
+
+#undef ENSURE_NOT_END
+#undef CONSUME
+#undef TRY_GET_SYLLABLE
+#undef PARSE_NONZERO_NUMBER
+#undef PARSE_HEX_DIGIT
+
+u3_noun
+_parse_tas(u3_noun txt) {
+ // For any symbol which matches, txt will return itself as a
+ // value. Therefore, this is mostly checking validity.
+ c3_c* c = u3a_string(txt);
+
+ // First character must represent a lowercase letter
+ c3_c* cur = c;
+ if (!islower(cur[0])) {
+ u3a_free(c);
+ return 0;
+ }
+ cur++;
+
+ while (cur[0] != 0) {
+ if (!(islower(cur[0]) || isdigit(cur[0]) || cur[0] == '-')) {
+ u3a_free(c);
+ return 0;
+ }
+
+ cur++;
+ }
+
+ u3a_free(c);
+ return u3nc(0, u3k(txt));
+}
+
+u3_noun
+u3we_slaw(u3_noun cor)
+{
+ u3_noun mod;
+ u3_noun txt;
+
+ if (c3n == u3r_mean(cor, u3x_sam_2, &mod,
+ u3x_sam_3, &txt, 0)) {
+ return u3m_bail(c3__exit);
+ }
+
+ switch (mod) {
+ case c3__da:
+ return _parse_da(cor, txt);
+
+ case 'p':
+ return _parse_p(cor, txt);
+
+ case c3__ud:
+ return _parse_ud(txt);
+
+ // %ta is used once in link.hoon. don't bother.
+
+ case c3__tas:
+ return _parse_tas(txt);
+
+ default:
+ return u3_none;
+ }
+}
diff --git a/vere/pkg/noun/jets/e/tape.c b/vere/pkg/noun/jets/e/tape.c
new file mode 100644
index 0000000..4d251b6
--- /dev/null
+++ b/vere/pkg/noun/jets/e/tape.c
@@ -0,0 +1,53 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ static u3_noun
+ _norm(u3_noun a)
+ {
+ if ( c3n == u3du(a) ) {
+ return u3_nul;
+ } else {
+ return u3nc(((c3y == u3du(u3h(a))) ? u3_nul : u3k(u3h(a))),
+ _norm(u3t(a)));
+ }
+ }
+
+ static u3_noun
+ _good(u3_noun a)
+ {
+ while ( 1 ) {
+ if ( u3_nul == a ) {
+ return c3y;
+ }
+ if ( c3n == u3ud(u3h(a)) ) {
+ return c3n;
+ }
+ a = u3t(a);
+ }
+ }
+
+ u3_noun
+ u3qe_tape(u3_noun a)
+ {
+ if ( c3y == _good(a) ) {
+ return u3k(a);
+ } else {
+ return _norm(a);
+ }
+ }
+ u3_noun
+ u3we_tape(u3_noun cor)
+ {
+ u3_noun a;
+
+ if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qe_tape(a);
+ }
+ }
diff --git a/vere/pkg/noun/jets/e/trip.c b/vere/pkg/noun/jets/e/trip.c
new file mode 100644
index 0000000..519a852
--- /dev/null
+++ b/vere/pkg/noun/jets/e/trip.c
@@ -0,0 +1,33 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_trip(u3_atom a)
+{
+ return u3qc_rip(3, 1, a);
+}
+
+u3_noun
+u3we_trip(u3_noun cor)
+{
+ u3_noun a = u3x_at(u3x_sam, cor);
+
+ if ( c3n == u3ud(a) ) {
+ return u3m_bail(c3__exit);
+ }
+
+ return u3qe_trip(a);
+}
+
+u3_atom
+u3ke_trip(u3_noun a)
+{
+ u3_atom pro = u3qe_trip(a);
+ u3z(a);
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/e/urwasm.c b/vere/pkg/noun/jets/e/urwasm.c
new file mode 100644
index 0000000..626aef3
--- /dev/null
+++ b/vere/pkg/noun/jets/e/urwasm.c
@@ -0,0 +1,3086 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+#include "wasm3.h"
+#include "m3_env.h"
+
+// #define URWASM_SUBROAD
+#define URWASM_STATEFUL
+
+#define ONCE_CTX 63
+#define RUN_CTX 7
+
+#define AX_RUNNABLE 374
+#define AX_ARROWS 1502
+
+#define AX_CALL 20
+#define AX_MEMREAD 383
+#define AX_MEMWRITE 94
+#define AX_CALL_EXT 375
+#define AX_GLOBAL_SET 4
+#define AX_GLOBAL_GET 22
+#define AX_MEM_SIZE 186
+#define AX_MEM_GROW 381
+#define AX_GET_ACC 374
+#define AX_SET_ACC 92
+#define AX_GET_ALL_GLOB 43
+#define AX_SET_ALL_GLOB 380
+
+#define AX_TRY 43
+#define AX_CATCH 4
+#define AX_RETURN 20
+#define AX_FAIL 47
+
+#define ARROW_CTX 511
+#define MONAD_CTX 127
+
+#define arr_sam 62
+#define arr_sam_2 124
+#define arr_sam_3 125
+#define arr_sam_6 250
+#define arr_sam_7 251
+
+#define seed_module 2
+#define seed_past 6
+#define seed_shop 14
+#define seed_import 15
+
+#define uw__lia c3_s3('l', 'i', 'a')
+
+#define uw_lia_run_version 1
+
+#define ERR(string) ("\r\n\033[31m>>> " string "\033[0m\r\n")
+#define WUT(string) ("\r\n\033[33m>> " string "\033[0m\r\n")
+#define DBG(string) ("\r\n" string "\r\n")
+
+#define KICK1(TRAP) uw_kick_nock(TRAP, 2)
+#define KICK2(TRAP) KICK1(KICK1(TRAP))
+
+// [a b c d e f g h]
+static inline u3_noun
+uw_octo(u3_noun a,
+ u3_noun b,
+ u3_noun c,
+ u3_noun d,
+ u3_noun e,
+ u3_noun f,
+ u3_noun g,
+ u3_noun h)
+{
+ return u3nc(a, u3nq(b, c, d, u3nq(e, f, g, h)));
+}
+
+// kick by nock. axe RETAINED (ignore if direct)
+static u3_noun
+uw_kick_nock(u3_noun cor, u3_noun axe)
+{
+ u3_noun fol = u3x_at(axe, cor);
+ return u3n_nock_on(cor, u3k(fol));
+}
+
+// slam by nock
+static u3_noun
+uw_slam_nock(u3_noun gat, u3_noun sam)
+{
+ u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat)))));
+ u3z(gat);
+ return uw_kick_nock(cor, 2);
+}
+
+static u3_noun
+uw_slam_check(u3_noun gat, u3_noun sam, c3_t is_stateful)
+{
+ u3_noun bat = u3k(u3h(gat));
+ u3_noun cor = u3nc(u3k(bat), u3nc(sam, u3k(u3t(u3t(gat)))));
+ u3z(gat);
+
+ if (!is_stateful)
+ {
+ return u3n_nock_on(cor, bat);
+ }
+ else
+ {
+ u3_noun ton = u3n_nock_an(cor, bat);
+
+ u3_noun tag, pro;
+ if (c3n == u3r_cell(ton, &tag, &pro))
+ {
+ return u3m_bail(c3__fail);
+ }
+ if (0 == tag)
+ {
+ u3k(pro);
+ u3z(ton);
+ return pro;
+ }
+ else if (2 == tag)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+}
+
+static inline void
+_push_list(u3_noun som, u3_noun *lit)
+{
+ if (u3_none == *lit)
+ {
+ u3z(som);
+ }
+ else
+ {
+ *lit = u3nc(som, *lit);
+ }
+}
+
+static inline u3_weak
+_pop_list(u3_weak *lit)
+{
+ if (u3_none == *lit)
+ {
+ return u3_none;
+ }
+ u3_noun hed, tel;
+ if (c3n == u3r_cell(*lit, &hed, &tel))
+ {
+ return u3m_bail(c3__fail);
+ }
+ u3k(hed);
+ u3k(tel);
+ u3z(*lit);
+ *lit = tel;
+ return hed;
+}
+
+static const M3Result UrwasmArrowExit = "An imported arrow returned %2";
+
+static const c3_m uw_run_m = uw__lia + c3__run + uw_lia_run_version;
+
+static_assert(
+ (c3y == u3a_is_cat(uw_run_m)),
+ "u3we_run key tag must be a direct atom"
+);
+
+typedef struct {
+ u3_noun call_bat;
+ u3_noun memread_bat;
+ u3_noun memwrite_bat;
+ u3_noun call_ext_bat;
+ u3_noun try_bat;
+ u3_noun catch_bat;
+ u3_noun return_bat;
+ u3_noun fail_bat;
+ u3_noun global_set_bat;
+ u3_noun global_get_bat;
+ u3_noun mem_grow_bat;
+ u3_noun mem_size_bat;
+ u3_noun get_acc_bat;
+ u3_noun set_acc_bat;
+ u3_noun get_all_glob_bat;
+ u3_noun set_all_glob_bat;
+//
+ u3_noun call_ctx;
+ u3_noun memread_ctx;
+ u3_noun memwrite_ctx;
+ u3_noun global_set_ctx;
+ u3_noun global_get_ctx;
+ u3_noun mem_grow_ctx;
+ u3_noun mem_size_ctx;
+ u3_noun get_all_glob_ctx;
+ u3_noun set_all_glob_ctx;
+} match_data_struct;
+
+// memory arena with exponential growth
+typedef struct {
+ c3_w siz_w; // size in bytes
+ c3_y pad_y; // alignment padding
+ c3_t ini_t; // already initialized
+ u3i_slab sab_u; // associated slab
+ c3_y* buf_y; // allocated buffer
+ c3_y* nex_y; // next allocation
+ c3_y* end_y; // end of arena
+ jmp_buf* esc_u; // escape buffer
+} uw_arena;
+
+typedef struct {
+ IM3Module wasm_module; // p
+ u3_noun lia_shop; // q, transferred
+ u3_noun acc; // p.r, transferred
+ u3_noun map; // q.r, retained
+ match_data_struct* match;
+ u3_noun arrow_yil; // transferred
+ u3_noun susp_list; // transferred
+ u3_noun resolution; // resolved %1 block, transferred
+ uw_arena box_arena;
+ uw_arena code_arena;
+ u3_noun yil_previous; // transferred
+ u3_noun queue; // transferred
+ c3_t is_stateful;
+} lia_state;
+
+typedef enum {
+ west_call,
+ west_call_ext,
+ west_try,
+ west_catch_try,
+ west_catch_err,
+ west_link_wasm,
+} wasm3_ext_suspend_tag;
+
+typedef enum {
+ lst_call = 0,
+ // lst_call_ext = 1, // not necessary
+ lst_try = 2,
+ lst_catch_try = 3,
+ lst_catch_err = 4,
+ lst_link_wasm = 5,
+} lia_suspend_tag;
+
+static void
+_uw_arena_init_size(uw_arena* ren_u, c3_w siz_w)
+{
+ ren_u->siz_w = siz_w;
+ u3i_slab_init(&ren_u->sab_u, 3, siz_w + 12); // size + max padding
+ ren_u->buf_y = ren_u->nex_y = c3_align(ren_u->sab_u.buf_y, 16, C3_ALGHI);
+ ren_u->end_y = ren_u->buf_y + ren_u->siz_w;
+ c3_y pad_y = ren_u->buf_y - ren_u->sab_u.buf_y;
+ if (pad_y > 12)
+ {
+ u3m_bail(c3__fail);
+ }
+ ren_u->pad_y = pad_y;
+ ren_u->ini_t = 1;
+}
+
+static void
+_uw_arena_init(uw_arena* ren_u)
+{
+ _uw_arena_init_size(ren_u, (c3_w)1 << 23);
+}
+
+static void
+_uw_arena_grow(uw_arena* ren_u)
+{
+ if (!ren_u->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_w new_w = ren_u->siz_w * 2;
+ if (new_w / 2 != ren_u->siz_w)
+ {
+ u3m_bail(c3__fail);
+ }
+ ren_u->siz_w = new_w;
+
+ u3i_slab_free(&ren_u->sab_u);
+
+ u3i_slab_init(&ren_u->sab_u, 3, new_w + 12); // size + max padding
+ ren_u->buf_y = ren_u->nex_y = c3_align(ren_u->sab_u.buf_y, 16, C3_ALGHI);
+ ren_u->end_y = ren_u->nex_y + new_w;
+ c3_y pad_y = ren_u->nex_y - ren_u->sab_u.buf_y;
+ if (pad_y > 12)
+ {
+ u3m_bail(c3__fail);
+ }
+ ren_u->pad_y = pad_y;
+}
+
+static void
+_uw_arena_reset(uw_arena* ren_u)
+{
+ if (!ren_u->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ ren_u->nex_y = ren_u->buf_y;
+ memset(ren_u->buf_y, 0, (size_t)ren_u->siz_w);
+}
+
+static void
+_uw_arena_free(uw_arena* ren_u)
+{
+ if (!ren_u->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ u3i_slab_free(&ren_u->sab_u);
+ ren_u->ini_t = 0;
+}
+
+// Code page allocation: simple bump allocator for non-growing objects,
+// i.e. code pages
+// save allocation length for realloc
+// CodeArena->esc_u MUST be initialized by the caller to handle OOM
+//
+static uw_arena* CodeArena;
+
+static void*
+_calloc_code(size_t num_i, size_t len_i)
+{
+ if (!CodeArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+
+ void* lag_v = CodeArena->nex_y;
+
+ size_t byt_i = num_i * len_i;
+ if (byt_i / len_i != num_i)
+ {
+ u3m_bail(c3__fail);
+ }
+
+ if (byt_i >= UINT64_MAX - 16)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_d byt_d = byt_i + 16; // c3_d for length + alignment padding
+
+ c3_y* nex_y = CodeArena->nex_y + byt_d;
+ nex_y = c3_align(nex_y, 16, C3_ALGHI);
+
+ if (nex_y >= CodeArena->end_y)
+ { // OOM, jump out to increase the arena size and try again
+ _longjmp(*CodeArena->esc_u, c3__code);
+ }
+
+ *((c3_d*)lag_v) = byt_d - 16; // corruption check
+ *((c3_d*)lag_v + 1) = byt_d - 16;
+
+ CodeArena->nex_y = nex_y;
+ return ((c3_d*)lag_v + 2);
+}
+
+static void*
+_realloc_code(void* lag_v, size_t len_i)
+{
+ if (!CodeArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ if (!lag_v)
+ {
+ return _calloc_code(len_i, 1);
+ }
+ c3_d old1_d = *((c3_d*)lag_v - 1);
+ c3_d old2_d = *((c3_d*)lag_v - 2);
+ if (old1_d != old2_d)
+ {
+ u3m_bail(c3__fail);
+ }
+ if (len_i >= UINT64_MAX)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_d len_d = len_i;
+ void* new_v = _calloc_code(len_d, 1);
+ memcpy(new_v, lag_v, c3_min(len_d, old1_d));
+
+ return new_v;
+}
+
+static void
+_free_code(void* lag_v)
+{
+ if (!CodeArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ // noop
+}
+
+// Struct/array allocation: [len_d cap_d data]
+// BoxArena->esc_u MUST be initialized by the caller to handle OOM
+//
+static uw_arena* BoxArena;
+
+// allocate with capacity
+// the allocated buffer
+static void*
+_malloc_box_cap(c3_d len_d, c3_d cap_d)
+{
+ if (!BoxArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+
+ void* lag_v = BoxArena->nex_y;
+
+ if (cap_d >= UINT64_MAX - 16)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_d pac_d = cap_d + 16; // c3_d for length + capacity
+
+ c3_y* nex_y = BoxArena->nex_y + pac_d;
+ nex_y = c3_align(nex_y, 16, C3_ALGHI);
+
+ if (nex_y >= BoxArena->end_y)
+ { // OOM, jump out to increase the arena size and try again
+ _longjmp(*BoxArena->esc_u, c3__box);
+ }
+
+ *((c3_d*)lag_v) = len_d;
+ *((c3_d*)lag_v + 1) = cap_d;
+
+ BoxArena->nex_y = nex_y;
+ return ((c3_d*)lag_v + 2);
+}
+
+static void*
+_calloc_box(size_t num_i, size_t len_i)
+{
+ size_t byt_i = num_i * len_i;
+ if (byt_i / len_i != num_i)
+ {
+ u3m_bail(c3__fail);
+ }
+ if (byt_i > UINT64_MAX - 16)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_d byt_d = byt_i;
+ return _malloc_box_cap(byt_d, byt_d);
+}
+
+static void*
+_realloc_box(void* lag_v, size_t len_i)
+{
+ if (!BoxArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ if (!lag_v)
+ {
+ return _calloc_box(len_i, 1);
+ }
+ c3_d old_d = *((c3_d*)lag_v - 2);
+ c3_d cap_d = *((c3_d*)lag_v - 1);
+ if (len_i >= UINT64_MAX)
+ {
+ u3m_bail(c3__fail);
+ }
+ c3_d len_d = len_i;
+ if (len_d <= cap_d)
+ {
+ *((c3_d*)lag_v - 2) = len_d;
+ return lag_v;
+ }
+
+ // while (cap_d <= len_d)
+ // {
+ // cap_d *= 2;
+ // }
+ cap_d <<= c3_bits_dabl(len_d) - c3_bits_dabl(cap_d);
+ cap_d <<= (cap_d <= len_d);
+
+ // overflow check
+ if (cap_d <= len_d)
+ u3m_bail(c3__fail);
+
+ void* new_v = _malloc_box_cap(len_d, cap_d);
+ memcpy(new_v, lag_v, old_d);
+
+ return new_v;
+}
+
+static void
+_free_box(void* lag_v)
+{
+ if (!BoxArena->ini_t)
+ {
+ u3m_bail(c3__fail);
+ }
+ // noop
+}
+
+// bailing allocator to prevent wasm3 from touching the arenas
+
+static void*
+_calloc_bail(size_t num_i, size_t len_i)
+{
+ u3m_bail(c3__fail);
+}
+
+static void*
+_realloc_bail(void* lag_v, size_t len_i)
+{
+ u3m_bail(c3__fail);
+}
+
+static void
+_free_bail(void* lag_v)
+{
+ u3m_bail(c3__fail);
+}
+
+
+static u3_noun
+_atoms_from_stack(void** valptrs, c3_w n, c3_y* types)
+{
+ u3_noun out = u3_nul;
+ while (n--)
+ {
+ switch (types[n])
+ { // TODO 64 bit vere
+ case c_m3Type_i32:
+ case c_m3Type_f32:
+ {
+ out = u3nc(u3i_word(*(c3_w*)valptrs[n]), out);
+ break;
+ }
+ case c_m3Type_i64:
+ case c_m3Type_f64:
+ {
+ out = u3nc(u3i_chub(*(c3_d*)valptrs[n]), out);
+ break;
+ }
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ return out;
+}
+
+// RETAIN argument
+static c3_o
+_atoms_to_stack(u3_noun atoms, void** valptrs, c3_w n, c3_y* types)
+{
+ for (c3_w i = 0; i < n; i++)
+ {
+ if (c3y == u3ud(atoms))
+ {
+ return c3n;
+ }
+ u3_noun atom;
+ u3x_cell(atoms, &atom, &atoms);
+ if (c3n == u3ud(atom))
+ {
+ return u3m_bail(c3__fail);
+ }
+ switch (types[i])
+ {
+ case c_m3Type_i32:
+ case c_m3Type_f32:
+ {
+ *(c3_w*)valptrs[i] = u3r_word(0, atom);
+ break;
+ }
+ case c_m3Type_i64:
+ case c_m3Type_f64:
+ {
+ *(c3_d*)valptrs[i] = u3r_chub(0, atom);
+ break;
+ }
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ return __(u3_nul == atoms);
+}
+
+static u3_noun
+_coins_from_stack(void** valptrs, c3_w n, c3_y* types)
+{
+ u3_noun out = u3_nul;
+ while (n--)
+ {
+ switch (types[n])
+ { // TODO 64 bit vere
+ case c_m3Type_i32:
+ {
+ out = u3nc(u3nc(c3__i32, u3i_word(*(c3_w*)valptrs[n])), out);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ out = u3nc(u3nc(c3__i64, u3i_chub(*(c3_d*)valptrs[n])), out);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ out = u3nc(u3nc(c3__f32, u3i_word(*(c3_w*)valptrs[n])), out);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ out = u3nc(u3nc(c3__f64, u3i_chub(*(c3_d*)valptrs[n])), out);
+ break;
+ }
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ return out;
+}
+
+// RETAIN argument
+static c3_o
+_coins_to_stack(u3_noun coins, void** valptrs, c3_w n, c3_y* types)
+{
+ for (c3_w i = 0; i < n; i++)
+ {
+ if (c3y == u3ud(coins))
+ {
+ return c3n;
+ }
+ u3_noun coin;
+ u3x_cell(coins, &coin, &coins);
+ if (c3y == u3ud(coin))
+ {
+ return u3m_bail(c3__fail);
+ }
+ u3_noun tag, value;
+ u3x_cell(coin, &tag, &value);
+ if (c3n == u3ud(value))
+ {
+ return u3m_bail(c3__fail);
+ }
+ switch (types[i])
+ {
+ case c_m3Type_i32:
+ {
+ if (c3__i32 != tag)
+ {
+ return c3n;
+ }
+ *(c3_w*)valptrs[i] = u3r_word(0, value);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ if (c3__i64 != tag)
+ {
+ return c3n;
+ }
+ *(c3_d*)valptrs[i] = u3r_chub(0, value);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ if (c3__f32 != tag)
+ {
+ return c3n;
+ }
+ *(c3_w*)valptrs[i] = u3r_word(0, value);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ if (c3__f64 != tag)
+ {
+ return c3n;
+ }
+ *(c3_d*)valptrs[i] = u3r_chub(0, value);
+ break;
+ }
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ return __(u3_nul == coins);
+}
+
+static c3_t
+_deterministic_trap(M3Result result)
+{
+ return ( result == m3Err_trapOutOfBoundsMemoryAccess
+ || result == m3Err_trapDivisionByZero
+ || result == m3Err_trapIntegerOverflow
+ || result == m3Err_trapIntegerConversion
+ || result == m3Err_trapIndirectCallTypeMismatch
+ || result == m3Err_trapTableIndexOutOfRange
+ || result == m3Err_trapTableElementIsNull
+ || result == UrwasmArrowExit
+ );
+}
+
+static u3_noun
+_reduce_monad(u3_noun monad, lia_state* sat_u)
+{
+ u3_noun monad_bat = u3h(monad);
+ if (c3y == u3r_sing(monad_bat, sat_u->match->call_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->call_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // call
+ u3_atom name = u3x_atom(u3at(arr_sam_2, monad));
+ u3_noun args = u3at(arr_sam_3, monad);
+
+ c3_w met_w = u3r_met(3, name);
+ c3_c* name_c = u3a_malloc(met_w + 1);
+ u3r_bytes(0, met_w, (c3_y*)name_c, name);
+ name_c[met_w] = 0;
+
+ M3Result result;
+
+ IM3Function f;
+ result = m3_FindFunction(&f, sat_u->wasm_module->runtime, name_c);
+
+ if (result)
+ {
+ fprintf(stderr, ERR("function %s search error: %s"), name_c, result);
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w n_in = f->funcType->numArgs;
+ c3_w n_out = f->funcType->numRets;
+ c3_y* types = f->funcType->types;
+
+ c3_d *vals_in = u3a_calloc(n_in, sizeof(c3_d));
+ void **valptrs_in = u3a_calloc(n_in, sizeof(void*));
+ for (c3_w i = 0; i < n_in; i++)
+ {
+ valptrs_in[i] = &vals_in[i];
+ }
+
+ c3_d *vals_out = u3a_calloc(n_out, sizeof(c3_d));
+ void **valptrs_out = u3a_calloc(n_out, sizeof(void*));
+ for (c3_w i = 0; i < n_out; i++)
+ {
+ valptrs_out[i] = &vals_out[i];
+ }
+
+ if (c3n == _atoms_to_stack(args, valptrs_in, n_in, (types+n_out)))
+ {
+ fprintf(stderr, ERR("function %s wrong number of args"), name_c);
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w edge_1 = sat_u->wasm_module->runtime->edge_suspend;
+
+ // printf("\r\n\r\n invoke %s\r\n\r\n", name_c);
+
+ { // push on suspend stacks
+ c3_d f_idx_d = f - sat_u->wasm_module->functions;
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, f_idx_d);
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_call);
+ m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime);
+ _push_list(
+ u3nc(lst_call, u3k(name)),
+ &sat_u->susp_list
+ );
+ }
+
+ M3Result result_call = m3_Call(f, n_in, (const void**)valptrs_in);
+ // printf("\r\n done %s\r\n", name_c);
+
+ if (result_call != m3Err_ComputationBlock
+ && result_call != m3Err_SuspensionError)
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag);
+ if (tag != -1 && tag != west_call)
+ {
+ printf(ERR("call tag mismatch: %"PRIc3_d), tag);
+ return u3m_bail(c3__fail);
+ }
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, NULL);
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (u3_none != frame && lst_call != u3h(frame))
+ {
+ printf(ERR("wrong frame: call"));
+ return u3m_bail(c3__fail);
+ }
+ u3z(frame);
+ }
+
+ u3_noun yil;
+ if (result_call == m3Err_ComputationBlock)
+ {
+ yil = sat_u->arrow_yil;
+ sat_u->arrow_yil = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ else if (_deterministic_trap(result_call))
+ {
+ fprintf(stderr, WUT("%s call trapped: %s"), name_c, result_call);
+ yil = u3nc(2, 0);
+ }
+ else if (result_call == m3Err_functionImportMissing)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else if (result_call)
+ {
+ fprintf(stderr, ERR("%s call failed: %s"), name_c, result_call);
+ return u3m_bail(c3__fail);
+ }
+ else
+ {
+ result = m3_GetResults(f, n_out, (const void**)valptrs_out);
+ if (result)
+ {
+ fprintf(stderr, ERR("function %s failed to get results"), name_c);
+ return u3m_bail(c3__fail);
+ }
+ yil = u3nc(0, _atoms_from_stack(valptrs_out, n_out, types));
+ }
+
+ c3_w edge_2 = sat_u->wasm_module->runtime->edge_suspend;
+ if (edge_1 != edge_2 && !result_call)
+ {
+ fprintf(stderr, ERR("imbalanced suspension stack on succesfull return: %d vs %d"), edge_1, edge_2);
+ return u3m_bail(c3__fail);
+ }
+
+ u3a_free(name_c);
+ u3a_free(vals_in);
+ u3a_free(valptrs_in);
+ u3a_free(vals_out);
+ u3a_free(valptrs_out);
+ u3z(monad);
+
+ return yil;
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->memread_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->memread_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // memread
+ u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad));
+ u3_noun len = u3at(arr_sam_3, monad);
+
+ c3_w ptr_w = u3r_word(0, ptr);
+ c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail);
+ c3_w len_buf_w;
+ c3_y* buf_y = m3_GetMemory(sat_u->wasm_module->runtime, &len_buf_w, 0);
+
+ if (buf_y == NULL)
+ {
+ fprintf(stderr, ERR("memread failed to get memory"));
+ return u3m_bail(c3__fail);
+ }
+
+ if (ptr_w + len_l > len_buf_w)
+ {
+ fprintf(stderr, ERR("memread out of bounds"));
+ return u3m_bail(c3__fail);
+ }
+
+ u3z(monad);
+ return u3nt(0, len_l, u3i_bytes(len_l, (buf_y + ptr_w)));
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->memwrite_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->memwrite_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // memwrite
+ u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad));
+ u3_noun len = u3at(arr_sam_6, monad);
+ u3_noun src = u3at(arr_sam_7, monad);
+
+ c3_w ptr_w = u3r_word(0, ptr);
+ c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail);
+
+ c3_w len_buf_w;
+ c3_y* buf_y = m3_GetMemory(sat_u->wasm_module->runtime, &len_buf_w, 0);
+
+ if (buf_y == NULL)
+ {
+ fprintf(stderr, ERR("memwrite failed to get memory"));
+ return u3m_bail(c3__fail);
+ }
+
+ if (ptr_w + len_l > len_buf_w)
+ {
+ fprintf(stderr, ERR("memwrite out of bounds"));
+ return u3m_bail(c3__fail);
+ }
+
+ u3r_bytes(0, len_l, (buf_y + ptr_w), u3x_atom(src));
+
+ u3z(monad);
+ return u3nc(0, 0);
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->call_ext_bat))
+ {
+ // call-ext
+ if (u3_nul == sat_u->lia_shop)
+ {
+ // Suspended computation will have exactly one blocking point, which
+ // must be at the top of the stack. You are at this point.
+ // There is no useful info to be saved here, name/args are not enough
+ // to qualify the external call, which can and will be nondeterministic
+ // (like all IO in urbit)
+ //
+ // On wasm3 side op_CallRaw will store the information about the
+ // called function. It shall be the top frame of the suspension stack,
+ // since only Lia can block, so wasm3 has to call Lia to get blocked.
+ //
+ // A frame is pushed in wasm3 to trigger the callback and signal to
+ // _apply_diff that the computation is blocked
+ //
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_call_ext);
+ m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime);
+
+ u3_noun name = u3at(arr_sam_2, monad);
+ u3_noun args = u3at(arr_sam_3, monad);
+
+ u3_noun yil = u3nt(1, u3k(name), u3k(args));
+ u3z(monad);
+ return yil;
+ }
+ else
+ {
+ u3z(monad);
+
+ u3_noun lia_buy, tel;
+ u3x_cell(sat_u->lia_shop, &lia_buy, &tel);
+ u3_noun yil = u3nc(0, u3k(lia_buy));
+ u3k(tel);
+ u3z(sat_u->lia_shop);
+ sat_u->lia_shop = tel;
+ return yil;
+ }
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->try_bat))
+ {
+ // try
+ u3_noun monad_b = u3at(60, monad);
+ u3_noun cont = u3at(61, monad);
+ u3_weak yil;
+ u3_noun monad_cont;
+ { // push on suspend stacks
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_try);
+ m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime);
+ _push_list(u3nc(lst_try, u3k(cont)), &sat_u->susp_list);
+ }
+ {
+ yil = _reduce_monad(u3k(monad_b), sat_u);
+
+ if (1 != u3h(yil))
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag);
+ if (tag != -1 && tag != west_try)
+ {
+ printf(ERR("try tag mismatch: %"PRIc3_d), tag);
+ return u3m_bail(c3__fail);
+ }
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (u3_none != frame && lst_try != u3h(frame))
+ {
+ printf(ERR("wrong frame: try"));
+ return u3m_bail(c3__fail);
+ }
+ u3z(frame);
+ }
+
+ if (0 == u3h(yil))
+ {
+ // any unconstrained nock computation is a potential urwasm reentry:
+ // save the pointers before that, restore after
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(u3t(yil)),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(yil);
+ yil = u3_none;
+ }
+ }
+
+ u3z(monad);
+ if (u3_none == yil)
+ {
+ return _reduce_monad(monad_cont, sat_u);
+ }
+ else
+ {
+ return yil;
+ }
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->catch_bat))
+ {
+ // catch
+ u3_noun monad_try = u3at(120, monad);
+ u3_noun monad_catch = u3at(121, monad);
+ u3_noun cont = u3at(61, monad);
+ u3_weak yil;
+ u3_noun monad_cont;
+
+ {
+ { // push on suspend stacks
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_try);
+ m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime);
+ _push_list(
+ u3nt(lst_catch_try, u3k(monad_catch), u3k(cont)),
+ &sat_u->susp_list
+ );
+ }
+ yil = _reduce_monad(u3k(monad_try), sat_u);
+
+ if (1 != u3h(yil))
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag);
+ if (tag != -1 && tag != west_catch_try)
+ {
+ printf(ERR("catch-try tag mismatch: %"PRIc3_d), tag);
+ return u3m_bail(c3__fail);
+ }
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (u3_none != frame && lst_catch_try != u3h(frame))
+ {
+ printf(ERR("wrong frame: catch-try"));
+ return u3m_bail(c3__fail);
+ }
+ u3z(frame);
+ }
+
+ if (0 == u3h(yil))
+ {
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(u3t(yil)),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(yil);
+ yil = u3_none;
+ }
+ else if (2 == u3h(yil))
+ {
+ u3z(yil);
+
+ { // push on suspend stacks
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_err);
+ m3_SuspendStackPushExtTag(sat_u->wasm_module->runtime);
+ _push_list(
+ u3nc(lst_catch_err, u3k(cont)),
+ &sat_u->susp_list
+ );
+ }
+
+ yil = _reduce_monad(u3k(monad_catch), sat_u);
+
+ if (1 != u3h(yil))
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(sat_u->wasm_module->runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag);
+ if (tag != -1 && tag != west_catch_err)
+ {
+ printf(ERR("catch-err tag mismatch: %"PRIc3_d), tag);
+ return u3m_bail(c3__fail);
+ }
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (u3_none != frame && lst_catch_err != u3h(frame))
+ {
+ printf(ERR("wrong frame: catch-err"));
+ return u3m_bail(c3__fail);
+ }
+ u3z(frame);
+ }
+
+ if (0 == u3h(yil))
+ {
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(u3t(yil)),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(yil);
+ yil = u3_none;
+ }
+ }
+ }
+
+ u3z(monad);
+ if (u3_none == yil)
+ {
+ return _reduce_monad(monad_cont, sat_u);
+ }
+ else
+ {
+ return yil;
+ }
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->return_bat))
+ {
+ // return
+ u3_noun yil = u3nc(0, u3k(u3at(30, monad)));
+ u3z(monad);
+ return yil;
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->global_set_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->global_set_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // global-set
+ u3_atom name = u3x_atom(u3at(arr_sam_2, monad));
+ u3_atom value = u3x_atom(u3at(arr_sam_3, monad));
+
+ c3_w met_w = u3r_met(3, name);
+ c3_c* name_c = u3a_malloc(met_w + 1);
+ u3r_bytes(0, met_w, (c3_y*)name_c, name);
+ name_c[met_w] = 0;
+
+ IM3Global glob = m3_FindGlobal(sat_u->wasm_module, name_c);
+
+ if (!glob)
+ {
+ fprintf(stderr, ERR("global %s not found"), name_c);
+ return u3m_bail(c3__fail);
+ }
+
+ if (!glob->isMutable)
+ {
+ fprintf(stderr, ERR("global %s not mutable"), name_c);
+ return u3m_bail(c3__fail);
+ }
+
+ M3TaggedValue glob_value;
+ M3Result result = m3_GetGlobal(glob, &glob_value);
+ if (result)
+ {
+ fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result);
+ return u3m_bail(c3__fail);
+ }
+ switch (glob_value.type)
+ {
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ case c_m3Type_i32:
+ {
+ glob_value.value.i32 = u3r_word(0, value);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ glob_value.value.i64 = u3r_chub(0, value);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ glob_value.value.f32 = u3r_word(0, value);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ glob_value.value.f64 = u3r_chub(0, value);
+ break;
+ }
+ }
+ result = m3_SetGlobal(glob, &glob_value);
+ if (result)
+ {
+ fprintf(stderr, ERR("couldn't set global %s: %s"), name_c, result);
+ return u3m_bail(c3__fail);
+ }
+ u3z(monad);
+ u3a_free(name_c);
+ return u3nc(0, 0);
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->global_get_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->global_get_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // global-get
+ u3_atom name = u3x_atom(u3at(arr_sam, monad));
+
+ c3_w met_w = u3r_met(3, name);
+ c3_c* name_c = u3a_malloc(met_w + 1);
+ u3r_bytes(0, met_w, (c3_y*)name_c, name);
+ name_c[met_w] = 0;
+
+ IM3Global glob = m3_FindGlobal(sat_u->wasm_module, name_c);
+ if (!glob)
+ {
+ fprintf(stderr, ERR("global %s not found"), name_c);
+ return u3m_bail(c3__fail);
+ }
+
+ M3TaggedValue glob_value;
+ M3Result result = m3_GetGlobal(glob, &glob_value);
+ if (result)
+ {
+ fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result);
+ return u3m_bail(c3__fail);
+ }
+
+ u3_noun out;
+ switch (glob_value.type)
+ {
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ case c_m3Type_i32:
+ {
+ out = u3i_word(glob_value.value.i32);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ out = u3i_chub(glob_value.value.i64);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ out = u3i_word(glob_value.value.f32);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ out = u3i_chub(glob_value.value.f64);
+ break;
+ }
+ }
+
+ u3z(monad);
+ u3a_free(name_c);
+ return u3nc(0, out);
+
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->mem_size_bat))
+ {
+ if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat_u->match->mem_size_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // memory-size
+ if (!sat_u->wasm_module->memoryInfo.hasMemory)
+ {
+ fprintf(stderr, ERR("memsize no memory"));
+ return u3m_bail(c3__fail);
+ }
+ c3_w num_pages = sat_u->wasm_module->runtime->memory.numPages;
+
+ u3z(monad);
+ return u3nc(0, u3i_word(num_pages));
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->mem_grow_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->mem_grow_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ // memory-grow
+ if (!sat_u->wasm_module->memoryInfo.hasMemory)
+ {
+ fprintf(stderr, ERR("memgrow no memory"));
+ return u3m_bail(c3__fail);
+ }
+
+ u3_noun delta = u3at(arr_sam, monad);
+
+ c3_l delta_l = (c3y == u3a_is_cat(delta)) ? delta : u3m_bail(c3__fail);
+
+ c3_w n_pages = sat_u->wasm_module->runtime->memory.numPages;
+ c3_w required_pages = n_pages + delta_l;
+
+ M3Result result = ResizeMemory(sat_u->wasm_module->runtime, required_pages);
+
+ if (result)
+ {
+ fprintf(stderr, ERR("failed to resize memory: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ u3z(monad);
+ return u3nc(0, u3i_word(n_pages));
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->get_acc_bat))
+ {
+ u3z(monad);
+ return u3nc(0, u3k(sat_u->acc));
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->set_acc_bat))
+ {
+ u3_noun new = u3k(u3at(arr_sam, monad));
+ u3z(monad);
+ u3z(sat_u->acc);
+ sat_u->acc = new;
+ return u3nc(0, 0);
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->get_all_glob_bat))
+ {
+ if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat_u->match->get_all_glob_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ u3z(monad);
+ u3_noun atoms = u3_nul;
+ c3_w n_globals = sat_u->wasm_module->numGlobals;
+ c3_w n_globals_import = sat_u->wasm_module->numGlobImports;
+ while (n_globals-- > n_globals_import)
+ {
+ M3Global glob = sat_u->wasm_module->globals[n_globals];
+ switch (glob.type)
+ {
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ case c_m3Type_i32:
+ {
+ atoms = u3nc(u3i_word(glob.intValue), atoms);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ atoms = u3nc(u3i_chub(glob.intValue), atoms);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ atoms = u3nc(u3i_word(glob.f32Value), atoms);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ atoms = u3nc(u3i_chub(glob.f64Value), atoms);
+ break;
+ }
+ }
+ }
+ return u3nc(0, atoms);
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->set_all_glob_bat))
+ {
+ if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat_u->match->set_all_glob_ctx))
+ {
+ return u3m_bail(c3__fail);
+ }
+ u3_noun atoms = u3at(arr_sam, monad);
+ c3_w n_globals = sat_u->wasm_module->numGlobals;
+ c3_w n_globals_import = sat_u->wasm_module->numGlobImports;
+ for (c3_w i = n_globals_import; i < n_globals; i++)
+ {
+ IM3Global glob = &sat_u->wasm_module->globals[i];
+ u3_noun atom;
+ u3x_cell(atoms, &atom, &atoms);
+ u3x_atom(atom);
+ switch (glob->type)
+ {
+ default:
+ {
+ return u3m_bail(c3__fail);
+ }
+ case c_m3Type_i32:
+ {
+ glob->intValue = u3r_word(0, atom);
+ break;
+ }
+ case c_m3Type_i64:
+ {
+ glob->intValue = u3r_chub(0, atom);
+ break;
+ }
+ case c_m3Type_f32:
+ {
+ glob->f32Value = u3r_word(0, atom);
+ break;
+ }
+ case c_m3Type_f64:
+ {
+ glob->f64Value = u3r_chub(0, atom);
+ break;
+ }
+ }
+ }
+ if (u3_nul != atoms)
+ {
+ fprintf(stderr, WUT("glob list too long"));
+ return u3m_bail(c3__exit);
+ }
+ u3z(monad);
+ return u3nc(0, 0);
+ }
+ else if (c3y == u3r_sing(monad_bat, sat_u->match->fail_bat))
+ {
+ u3z(monad);
+ return u3nc(2, 0);
+ }
+ else
+ {
+ return u3m_bail(c3__fail);
+ }
+}
+
+static const M3Result
+_resume_callback(M3Result result_m3, IM3Runtime runtime)
+{
+ if (result_m3 == m3Err_ComputationBlock
+ || result_m3 == m3Err_SuspensionError)
+ {
+ return result_m3;
+ }
+ M3Result result = m3Err_none;
+ lia_state* sat_u = runtime->userdata_resume;
+ m3_SuspendStackPopExtTag(runtime);
+ c3_d tag_d;
+ m3_SuspendStackPop64(runtime, &tag_d);
+ switch (tag_d)
+ {
+ default:
+ {
+ u3m_bail(c3__fail);
+ }
+ case west_call:
+ {
+ c3_d f_idx_d;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &f_idx_d);
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (lst_call != u3h(frame))
+ {
+ printf(ERR("wrong frame: call"));
+ u3m_bail(c3__fail);
+ }
+ u3_noun name = u3t(frame);
+ c3_w met_w = u3r_met(3, name);
+ c3_c* name_c = u3a_malloc(met_w + 1);
+ u3r_bytes(0, met_w, (c3_y*)name_c, name);
+ u3z(frame);
+ name_c[met_w] = 0;
+
+ u3_noun yil;
+ if (_deterministic_trap(result_m3))
+ {
+ fprintf(stderr, WUT("%s call trapped: %s"), name_c, result_m3);
+ yil = u3nc(2, 0);
+ }
+ else if (result_m3)
+ {
+ fprintf(stderr, ERR("%s call failed: %s"), name_c, result_m3);
+ u3m_bail(c3__fail);
+ }
+ else
+ {
+ IM3Function f = runtime->modules->functions + f_idx_d;
+ c3_w n_out_w = f->funcType->numRets;
+ c3_d *vals_out = u3a_calloc(n_out_w, sizeof(c3_d));
+ void **valptrs_out = u3a_calloc(n_out_w, sizeof(void*));
+ for (c3_w i = 0; i < n_out_w; i++)
+ {
+ valptrs_out[i] = &vals_out[i];
+ }
+ M3Result result_tmp = m3_GetResults(f,
+ n_out_w,
+ (const void**)valptrs_out
+ );
+ if (result_tmp)
+ {
+ fprintf(stderr,
+ ERR("function %s failed to get results: %s"), name_c, result_tmp
+ );
+ u3m_bail(c3__fail);
+ }
+ yil = u3nc(0,
+ _atoms_from_stack(valptrs_out, n_out_w, f->funcType->types)
+ );
+ u3a_free(valptrs_out);
+ u3a_free(vals_out);
+ }
+ if (u3_none != sat_u->resolution)
+ {
+ u3m_bail(c3__fail);
+ }
+ sat_u->resolution = yil;
+ u3a_free(name_c);
+ break;
+ }
+
+ case west_call_ext:
+ {
+ if (1 == u3h(sat_u->resolution))
+ {
+ // it's a new block, it's not yet resolved
+ // restore the frame
+ //
+ m3_SuspendStackPush64(runtime, tag_d);
+ m3_SuspendStackPushExtTag(runtime);
+ result = m3Err_ComputationBlock;
+ }
+ // else the block is resolved and sat_u->resolution holds the result
+ //
+ break;
+ }
+
+ case west_try:
+ {
+ if (1 != u3h(sat_u->resolution))
+ {
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (lst_try != u3h(frame))
+ {
+ printf(ERR("wrong frame: try"));
+ u3m_bail(c3__fail);
+ }
+ if (0 == u3h(sat_u->resolution))
+ {
+ u3_noun cont = u3t(frame);
+ u3_noun p_res = u3t(sat_u->resolution);
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ u3_noun monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(p_res),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(sat_u->resolution);
+ sat_u->resolution = _reduce_monad(monad_cont, sat_u);
+ }
+ // if %2 then nothing to do, sat_u->resolution already holds %2 result
+ //
+ u3z(frame);
+ }
+ else
+ {
+ // we shouldn't be here
+ //
+ u3m_bail(c3__fail);
+ }
+ break;
+ }
+
+ case west_catch_try:
+ {
+ if (1 != u3h(sat_u->resolution))
+ {
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (lst_catch_try != u3h(frame))
+ {
+ printf(ERR("wrong frame: catch-try"));
+ u3m_bail(c3__fail);
+ }
+ if (0 == u3h(sat_u->resolution))
+ {
+ u3_noun cont = u3t(u3t(frame));
+ u3_noun p_res = u3t(sat_u->resolution);
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ u3_noun monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(p_res),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(sat_u->resolution);
+ sat_u->resolution = _reduce_monad(monad_cont, sat_u);
+ }
+ // %2
+ //
+ else
+ {
+ u3_noun cont = u3t(u3t(frame));
+ u3_noun monad_catch = u3h(u3t(frame));
+ { // push on suspend stacks
+ m3_SuspendStackPush64(sat_u->wasm_module->runtime, west_catch_err);
+ m3_SuspendStackPushExtTag(runtime);
+ _push_list(
+ u3nc(lst_catch_err, u3k(cont)),
+ &sat_u->susp_list
+ );
+ }
+
+ u3_noun yil = _reduce_monad(u3k(monad_catch), sat_u);
+
+ if (1 != u3h(yil))
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(sat_u->wasm_module->runtime, &tag);
+ if (tag != -1 && tag != west_catch_err)
+ {
+ printf(ERR("catch-err tag mismatch: %"PRIc3_d), tag);
+ u3m_bail(c3__fail);
+ }
+ u3_noun frame1 = _pop_list(&sat_u->susp_list);
+ if (lst_catch_err != u3h(frame1))
+ {
+ printf(ERR("wrong frame: catch-err"));
+ u3m_bail(c3__fail);
+ }
+ u3z(frame1);
+ }
+
+ if (2 == u3h(yil))
+ {
+ // sat_u->resolution already has %2, do nothing
+ u3z(yil);
+ }
+ else if (1 == u3h(yil))
+ {
+ u3z(sat_u->resolution);
+ sat_u->resolution = yil;
+ }
+ else // %0
+ {
+ u3_noun p_res = u3t(yil);
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ u3_noun monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(p_res),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(sat_u->resolution);
+ u3z(yil);
+ sat_u->resolution = _reduce_monad(monad_cont, sat_u);
+ }
+ }
+ u3z(frame);
+ }
+ else
+ {
+ // we shouldn't be here
+ //
+ u3m_bail(c3__fail);
+ }
+ break;
+ }
+ case west_catch_err:
+ {
+ if (1 != u3h(sat_u->resolution))
+ {
+ u3_noun frame = _pop_list(&sat_u->susp_list);
+ if (lst_catch_err != u3h(frame))
+ {
+ printf(ERR("wrong frame: catch-err"));
+ u3m_bail(c3__fail);
+ }
+ if (0 == u3h(sat_u->resolution))
+ {
+ u3_noun cont = u3t(frame);
+ u3_noun p_res = u3t(sat_u->resolution);
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ u3_noun monad_cont = uw_slam_check(
+ u3k(cont),
+ u3k(p_res),
+ sat_u->is_stateful
+ );
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3z(sat_u->resolution);
+ sat_u->resolution = _reduce_monad(monad_cont, sat_u);
+ }
+ // if %2 then nothing to do, sat_u->resolution already holds %2 result
+ //
+ u3z(frame);
+ }
+ else
+ {
+ // we shouldn't be here
+ //
+ u3m_bail(c3__fail);
+ }
+ break;
+ }
+ case west_link_wasm:
+ {
+ if (1 != u3h(sat_u->resolution))
+ {
+ c3_d _sp_offset_d, func_idx_d;
+ m3_SuspendStackPop64(runtime, &func_idx_d);
+ m3_SuspendStackPop64(runtime, &_sp_offset_d);
+ if (2 == u3h(sat_u->resolution))
+ {
+ u3z(sat_u->resolution);
+ sat_u->resolution = u3_none;
+ result = UrwasmArrowExit;
+ }
+ else // %0
+ {
+ IM3Function f = runtime->modules->functions + func_idx_d;
+ uint64_t * _sp = (uint64_t *)(runtime->base + _sp_offset_d);
+ c3_w n_out = f->funcType->numRets;
+ c3_y* types = f->funcType->types;
+ void **valptrs_out = u3a_calloc(n_out, sizeof(void*));
+ const char *mod = f->import.moduleUtf8;
+ const char *name = f->import.fieldUtf8;
+ for (c3_w i = 0; i < n_out; i++)
+ {
+ valptrs_out[i] = &_sp[i];
+ }
+ c3_o pushed = _coins_to_stack(
+ u3t(sat_u->resolution),
+ valptrs_out,
+ n_out,
+ types
+ );
+
+ if (c3n == pushed)
+ {
+ printf(ERR("import result type mismatch: %s/%s"), mod, name);
+ result = "import result type mismatch";
+ }
+
+ u3z(sat_u->resolution);
+ sat_u->resolution = u3_none;
+ u3a_free(valptrs_out);
+ }
+ }
+ else
+ {
+ // we shouldn't be here
+ //
+ u3m_bail(c3__fail);
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+// TRANSFERS sat->arrow_yil if m3Err_ComputationBlock is thrown
+static const void *
+_link_wasm_with_arrow_map(
+ IM3Runtime runtime,
+ IM3ImportContext _ctx,
+ uint64_t * _sp,
+ void * _mem
+)
+{
+ const char *mod = _ctx->function->import.moduleUtf8;
+ const char *name = _ctx->function->import.fieldUtf8;
+ lia_state* sat_u = _ctx->userdata;
+
+ u3_noun key = u3nc(u3i_string(mod), u3i_string(name));
+ u3_weak arrow = u3kdb_get(u3k(sat_u->map), key);
+ if (u3_none == arrow)
+ {
+ fprintf(stderr, ERR("import not found: %s/%s"), mod, name);
+ return m3Err_functionImportMissing;
+ }
+ c3_w n_in = _ctx->function->funcType->numArgs;
+ c3_w n_out = _ctx->function->funcType->numRets;
+ c3_y* types = _ctx->function->funcType->types;
+ void **valptrs_in = u3a_calloc(n_in, sizeof(void*));
+ for (c3_w i = 0; i < n_in; i++)
+ {
+ valptrs_in[i] = &_sp[i+n_out];
+ }
+ void **valptrs_out = u3a_calloc(n_out, sizeof(void*));
+ for (c3_w i = 0; i < n_out; i++)
+ {
+ valptrs_out[i] = &_sp[i];
+ }
+
+ u3_noun coin_wasm_list = _coins_from_stack(valptrs_in, n_in, (types+n_out));
+
+ { // push on suspend stacks
+ m3_SuspendStackPush64(runtime, (c3_d)((c3_y*)_sp - (c3_y*)runtime->base));
+ c3_d func_idx_d = _ctx->function - runtime->modules->functions;
+ m3_SuspendStackPush64(runtime, func_idx_d);
+ m3_SuspendStackPush64(runtime, west_link_wasm);
+ m3_SuspendStackPushExtTag(runtime);
+ }
+
+ uw_arena* box_arena_frame = BoxArena;
+ uw_arena* code_arena_frame = CodeArena;
+ u3_noun script = uw_slam_check(arrow, coin_wasm_list, sat_u->is_stateful);
+ BoxArena = box_arena_frame;
+ CodeArena = code_arena_frame;
+ u3_noun yil = _reduce_monad(script, sat_u);
+
+ M3Result result = m3Err_none;
+
+ if (1 != u3h(yil))
+ { // pop suspend stacks
+ m3_SuspendStackPopExtTag(runtime);
+ c3_d tag;
+ m3_SuspendStackPop64(runtime, &tag);
+ if (tag != -1 && tag != west_link_wasm)
+ {
+ printf(ERR("west_link tag mismatch: %"PRIc3_d), tag);
+ u3m_bail(c3__fail);
+ }
+ m3_SuspendStackPop64(runtime, NULL);
+ m3_SuspendStackPop64(runtime, NULL);
+
+ }
+
+ if (1 == u3h(yil))
+ {
+ if (sat_u->arrow_yil != u3_none)
+ {
+ u3z(yil);
+ result = "non-empty sat_u->arrow_yil on block";
+ }
+ else
+ {
+ sat_u->arrow_yil = yil;
+ result = m3Err_ComputationBlock; // start suspending if not yet suspending
+ }
+ }
+ else if (2 == u3h(yil))
+ {
+ u3z(yil);
+ result = UrwasmArrowExit;
+ }
+ else
+ {
+ c3_o pushed = _coins_to_stack(u3t(yil), valptrs_out, n_out, types);
+ u3z(yil);
+ if (c3n == pushed)
+ {
+ fprintf(stderr, ERR("import result type mismatch: %s/%s"), mod, name);
+ result = "import result type mismatch";
+ }
+ }
+ u3a_free(valptrs_in);
+ u3a_free(valptrs_out);
+ return result;
+}
+
+// key: [uw_run_m seed]
+// stored nouns:
+// $@ ~ :: tombstone value
+// $: yield=* :: +2
+// queue=(list script) :: +6
+// box_arena=[buffer=octs padding=@] :: [[+56 +57] +29]
+// memory=[buffer=octs max_stack_offset=@] :: [[+120 +121] +61]
+// runtime_offset=@ :: +62
+// lia_shop=(list) :: +126
+// acc=* :: +254
+// susp_list=(list) :: +255
+// ==
+// arguments RETAINED
+// on success allocates sat_u->wasm_module->runtime->memory.mallocated
+// and initializes the arenas
+static c3_t
+_get_state(u3_noun hint, u3_noun seed, lia_state* sat_u)
+{
+ // u3_weak get = u3z_find_m(u3z_memo_keep, uw_run_m, seed);
+ // XX order of search matters (sentinel value ~
+ // from previous invocation is closer to the home road)
+ // and u3z_find_m searches from home road down, which is the opposite
+ // of what we want
+ //
+ u3_noun key = u3z_key(uw_run_m, seed);
+ u3_weak get = u3z_find_up(key);
+ u3z(key);
+
+ if (u3_none == get || u3_nul == get)
+ {
+ return 0;
+ }
+ else
+ {
+ u3_noun yil_previous;
+ u3_noun queue;
+ u3_noun p_box_buffer, q_box_buffer, pad_box;
+ u3_noun p_mem_buffer, q_mem_buffer, stack_offset;
+ u3_noun runtime_offset;
+ u3_noun lia_shop;
+ u3_noun acc;
+ u3_noun susp_list;
+
+ if ( c3n == u3r_mean(get,
+ 2, &yil_previous,
+ 6, &queue,
+ 56, &p_box_buffer,
+ 57, &q_box_buffer,
+ 29, &pad_box,
+ 120, &p_mem_buffer,
+ 121, &q_mem_buffer,
+ 61, &stack_offset,
+ 62, &runtime_offset,
+ 126, &lia_shop,
+ 254, &acc,
+ 255, &susp_list,
+ 0)
+ )
+ {
+ return u3m_bail(c3__fail);
+ }
+ c3_w box_len_w = (c3y == u3a_is_cat(p_box_buffer))
+ ? p_box_buffer
+ : u3m_bail(c3__fail);
+
+ c3_w pad_w = (c3y == u3a_is_cat(pad_box))
+ ? pad_box
+ : u3m_bail(c3__fail);
+
+ c3_w run_off_w = (c3y == u3a_is_cat(runtime_offset))
+ ? runtime_offset
+ : u3m_bail(c3__fail);
+
+ c3_w len_buf_w = (c3y == u3a_is_cat(p_mem_buffer))
+ ? p_mem_buffer
+ : u3m_bail(c3__fail);
+
+ c3_w stk_off_w = (c3y == u3a_is_cat(stack_offset))
+ ? stack_offset
+ : u3m_bail(c3__fail);
+
+ _uw_arena_init_size(BoxArena, box_len_w);
+ u3r_bytes(pad_w, box_len_w, BoxArena->buf_y, q_box_buffer);
+ _uw_arena_init(CodeArena);
+
+ M3Result result;
+ IM3Runtime wasm3_runtime = (IM3Runtime)(BoxArena->buf_y + run_off_w);
+ wasm3_runtime->base = BoxArena->buf_y;
+ wasm3_runtime->base_transient = CodeArena->buf_y;
+ m3_RewritePointersRuntime(wasm3_runtime, BoxArena->buf_y, 0 /*is_store*/);
+ IM3Module wasm3_module = wasm3_runtime->modules;
+ c3_w n_imports = wasm3_module->numFuncImports;
+
+ // make sure to not touch BoxArena
+ m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail);
+ m3_SetTransientAllocators(_calloc_code, _free_code, _realloc_code);
+ m3_SetMemoryAllocators(_calloc_bail, _free_bail, _realloc_bail);
+
+ jmp_buf esc;
+ CodeArena->esc_u = &esc;
+ c3_i jmp_i;
+
+ while (1)
+ {
+ wasm3_runtime->base_transient = CodeArena->buf_y;
+
+ if (0 == (jmp_i = setjmp(esc)))
+ {
+ for (c3_w i = 0; i < n_imports; i++)
+ {
+ M3Function f = wasm3_module->functions[i];
+ const char* mod = f.import.moduleUtf8;
+ const char* name = f.import.fieldUtf8;
+
+ result = m3_LinkRawFunctionEx(
+ wasm3_module, mod, name,
+ NULL, &_link_wasm_with_arrow_map,
+ sat_u
+ );
+
+ if (result)
+ {
+ fprintf(stderr, ERR("link error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ }
+
+ result = m3_CompileModule(wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("compilation error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ break;
+ }
+ else
+ {
+ if (jmp_i == c3__code)
+ {
+ _uw_arena_grow(CodeArena);
+ }
+ else
+ {
+ return u3m_bail(c3__fail);
+ }
+ continue;
+ }
+ }
+
+ {
+ sat_u->yil_previous = u3k(yil_previous);
+ sat_u->queue = u3k(queue);
+ sat_u->wasm_module = wasm3_module;
+ sat_u->lia_shop = u3k(lia_shop);
+ sat_u->acc = u3k(acc);
+ // sat_u->map to be filled afterwards
+ // sat_u->match same
+ // sat_u->resolution same
+ sat_u->arrow_yil = u3_none;
+ sat_u->susp_list = u3k(susp_list);
+ M3MemoryHeader* mem = u3a_malloc(len_buf_w + sizeof(M3MemoryHeader));
+ mem->runtime = wasm3_runtime;
+ mem->maxStack = BoxArena->buf_y + stk_off_w;
+ mem->length = len_buf_w;
+ u3r_bytes(0, len_buf_w, (u8*)(mem + 1), q_mem_buffer);
+ wasm3_runtime->memory.mallocated = mem;
+ }
+
+ u3z(get);
+
+ return 1;
+ }
+}
+
+// arguments RETAINED, returned yield transfered.
+// transfers sat_u->yil_previous if it is returned, and replaces
+// the struct value with u3_none
+static u3_noun
+_apply_diff(u3_noun input_tag, u3_noun p_input, lia_state* sat_u)
+{
+ m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail);
+ m3_SetTransientAllocators(_calloc_bail, _free_bail, _realloc_bail);
+ m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc);
+
+ if (input_tag == c3y)
+ {
+ if (sat_u->wasm_module->runtime->edge_suspend)
+ {
+ // appended new script but the computation is still suspended:
+ // add script to queue, return previous yield
+ if (sat_u->yil_previous == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ sat_u->queue = u3kb_weld(sat_u->queue, u3nc(u3k(p_input), u3_nul)); // snoc
+ u3_noun yil = sat_u->yil_previous;
+ sat_u->yil_previous = u3_none;
+ return yil;
+ }
+ else
+ {
+ return _reduce_monad(u3k(p_input), sat_u);
+ }
+ }
+ else
+ {
+ if (!sat_u->wasm_module->runtime->edge_suspend)
+ {
+ // appended external call resolution but no block to resolve:
+ // snoc result to shop, return previous yield
+ if (sat_u->yil_previous == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ sat_u->lia_shop = u3kb_weld(sat_u->lia_shop, u3nc(u3k(p_input), u3_nul)); // snoc
+ u3_noun yil = sat_u->yil_previous;
+ sat_u->yil_previous = u3_none;
+ return yil;
+ }
+ // else resume
+ IM3Runtime run_u = sat_u->wasm_module->runtime;
+ run_u->resume_external = _resume_callback;
+ run_u->userdata_resume = sat_u;
+ if (sat_u->resolution != u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ sat_u->resolution = u3nc(0, u3k(p_input));
+ M3Result result = m3_Resume(run_u);
+ u3_noun yil;
+ if (result == m3Err_ComputationBlock)
+ {
+ yil = sat_u->resolution;
+ sat_u->resolution = u3_none;
+ if (yil == u3_none)
+ {
+ yil = sat_u->arrow_yil;
+ sat_u->arrow_yil = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ }
+ else if (_deterministic_trap(result))
+ {
+ fprintf(stderr, WUT("function call trapped: %s"), result); // XX get name of entry function?
+ yil = u3nc(2, 0);
+ }
+ else if (result == m3Err_functionImportMissing)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else if (result)
+ {
+ fprintf(stderr, ERR("resumption failed: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ else
+ {
+ yil = sat_u->resolution;
+ sat_u->resolution = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ if (sat_u->queue != u3_none)
+ {
+ while (u3h(yil) == 0 && sat_u->queue != u3_nul)
+ {
+ u3z(yil);
+ u3_noun deferred_script = _pop_list(&sat_u->queue);
+ yil = _reduce_monad(deferred_script, sat_u);
+ }
+ }
+ }
+
+ return yil;
+ }
+}
+
+// try to save new state, replacing old state with a tombstone value
+// frees wasm3 memory buffer, releases arenas
+// RETAINS arguments, transfers sat_u->lia_shop/susp_list/queue and
+// replaces them with u3_none if save is succesful
+static void
+_move_state(
+ lia_state* sat_u,
+ u3_noun seed_old,
+ u3_noun seed_new,
+ u3_noun hint,
+ u3_noun yil)
+{
+ if ( (c3__oust == hint)
+ || (2 == u3h(yil))
+ || (c3__rand == hint && 0 == u3h(yil))
+ )
+ {
+ u3z_save_m(u3z_memo_keep, uw_run_m, seed_old, u3_nul);
+ IM3Runtime run_u = sat_u->wasm_module->runtime;
+ M3MemoryHeader* mem_u = run_u->memory.mallocated;
+ u3a_free(mem_u);
+ _uw_arena_free(CodeArena);
+ _uw_arena_free(BoxArena);
+ return;
+ }
+
+ IM3Runtime run_u = sat_u->wasm_module->runtime;
+ M3MemoryHeader* mem_u = run_u->memory.mallocated;
+ c3_w stk_off_w = (u8*)mem_u->maxStack - BoxArena->buf_y;
+ if (c3n == u3a_is_cat(stk_off_w))
+ {
+ u3m_bail(c3__fail);
+ }
+
+ c3_w len_buf_w = mem_u->length;
+ if (c3n == u3a_is_cat(len_buf_w))
+ {
+ u3m_bail(c3__fail);
+ }
+
+ u3_atom q_buf = u3i_bytes(len_buf_w, (c3_y*)(mem_u + 1));
+
+ u3a_free(mem_u);
+
+ m3_RewritePointersRuntime(run_u, BoxArena->buf_y, 1 /*is_store*/);
+ c3_w run_off_w = (c3_y*)run_u - BoxArena->buf_y;
+ if (c3n == u3a_is_cat(run_off_w))
+ {
+ u3m_bail(c3__fail);
+ }
+
+ _uw_arena_free(CodeArena);
+
+ c3_w box_len_w = BoxArena->siz_w;
+ if (c3n == u3a_is_cat(box_len_w))
+ {
+ u3m_bail(c3__fail);
+ }
+
+ c3_y pad_y = BoxArena->pad_y;
+
+ u3_atom q_box = u3i_slab_mint(&BoxArena->sab_u);
+ BoxArena->ini_t = 0;
+
+ u3_noun stash = uw_octo(
+ u3k(yil),
+ sat_u->queue,
+ u3nc(u3nc(box_len_w, q_box), pad_y),
+ u3nc(u3nc(len_buf_w, q_buf), stk_off_w),
+ run_off_w,
+ sat_u->lia_shop,
+ u3k(sat_u->acc), // accumulator will be returned
+ sat_u->susp_list
+ );
+ sat_u->lia_shop = u3_none;
+ sat_u->susp_list = u3_none;
+ sat_u->queue = u3_none;
+
+ u3z_save_m(u3z_memo_keep, uw_run_m, seed_old, u3_nul);
+
+ u3z_save_m(u3z_memo_keep, uw_run_m, seed_new, stash);
+
+ u3z(stash);
+}
+
+u3_weak
+u3we_lia_run_v1(u3_noun cor)
+{
+#ifndef URWASM_STATEFUL
+ return u3_none;
+#else
+
+ u3_noun hint = u3at(u3x_sam_7, cor);
+ if (c3__none == hint)
+ {
+ return u3_none;
+ }
+
+ // strand: save %1, delete in other cases
+ c3_t rand_t = (c3__rand == hint);
+
+ // agent: always save
+ c3_t gent_t = (c3__gent == hint);
+
+ // oust: don't save
+ c3_t oust_t = (c3__oust == hint);
+
+ // omit: run statelessly
+ c3_t omit_t = !(rand_t || gent_t || oust_t);
+
+ #ifdef URWASM_SUBROAD
+
+ // enter subroad, 4MB safety buffer
+ u3m_hate(1 << 20);
+
+ #endif
+
+ u3_noun ctx = u3at(RUN_CTX, cor);
+ u3r_mug(ctx);
+
+ u3_noun input = u3at(u3x_sam_2, cor);
+ u3_noun seed = u3at(u3x_sam_6, cor);
+
+ u3_noun runnable = uw_kick_nock(u3k(ctx), AX_RUNNABLE);
+ u3_noun arrows = KICK1(uw_kick_nock(u3k(ctx), AX_ARROWS));
+
+ u3_noun try_gate = uw_kick_nock(u3k(runnable), AX_TRY);
+ u3_noun try_gate_inner = KICK1(try_gate);
+
+ u3_noun seed_new;
+ u3_noun input_tag, p_input;
+ u3x_cell(input, &input_tag, &p_input);
+
+ if (input_tag == c3y)
+ {
+ u3_noun p_input_gate = u3nt(u3nc(0, 7), 0, u3k(p_input)); // =>(p.input |=(* +>))
+ u3_noun past_new = uw_slam_nock(
+ u3k(try_gate_inner),
+ u3nc(
+ u3k(u3at(seed_past, seed)),
+ p_input_gate
+ )
+ );
+ seed_new = u3nq(
+ u3k(u3at(seed_module, seed)),
+ past_new,
+ u3k(u3at(seed_shop, seed)),
+ u3k(u3at(seed_import, seed))
+ );
+ }
+ else if (input_tag == c3n)
+ {
+ seed_new = u3nq(
+ u3k(u3at(seed_module, seed)),
+ u3k(u3at(seed_past, seed)),
+ u3nc(u3k(p_input), u3k(u3at(seed_shop, seed))),
+ u3k(u3at(seed_import, seed))
+ );
+ }
+ else
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ u3_noun call_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL));
+ u3_noun memread_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMREAD));
+ u3_noun memwrite_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMWRITE));
+ u3_noun call_ext_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL_EXT));
+ u3_noun global_set_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_SET));
+ u3_noun global_get_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_GET));
+ u3_noun mem_grow_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEM_GROW));
+ u3_noun mem_size_script = uw_kick_nock(u3k(arrows), AX_MEM_SIZE);
+ u3_noun get_acc_script = uw_kick_nock(u3k(arrows), AX_GET_ACC);
+ u3_noun set_acc_script = KICK1(uw_kick_nock(u3k(arrows), AX_SET_ACC));
+ u3_noun get_all_glob_script = uw_kick_nock(u3k(arrows), AX_GET_ALL_GLOB);
+ u3_noun set_all_glob_script = KICK1(uw_kick_nock( arrows, AX_SET_ALL_GLOB));
+
+ u3_noun try_script = KICK1(try_gate_inner);
+ u3_noun catch_script = KICK2(uw_kick_nock(u3k(runnable), AX_CATCH));
+ u3_noun return_script = KICK1(uw_kick_nock(u3k(runnable), AX_RETURN));
+ u3_noun fail_script = uw_kick_nock( runnable, AX_FAIL);
+
+ u3_noun call_bat = u3k(u3h(call_script));
+ u3_noun memread_bat = u3k(u3h(memread_script));
+ u3_noun memwrite_bat = u3k(u3h(memwrite_script));
+ u3_noun call_ext_bat = u3k(u3h(call_ext_script));
+ u3_noun try_bat = u3k(u3h(try_script));
+ u3_noun catch_bat = u3k(u3h(catch_script));
+ u3_noun return_bat = u3k(u3h(return_script));
+ u3_noun fail_bat = u3k(u3h(fail_script));
+ u3_noun global_set_bat = u3k(u3h(global_set_script));
+ u3_noun global_get_bat = u3k(u3h(global_get_script));
+ u3_noun mem_grow_bat = u3k(u3h(mem_grow_script));
+ u3_noun mem_size_bat = u3k(u3h(mem_size_script));
+ u3_noun get_acc_bat = u3k(u3h(get_acc_script));
+ u3_noun set_acc_bat = u3k(u3h(set_acc_script));
+ u3_noun get_all_glob_bat = u3k(u3h(get_all_glob_script));
+ u3_noun set_all_glob_bat = u3k(u3h(set_all_glob_script));
+
+ u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script));
+ u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script));
+ u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script));
+ u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script));
+ u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script));
+ u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script));
+ u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_size_script));
+ u3_noun get_all_glob_ctx = u3k(u3at(MONAD_CTX, get_all_glob_script));
+ u3_noun set_all_glob_ctx = u3k(u3at(ARROW_CTX, set_all_glob_script));
+
+ u3z(call_script);
+ u3z(memread_script);
+ u3z(memwrite_script);
+ u3z(call_ext_script);
+ u3z(try_script);
+ u3z(catch_script);
+ u3z(return_script);
+ u3z(fail_script);
+ u3z(global_set_script);
+ u3z(global_get_script);
+ u3z(mem_grow_script);
+ u3z(mem_size_script);
+ u3z(get_acc_script);
+ u3z(set_acc_script);
+ u3z(get_all_glob_script);
+ u3z(set_all_glob_script);
+
+ match_data_struct match = {
+ call_bat,
+ memread_bat,
+ memwrite_bat,
+ call_ext_bat,
+ try_bat,
+ catch_bat,
+ return_bat,
+ fail_bat,
+ global_set_bat,
+ global_get_bat,
+ mem_grow_bat,
+ mem_size_bat,
+ get_acc_bat,
+ set_acc_bat,
+ get_all_glob_bat,
+ set_all_glob_bat,
+ //
+ call_ctx,
+ memread_ctx,
+ memwrite_ctx,
+ global_set_ctx,
+ global_get_ctx,
+ mem_grow_ctx,
+ mem_size_ctx,
+ get_all_glob_ctx,
+ set_all_glob_ctx,
+ };
+
+ lia_state sat;
+
+ BoxArena = &sat.box_arena;
+ CodeArena = &sat.code_arena;
+
+ u3_noun yil;
+ if (!omit_t)
+ {
+ sat.is_stateful = 1;
+ if (_get_state(hint, seed, &sat))
+ {
+ sat.map = u3t(u3at(seed_import, seed));
+ sat.match = &match;
+ sat.resolution = u3_none;
+ yil = _apply_diff(input_tag, p_input, &sat);
+ }
+ else
+ { // instantiate state with retries
+ u3_noun octs = u3at(seed_module, seed_new);
+ u3_noun p_octs, q_octs;
+ u3x_cell(octs, &p_octs, &q_octs);
+ c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs
+ : u3m_bail(c3__fail);
+ c3_y* bin_y;
+ M3Result result;
+ IM3Environment wasm3_env;
+ IM3Runtime wasm3_runtime = NULL;
+ IM3Module wasm3_module;
+
+ _uw_arena_init(CodeArena);
+ _uw_arena_init(BoxArena);
+
+ m3_SetAllocators(_calloc_box, _free_box, _realloc_box);
+ m3_SetTransientAllocators(_calloc_code, _free_code, _realloc_code);
+ m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc);
+ jmp_buf esc;
+ CodeArena->esc_u = BoxArena->esc_u = &esc;
+ c3_i jmp_i;
+
+ while (1)
+ {
+ if (0 == (jmp_i = setjmp(esc)))
+ {
+ bin_y = _calloc_box(bin_len_w, 1);
+ u3r_bytes(0, bin_len_w, bin_y, u3x_atom(q_octs));
+
+ wasm3_env = m3_NewEnvironment();
+ if (!wasm3_env)
+ {
+ fprintf(stderr, ERR("env is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ wasm3_runtime = m3_NewRuntime(
+ wasm3_env,
+ 1 << 21,
+ NULL,
+ 1 /* suspend */
+ );
+ if (!wasm3_runtime)
+ {
+ fprintf(stderr, ERR("runtime is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w);
+ if (result)
+ {
+ fprintf(stderr, ERR("parse binary error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_LoadModule(wasm3_runtime, wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("load module error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_ValidateModule(wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("validation error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w n_imports = wasm3_module->numFuncImports;
+ u3_noun lia_shop = u3at(seed_shop, seed_new);
+ u3_noun import = u3at(seed_import, seed_new);
+
+ u3_noun acc, map;
+ u3x_cell(import, &acc, &map);
+ {
+ sat.yil_previous = u3_none;
+ sat.queue = u3_nul;
+ sat.wasm_module = wasm3_module;
+ sat.lia_shop = u3qb_flop(lia_shop);
+ sat.acc = u3k(acc);
+ sat.map = map;
+ sat.match = &match;
+ sat.arrow_yil = u3_none;
+ sat.susp_list = u3_nul;
+ sat.resolution = u3_none;
+ }
+
+ for (c3_w i = 0; i < n_imports; i++)
+ {
+ M3Function f = wasm3_module->functions[i];
+ const char* mod = f.import.moduleUtf8;
+ const char* name = f.import.fieldUtf8;
+
+ result = m3_LinkRawFunctionEx(
+ wasm3_module, mod, name,
+ NULL, &_link_wasm_with_arrow_map,
+ &sat
+ );
+
+ if (result)
+ {
+ fprintf(stderr, ERR("link error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ }
+
+ result = m3_CompileModule(wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("compilation error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ break;
+ }
+ else
+ {
+ // escaped, grow arena and retry
+ if (wasm3_runtime)
+ {
+ u3a_free(wasm3_runtime->memory.mallocated);
+ }
+
+ if (jmp_i == c3__box)
+ {
+ _uw_arena_grow(BoxArena);
+ _uw_arena_reset(CodeArena);
+ }
+ else if (jmp_i == c3__code)
+ {
+ _uw_arena_grow(CodeArena);
+ _uw_arena_reset(BoxArena);
+ }
+ else
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ continue;
+ }
+ }
+
+ wasm3_runtime->base = BoxArena->buf_y;
+ wasm3_runtime->base_transient = CodeArena->buf_y;
+ // sanity check: struct and code allocators should not be used
+ // when running wasm
+ m3_SetAllocators(_calloc_bail, _free_bail, _realloc_bail);
+ m3_SetTransientAllocators(_calloc_bail, _free_bail, _realloc_bail);
+
+ result = m3_RunStart(wasm3_module);
+
+ if (result == m3Err_ComputationBlock)
+ {
+ yil = sat.arrow_yil;
+ sat.arrow_yil = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ else if (_deterministic_trap(result))
+ {
+ fprintf(stderr, WUT("start function call trapped: %s"), result);
+ yil = u3nc(2, 0);
+ }
+ else if (result == m3Err_functionImportMissing)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else if (result)
+ {
+ fprintf(stderr, ERR("start function failed: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ else
+ {
+ u3_noun monad = u3at(seed_past, seed_new);
+ yil = _reduce_monad(u3k(monad), &sat);
+ }
+ }
+
+ _move_state(&sat, seed, seed_new, hint, yil);
+ }
+ else
+ {
+ sat.is_stateful = 0;
+ M3Result result;
+ IM3Environment wasm3_env;
+ IM3Runtime wasm3_runtime = NULL;
+ IM3Module wasm3_module;
+ u3_noun p_octs, q_octs;
+
+ u3_noun octs = u3at(seed_module, seed_new);
+ u3x_cell(octs, &p_octs, &q_octs);
+ c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs
+ : u3m_bail(c3__fail);
+ c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs));
+
+ m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc);
+ m3_SetTransientAllocators(u3a_calloc, u3a_free, u3a_realloc);
+ m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc);
+
+ wasm3_env = m3_NewEnvironment();
+ if (!wasm3_env)
+ {
+ fprintf(stderr, ERR("env is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ // 2MB stack
+ wasm3_runtime = m3_NewRuntime(wasm3_env, 1 << 21, NULL, 0 /* suspend */);
+ if (!wasm3_runtime)
+ {
+ fprintf(stderr, ERR("runtime is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ // save the stack to restore it later before calling m3_FreeRuntime
+ // since it is allocated and freed seperately; no need to do it in
+ // stateful code branch since there we will allocate and free
+ // whole arena
+
+ void* stk_u = wasm3_runtime->stack;
+
+ result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w);
+ if (result)
+ {
+ fprintf(stderr, ERR("parse binary error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_LoadModule(wasm3_runtime, wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("load module error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_ValidateModule(wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("validation error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w n_imports = wasm3_module->numFuncImports;
+ u3_noun lia_shop = u3at(seed_shop, seed_new);
+ u3_noun import = u3at(seed_import, seed_new);
+
+ u3_noun acc, map;
+ u3x_cell(import, &acc, &map);
+ {
+ sat.yil_previous = u3_none;
+ sat.queue = u3_none;
+ sat.wasm_module = wasm3_module;
+ sat.lia_shop = u3qb_flop(lia_shop);
+ sat.acc = u3k(acc);
+ sat.map = map;
+ sat.match = &match;
+ sat.arrow_yil = u3_none;
+ sat.susp_list = u3_none;
+ sat.resolution = u3_none;
+ }
+
+ for (c3_w i = 0; i < n_imports; i++)
+ {
+ M3Function f = wasm3_module->functions[i];
+ const char* mod = f.import.moduleUtf8;
+ const char* name = f.import.fieldUtf8;
+
+ result = m3_LinkRawFunctionEx(
+ wasm3_module, mod, name,
+ NULL, &_link_wasm_with_arrow_map,
+ &sat
+ );
+
+ if (result)
+ {
+ fprintf(stderr, ERR("link error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ }
+
+ // don't compile module since here we don't care about the ordering
+ // of code pages when we don't suspend, the functions will
+ // get compiled on call
+ //
+
+ result = m3_RunStart(wasm3_module);
+
+ if (result == m3Err_ComputationBlock)
+ {
+ yil = sat.arrow_yil;
+ sat.arrow_yil = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ else if (_deterministic_trap(result))
+ {
+ fprintf(stderr, WUT("start function call trapped: %s"), result);
+ yil = u3nc(2, 0);
+ }
+ else if (result == m3Err_functionImportMissing)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else if (result)
+ {
+ fprintf(stderr, ERR("start function failed: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ else
+ {
+ u3_noun monad = u3at(seed_past, seed_new);
+ yil = _reduce_monad(u3k(monad), &sat);
+ }
+
+ wasm3_runtime->stack = stk_u;
+ m3_FreeRuntime(wasm3_runtime);
+ m3_FreeEnvironment(wasm3_env);
+ u3a_free(bin_y);
+ }
+
+ // any of these could be u3_none
+ //
+ {
+ u3z(sat.lia_shop);
+ u3z(sat.susp_list);
+ u3z(sat.yil_previous);
+ u3z(sat.queue);
+ }
+
+ u3z(match.call_bat);
+ u3z(match.memread_bat);
+ u3z(match.memwrite_bat);
+ u3z(match.call_ext_bat);
+ u3z(match.try_bat);
+ u3z(match.catch_bat);
+ u3z(match.return_bat);
+ u3z(match.fail_bat);
+ u3z(match.global_set_bat);
+ u3z(match.global_get_bat);
+ u3z(match.mem_grow_bat);
+ u3z(match.mem_size_bat);
+
+ u3z(match.call_ctx);
+ u3z(match.memread_ctx);
+ u3z(match.memwrite_ctx);
+ u3z(global_set_ctx);
+ u3z(global_get_ctx);
+ u3z(mem_grow_ctx);
+ u3z(mem_size_ctx);
+
+ #ifdef URWASM_SUBROAD
+ // exit subroad, copying the result
+ u3_noun pro = u3m_love(u3nc(u3nc(yil, sat.acc), seed_new));
+ #else
+ u3_noun pro = u3nc(u3nc(yil, sat.acc), seed_new);
+ #endif
+
+ return pro;
+
+#endif // URWASM_STATEFUL
+}
+
+
+u3_weak
+u3we_lia_run_once(u3_noun cor)
+{
+ if (c3__none == u3at(u3x_sam_6, cor))
+ {
+ return u3_none;
+ }
+
+ #ifdef URWASM_SUBROAD
+ // enter subroad, 4MB safety buffer
+ u3m_hate(1 << 20);
+ #endif
+
+ u3_noun ctx = u3at(ONCE_CTX, cor);
+ u3r_mug(ctx);
+
+ u3_noun runnable = uw_kick_nock(u3k(ctx), AX_RUNNABLE);
+ u3_noun arrows = KICK1(uw_kick_nock(u3k(ctx), AX_ARROWS));
+
+ u3_noun call_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL));
+ u3_noun memread_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMREAD));
+ u3_noun memwrite_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEMWRITE));
+ u3_noun call_ext_script = KICK1(uw_kick_nock(u3k(arrows), AX_CALL_EXT));
+ u3_noun global_set_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_SET));
+ u3_noun global_get_script = KICK1(uw_kick_nock(u3k(arrows), AX_GLOBAL_GET));
+ u3_noun mem_grow_script = KICK1(uw_kick_nock(u3k(arrows), AX_MEM_GROW));
+ u3_noun mem_size_script = uw_kick_nock(u3k(arrows), AX_MEM_SIZE);
+ u3_noun get_acc_script = uw_kick_nock(u3k(arrows), AX_GET_ACC);
+ u3_noun set_acc_script = KICK1(uw_kick_nock(u3k(arrows), AX_SET_ACC));
+ u3_noun get_all_glob_script = uw_kick_nock(u3k(arrows), AX_GET_ALL_GLOB);
+ u3_noun set_all_glob_script = KICK1(uw_kick_nock( arrows, AX_SET_ALL_GLOB));
+
+ u3_noun try_script = KICK2(uw_kick_nock(u3k(runnable), AX_TRY));
+ u3_noun catch_script = KICK2(uw_kick_nock(u3k(runnable), AX_CATCH));
+ u3_noun return_script = KICK1(uw_kick_nock(u3k(runnable), AX_RETURN));
+ u3_noun fail_script = uw_kick_nock( runnable, AX_FAIL);
+
+ u3_noun call_bat = u3k(u3h(call_script));
+ u3_noun memread_bat = u3k(u3h(memread_script));
+ u3_noun memwrite_bat = u3k(u3h(memwrite_script));
+ u3_noun call_ext_bat = u3k(u3h(call_ext_script));
+ u3_noun try_bat = u3k(u3h(try_script));
+ u3_noun catch_bat = u3k(u3h(catch_script));
+ u3_noun return_bat = u3k(u3h(return_script));
+ u3_noun fail_bat = u3k(u3h(fail_script));
+ u3_noun global_set_bat = u3k(u3h(global_set_script));
+ u3_noun global_get_bat = u3k(u3h(global_get_script));
+ u3_noun mem_grow_bat = u3k(u3h(mem_grow_script));
+ u3_noun mem_size_bat = u3k(u3h(mem_size_script));
+ u3_noun get_acc_bat = u3k(u3h(get_acc_script));
+ u3_noun set_acc_bat = u3k(u3h(set_acc_script));
+ u3_noun get_all_glob_bat = u3k(u3h(get_all_glob_script));
+ u3_noun set_all_glob_bat = u3k(u3h(set_all_glob_script));
+
+ u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script));
+ u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script));
+ u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script));
+ u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script));
+ u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script));
+ u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script));
+ u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_size_script));
+ u3_noun get_all_glob_ctx = u3k(u3at(MONAD_CTX, get_all_glob_script));
+ u3_noun set_all_glob_ctx = u3k(u3at(ARROW_CTX, set_all_glob_script));
+
+ u3z(call_script);
+ u3z(memread_script);
+ u3z(memwrite_script);
+ u3z(call_ext_script);
+ u3z(try_script);
+ u3z(catch_script);
+ u3z(return_script);
+ u3z(fail_script);
+ u3z(global_set_script);
+ u3z(global_get_script);
+ u3z(mem_grow_script);
+ u3z(mem_size_script);
+ u3z(get_acc_script);
+ u3z(set_acc_script);
+ u3z(get_all_glob_script);
+ u3z(set_all_glob_script);
+
+
+ match_data_struct match = {
+ call_bat,
+ memread_bat,
+ memwrite_bat,
+ call_ext_bat,
+ try_bat,
+ catch_bat,
+ return_bat,
+ fail_bat,
+ global_set_bat,
+ global_get_bat,
+ mem_grow_bat,
+ mem_size_bat,
+ get_acc_bat,
+ set_acc_bat,
+ get_all_glob_bat,
+ set_all_glob_bat,
+ //
+ call_ctx,
+ memread_ctx,
+ memwrite_ctx,
+ global_set_ctx,
+ global_get_ctx,
+ mem_grow_ctx,
+ mem_size_ctx,
+ get_all_glob_ctx,
+ set_all_glob_ctx,
+ };
+
+ u3_noun octs = u3at(u3x_sam_4, cor);
+ u3_noun p_octs, q_octs;
+ u3x_cell(octs, &p_octs, &q_octs);
+
+ c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs : u3m_bail(c3__fail);
+ c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs));
+
+ M3Result result;
+
+ m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc);
+ m3_SetTransientAllocators(u3a_calloc, u3a_free, u3a_realloc);
+ m3_SetMemoryAllocators(u3a_calloc, u3a_free, u3a_realloc);
+
+ IM3Environment wasm3_env = m3_NewEnvironment();
+ if (!wasm3_env)
+ {
+ fprintf(stderr, ERR("env is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ // 2MB stack
+ IM3Runtime wasm3_runtime = m3_NewRuntime(
+ wasm3_env,
+ 1 << 21,
+ NULL,
+ 0 /* suspend */
+ );
+ if (!wasm3_runtime)
+ {
+ fprintf(stderr, ERR("runtime is null"));
+ return u3m_bail(c3__fail);
+ }
+
+ void* stk_u = wasm3_runtime->stack;
+
+ IM3Module wasm3_module;
+ result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w);
+ if (result)
+ {
+ fprintf(stderr, ERR("parse binary error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_LoadModule(wasm3_runtime, wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("load module error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ result = m3_ValidateModule(wasm3_module);
+ if (result)
+ {
+ fprintf(stderr, ERR("validation error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+
+ c3_w n_imports = wasm3_module->numFuncImports;
+ u3_noun monad = u3at(u3x_sam_7, cor);
+ u3_noun import = u3at(u3x_sam_5, cor);
+
+ u3_noun acc, map;
+ u3x_cell(import, &acc, &map);
+
+ lia_state sat = {
+ wasm3_module,
+ u3_nul,
+ u3k(acc),
+ map,
+ &match,
+ u3_none,
+ u3_none,
+ u3_none
+ };
+
+ sat.is_stateful = 0;
+
+ for (c3_w i = 0; i < n_imports; i++)
+ {
+ M3Function f = wasm3_module->functions[i];
+ const char * mod = f.import.moduleUtf8;
+ const char * name = f.import.fieldUtf8;
+
+ result = m3_LinkRawFunctionEx(
+ wasm3_module, mod, name,
+ NULL, &_link_wasm_with_arrow_map,
+ (void *)&sat
+ );
+
+ if (result)
+ {
+ fprintf(stderr, ERR("link error: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ }
+
+ u3_noun yil;
+
+ result = m3_RunStart(wasm3_module);
+
+ if (result == m3Err_ComputationBlock)
+ {
+ yil = sat.arrow_yil;
+ sat.arrow_yil = u3_none;
+ if (yil == u3_none)
+ {
+ return u3m_bail(c3__fail);
+ }
+ }
+ else if (_deterministic_trap(result))
+ {
+ fprintf(stderr, WUT("start function call trapped: %s"), result);
+ yil = u3nc(2, 0);
+ }
+ else if (result == m3Err_functionImportMissing)
+ {
+ return u3m_bail(c3__exit);
+ }
+ else if (result)
+ {
+ fprintf(stderr, ERR("start function failed: %s"), result);
+ return u3m_bail(c3__fail);
+ }
+ else
+ {
+ yil = _reduce_monad(u3k(monad), &sat);
+ }
+
+ wasm3_runtime->stack = stk_u;
+ m3_FreeRuntime(wasm3_runtime);
+ m3_FreeEnvironment(wasm3_env);
+
+ u3a_free(bin_y);
+
+ u3z(match.call_bat);
+ u3z(match.memread_bat);
+ u3z(match.memwrite_bat);
+ u3z(match.call_ext_bat);
+ u3z(match.try_bat);
+ u3z(match.catch_bat);
+ u3z(match.return_bat);
+ u3z(match.fail_bat);
+ u3z(match.global_set_bat);
+ u3z(match.global_get_bat);
+ u3z(match.mem_grow_bat);
+ u3z(match.mem_size_bat);
+ u3z(match.get_acc_bat);
+ u3z(match.set_acc_bat);
+ u3z(match.get_all_glob_bat);
+ u3z(match.set_all_glob_bat);
+
+ u3z(match.call_ctx);
+ u3z(match.memread_ctx);
+ u3z(match.memwrite_ctx);
+ u3z(global_set_ctx);
+ u3z(global_get_ctx);
+ u3z(mem_grow_ctx);
+ u3z(mem_size_ctx);
+ u3z(get_all_glob_ctx);
+ u3z(set_all_glob_ctx);
+
+ #ifdef URWASM_SUBROAD
+ // exit subroad, copying the result
+ u3_noun pro = u3m_love(u3nc(yil, sat.acc));
+ #else
+ u3_noun pro = u3nc(yil, sat.acc);
+ #endif
+
+ return pro;
+}
diff --git a/vere/pkg/noun/jets/e/zlib.c b/vere/pkg/noun/jets/e/zlib.c
new file mode 100644
index 0000000..89937df
--- /dev/null
+++ b/vere/pkg/noun/jets/e/zlib.c
@@ -0,0 +1,225 @@
+/// @file
+
+#include <allocate.h>
+#include <stdio.h>
+#include "zlib.h"
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static void*
+zlib_malloc(voidpf opaque, uInt items, uInt size)
+{
+ size_t len = items * size;
+ void* result = u3a_malloc(len);
+ return result;
+}
+
+static void
+zlib_free(voidpf opaque, voidpf address)
+{
+ u3a_free(address);
+}
+
+u3_noun
+_decompress(u3_atom pos, u3_noun octs, int window_bits)
+{
+ u3_atom p_octs = u3h(octs);
+ u3_atom q_octs = u3t(octs);
+
+ c3_w p_octs_w, pos_w;
+
+ if ( c3n == u3r_safe_word(p_octs, &p_octs_w) ) {
+ return u3_none;
+ }
+ if (c3n == u3r_safe_word(pos, &pos_w)) {
+ return u3_none;
+ }
+
+ c3_w len_w = u3r_met(3, q_octs);
+
+ int leading_zeros = 0;
+
+ if (p_octs_w > len_w) {
+ leading_zeros = p_octs_w - len_w;
+ }
+ else {
+ len_w = p_octs_w;
+ }
+
+ // Bytestream exhausted
+ //
+ if (pos_w >= len_w) {
+ return u3_none;
+ }
+
+ c3_y* input;
+
+ if (c3y == u3a_is_cat(q_octs)) {
+ input = (c3_y*)&q_octs + pos_w;
+ }
+ else {
+ u3a_atom* vat_u = u3a_to_ptr(q_octs);
+ input = (c3_y*)vat_u->buf_w + pos_w;
+ }
+
+ int ret;
+ z_stream strm;
+
+ if (pos_w < len_w) {
+ strm.avail_in = (len_w - pos_w);
+ }
+ else {
+ strm.avail_in = 0;
+ }
+
+ strm.zalloc = zlib_malloc;
+ strm.zfree = zlib_free;
+ strm.opaque = Z_NULL;
+ strm.next_in = input;
+
+ ret = inflateInit2(&strm, window_bits);
+
+ if (ret != Z_OK) {
+ u3l_log("%i", ret);
+ u3l_log("%s", strm.msg);
+ return u3m_bail(c3__exit);
+ }
+
+ c3_w chunk_w = len_w / 10;
+ u3i_slab sab_u;
+
+#define INIT_SZ 16384
+ strm.avail_out = INIT_SZ;
+ u3i_slab_init(&sab_u, 3, INIT_SZ);
+ strm.next_out = sab_u.buf_y;
+
+ void* this_address = strm.next_out;
+
+#define ZEROS_SZ 256
+ c3_y zeros[ZEROS_SZ];
+
+ if (leading_zeros) {
+ memset(zeros, 0, ZEROS_SZ);
+ }
+
+ while ((ret = inflate(&strm, Z_FINISH)) == Z_BUF_ERROR) {
+
+ // Output exhausted: reallocate
+ //
+ if (strm.avail_out == 0) {
+ strm.avail_out = chunk_w;
+
+ u3i_slab_grow(&sab_u, 3, strm.total_out + chunk_w);
+ strm.next_out = sab_u.buf_y + strm.total_out;
+ }
+
+ // Input exhausted: input leading zeros?
+ //
+ if (strm.avail_in == 0) {
+
+ if (leading_zeros) {
+ // Position in the stream exceeded atom bytes,
+ // but is still below stream length
+ //
+ if (strm.total_in + pos_w >= len_w
+ && strm.total_in + pos_w < p_octs_w) {
+
+ c3_w rem_w = p_octs_w - (strm.total_in + pos_w);
+ strm.next_in = zeros;
+
+ if (rem_w > ZEROS_SZ) {
+ strm.avail_in = ZEROS_SZ;
+ }
+ else {
+ strm.avail_in = rem_w;
+ }
+ }
+ else {
+ u3l_log("%i", ret);
+ u3l_log("%s", strm.msg);
+ inflateEnd(&strm);
+ u3i_slab_free(&sab_u);
+ return u3m_bail(c3__exit);
+ }
+ }
+ else {
+ u3l_log("%i", ret);
+ u3l_log("%s", strm.msg);
+ inflateEnd(&strm);
+ u3i_slab_free(&sab_u);
+ return u3m_bail(c3__exit);
+ }
+ }
+ }
+ if (ret != Z_STREAM_END) {
+ u3l_log("%i", ret);
+ u3l_log("%s", strm.msg);
+ inflateEnd(&strm);
+ u3i_slab_free(&sab_u);
+ return u3m_bail(c3__exit);
+ }
+ ret = inflateEnd(&strm);
+
+ if (ret != Z_OK) {
+ u3l_log("%i", ret);
+ u3l_log("%s", strm.msg);
+ u3i_slab_free(&sab_u);
+ return u3m_bail(c3__exit);
+ }
+
+ u3_noun decompressed_octs = u3nc(strm.total_out, u3i_slab_mint(&sab_u));
+ u3_noun new_pos = pos_w + strm.total_in;
+ u3_noun new_stream = u3nc(u3i_word(new_pos), u3k(octs));
+
+ return u3nc(decompressed_octs, new_stream);
+}
+
+u3_noun
+u3qe_decompress_gzip(u3_atom pos, u3_noun octs)
+{
+ return _decompress(pos, octs, 31);
+}
+u3_noun
+u3qe_decompress_zlib(u3_atom pos, u3_noun octs)
+{
+ return _decompress(pos, octs, 15);
+}
+
+u3_noun
+u3we_decompress_gzip(u3_noun cor)
+{
+ u3_atom pos;
+ u3_noun octs;
+
+ u3_noun a = u3r_at(u3x_sam, cor);
+ u3x_cell(a, &pos, &octs);
+
+ if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) {
+ return u3qe_decompress_gzip(pos, octs);
+ }
+
+ else {
+ return u3m_bail(c3__exit);
+ }
+}
+
+u3_noun
+u3we_decompress_zlib(u3_noun cor)
+{
+ u3_atom pos;
+ u3_noun octs;
+
+ u3_noun a = u3r_at(u3x_sam, cor);
+ u3x_cell(a, &pos, &octs);
+
+ if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) {
+ return u3qe_decompress_zlib(pos, octs);
+ }
+
+ else {
+ return u3m_bail(c3__exit);
+ }
+}
diff --git a/vere/pkg/noun/jets/f/cell.c b/vere/pkg/noun/jets/f/cell.c
new file mode 100644
index 0000000..0a818f2
--- /dev/null
+++ b/vere/pkg/noun/jets/f/cell.c
@@ -0,0 +1,29 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_cell(u3_noun hed,
+ u3_noun tal)
+ {
+ if ( (c3__void == hed) || (c3__void == tal) ) {
+ return c3__void;
+ } else {
+ return u3nt(c3__cell, u3k(hed), u3k(tal));
+ }
+ }
+ u3_noun
+ u3wf_cell(u3_noun cor)
+ {
+ u3_noun hed, tal;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &hed, u3x_sam_3, &tal, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_cell(hed, tal);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/comb.c b/vere/pkg/noun/jets/f/comb.c
new file mode 100644
index 0000000..1dfe794
--- /dev/null
+++ b/vere/pkg/noun/jets/f/comb.c
@@ -0,0 +1,70 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_comb(u3_noun mal,
+ u3_noun buz)
+ {
+ if ( (u3_none == mal) || (u3_none == buz) ) {
+ return u3_none;
+ }
+ else {
+ u3_noun p_mal, q_mal, p_buz, q_buz, pp_buz, pq_buz;
+
+ if ( (c3y == u3r_p(mal, 0, &p_mal)) && (0 != p_mal) ) {
+ if ( (c3y == u3r_p(buz, 0, &p_buz)) && (0 != p_buz) ) {
+ return u3nc(0,
+ u3qc_peg(p_mal, p_buz));
+ }
+ else if ( c3y == u3r_pq(buz, 2, &p_buz, &q_buz) &&
+ c3y == u3r_p(p_buz, 0, &pp_buz) &&
+ c3y == u3r_p(q_buz, 0, &pq_buz) )
+ {
+ return u3nt(2,
+ u3nc(0,
+ u3qc_peg(p_mal, pp_buz)),
+ u3nc(0,
+ u3qc_peg(p_mal, pq_buz)));
+ }
+ else return u3nt(7,
+ u3k(mal),
+ u3k(buz));
+ }
+#if 1
+ else if ( (c3y == u3r_bush(mal, &p_mal, &q_mal)) &&
+ (c3y == u3du(p_mal)) &&
+ (c3y == u3du(q_mal)) &&
+ (0 == u3h(q_mal)) &&
+ (1 == u3t(q_mal)) )
+ {
+ return u3nt(8,
+ u3k(p_mal),
+ u3k(buz));
+ }
+#endif
+ else if ( (c3y == u3r_p(buz, 0, &p_buz)) &&
+ (c3y == u3r_sing(1, p_buz)) )
+ {
+ return u3k(mal);
+ }
+ else return u3nt(7,
+ u3k(mal),
+ u3k(buz));
+ }
+ }
+ u3_noun
+ u3wf_comb(u3_noun cor)
+ {
+ u3_noun mal, buz;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &mal, u3x_sam_3, &buz, 0) ) {
+ return u3_none;
+ } else {
+ return u3qf_comb(mal, buz);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/cons.c b/vere/pkg/noun/jets/f/cons.c
new file mode 100644
index 0000000..45719c1
--- /dev/null
+++ b/vere/pkg/noun/jets/f/cons.c
@@ -0,0 +1,54 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_cons(u3_noun vur,
+ u3_noun sed)
+ {
+ u3_noun p_vur, p_sed;
+
+ if ( c3y == u3r_p(vur, 1, &p_vur) &&
+ c3y == u3r_p(sed, 1, &p_sed) ) {
+ return u3nt(1,
+ u3k(p_vur),
+ u3k(p_sed));
+ }
+#if 0
+ else if ( c3y == u3r_p(vur, 0, &p_vur) &&
+ c3y == u3r_p(sed, 0, &p_sed) &&
+ !(c3y == u3r_sing(1, p_vur)) &&
+ !(c3y == u3r_sing(p_vur, p_sed)) &&
+ (0 == u3r_nord(p_vur, p_sed)) )
+ {
+ u3_atom fub = u3qa_div(p_vur, 2);
+ u3_atom nof = u3qa_div(p_sed, 2);
+
+ if ( c3y == u3r_sing(fub, nof) ) {
+ u3z(nof);
+
+ return u3nc(0, fub);
+ }
+ else {
+ u3z(fub);
+ u3z(nof);
+ }
+ }
+#endif
+ return u3nc(u3k(vur), u3k(sed));
+ }
+ u3_noun
+ u3wf_cons(u3_noun cor)
+ {
+ u3_noun vur, sed;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &vur, u3x_sam_3, &sed, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_cons(vur, sed);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/core.c b/vere/pkg/noun/jets/f/core.c
new file mode 100644
index 0000000..ca7e93d
--- /dev/null
+++ b/vere/pkg/noun/jets/f/core.c
@@ -0,0 +1,118 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_core(u3_noun pac,
+ u3_noun con)
+ {
+ if ( (c3__void == pac) ) {
+ return c3__void;
+ } else {
+ {
+ u3_noun p_con, q_con, r_con, hr_con, tr_con;
+
+ u3r_trel(con, &p_con, &q_con, &r_con);
+ u3r_cell(r_con, &hr_con, &tr_con);
+ if ( (c3y == u3du(hr_con)) &&
+ (u3_nul == u3h(hr_con)) &&
+ (u3_nul == u3t(hr_con)) )
+ {
+ u3l_log("old core");
+ abort();
+ }
+ }
+ return u3nt(c3__core, u3k(pac), u3k(con));
+ }
+ }
+ u3_noun
+ u3wf_core(u3_noun cor)
+ {
+ u3_noun pac, con;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &pac, u3x_sam_3, &con, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_core(pac, con);
+ }
+ }
+
+#if 0
+ static void
+ _fork_test(const c3_c *lab_c, u3_noun set)
+ {
+ if ( u3_nul == set ) {
+ return;
+ } else {
+ u3_noun n_set, l_set, r_set;
+
+ u3x_trel(set, &n_set, &l_set, &r_set);
+
+ u3qf_test(lab_c, n_set);
+ _fork_test(lab_c, l_set);
+ _fork_test(lab_c, r_set);
+ }
+ }
+ void
+ u3qf_test(const c3_c* lab_c, u3_noun sut)
+ {
+ u3_noun p_sut, q_sut;
+
+ if ( c3n == u3du(sut) ) switch ( sut ) {
+ default: u3m_bail(c3__fail); return;
+
+ case c3__noun:
+ {
+ return;
+ }
+ case c3__void:
+ {
+ return;
+ }
+ }
+ else switch ( u3h(sut) ) {
+ default: u3m_bail(c3__fail); return;
+
+ case c3__atom: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ return;
+ }
+ case c3__cell: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ u3qf_test(lab_c, p_sut);
+ u3qf_test(lab_c, q_sut);
+ return;
+ }
+ case c3__core: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ u3qf_test(lab_c, p_sut);
+ return;
+ }
+ case c3__face: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ u3qf_test(lab_c, q_sut);
+ return;
+ }
+ case c3__fork: p_sut = u3t(sut);
+ {
+ _fork_test(lab_c, p_sut);
+ return;
+ }
+ case c3__hint: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ u3qf_test(lab_c, q_sut);
+ u3qf_test(lab_c, u3h(p_sut));
+ return;
+ }
+ case c3__hold: u3x_cell(u3t(sut), &p_sut, &q_sut);
+ {
+ u3qf_test(lab_c, p_sut);
+ return;
+ }
+ }
+ }
+#endif
diff --git a/vere/pkg/noun/jets/f/face.c b/vere/pkg/noun/jets/f/face.c
new file mode 100644
index 0000000..7e689e7
--- /dev/null
+++ b/vere/pkg/noun/jets/f/face.c
@@ -0,0 +1,31 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_face(u3_noun sag,
+ u3_noun tip)
+ {
+ if ( c3__void == tip ) {
+ return c3__void;
+ }
+ else return u3nt(c3__face,
+ u3k(sag),
+ u3k(tip));
+ }
+ u3_noun
+ u3wf_face(u3_noun cor)
+ {
+ u3_noun sag, tip;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_face(sag, tip);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/f/fine.c b/vere/pkg/noun/jets/f/fine.c
new file mode 100644
index 0000000..2c5a85c
--- /dev/null
+++ b/vere/pkg/noun/jets/f/fine.c
@@ -0,0 +1,35 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_fine(u3_noun fuv,
+ u3_noun lup,
+ u3_noun mar)
+ {
+ if ( (c3__void == lup) || (c3__void == mar) ) {
+ return c3__void;
+ } else {
+ return u3nq(c3__fine,
+ u3k(fuv),
+ u3k(lup),
+ u3k(mar));
+ }
+ }
+ u3_noun
+ u3wf_fine(u3_noun cor)
+ {
+ u3_noun fuv, lup, mar;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &fuv,
+ u3x_sam_6, &lup,
+ u3x_sam_7, &mar, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_fine(fuv, lup, mar);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/fitz.c b/vere/pkg/noun/jets/f/fitz.c
new file mode 100644
index 0000000..b1c2a5d
--- /dev/null
+++ b/vere/pkg/noun/jets/f/fitz.c
@@ -0,0 +1,75 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+static u3_noun
+_fitz_fiz(u3_noun yaz,
+ u3_noun wix)
+{
+ c3_w yaz_w = u3r_met(3, yaz);
+ c3_w wix_w = u3r_met(3, wix);
+ c3_y yaz_y, wix_y;
+
+ yaz_y = (0 == yaz_w) ? 0 : u3r_byte((yaz_w - 1), yaz);
+ if ( (yaz_y < 'A') || (yaz_y > 'Z') ) yaz_y = 0;
+
+ wix_y = (0 == wix_w) ? 0 : u3r_byte((wix_w - 1), wix);
+ if ( (wix_y < 'A') || (wix_y > 'Z') ) wix_y = 0;
+
+ if ( yaz_y && wix_y ) {
+ if ( wix_y > yaz_y ) {
+ return c3n;
+ }
+ }
+
+ return c3y;
+}
+
+u3_noun
+u3qf_fitz(u3_noun yaz,
+ u3_noun wix)
+{
+ c3_w yet_w = u3r_met(3, yaz);
+ c3_w wet_w = u3r_met(3, wix);
+
+ c3_w i_w, met_w = c3_min(yet_w, wet_w);
+
+ if ( c3n == _fitz_fiz(yaz, wix) ) {
+ return c3n;
+ }
+ for ( i_w = 0; i_w < met_w; i_w++ ) {
+ c3_y yaz_y = u3r_byte(i_w, yaz);
+ c3_y wix_y = u3r_byte(i_w, wix);
+
+ if ( (i_w == (yet_w - 1)) && (yaz_y >= 'A') && (yaz_y <= 'Z')) {
+ return c3y;
+ }
+
+ if ( (i_w == (wet_w - 1)) && (wix_y >= 'A') && (wix_y <= 'Z')) {
+ return c3y;
+ }
+
+ if ( yaz_y != wix_y ) {
+ return c3n;
+ }
+ }
+ return c3y;
+}
+
+u3_noun
+u3wf_fitz(u3_noun cor)
+{
+ u3_noun yaz, wix;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &yaz, u3x_sam_3, &wix, 0)) ||
+ (c3n == u3ud(yaz)) ||
+ (c3n == u3ud(wix)) )
+ {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_fitz(yaz, wix);
+ }
+}
diff --git a/vere/pkg/noun/jets/f/flan.c b/vere/pkg/noun/jets/f/flan.c
new file mode 100644
index 0000000..319e1f0
--- /dev/null
+++ b/vere/pkg/noun/jets/f/flan.c
@@ -0,0 +1,47 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_flan(u3_noun bos,
+ u3_noun nif)
+ {
+ if ( c3y == u3r_sing(bos, nif) ) {
+ return u3k(bos);
+ }
+ if ( c3y == u3r_sing(1, u3h(bos)) ) {
+ if ( (u3_nul == u3t(bos)) ) {
+ return u3k(nif);
+ }
+ else return u3k(bos);
+ }
+ else {
+ if ( c3y == u3r_sing(1, u3h(nif)) ) {
+ if ( (u3_nul == u3t(nif)) ) {
+ return u3k(bos);
+ }
+ else return u3k(nif);
+ }
+ else {
+ return u3nq(6,
+ u3k(bos),
+ u3k(nif),
+ u3nc(1, c3n));
+ }
+ }
+ }
+ u3_noun
+ u3wf_flan_139(u3_noun cor)
+ {
+ u3_noun bos, nif;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_flan(bos, nif);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/flip.c b/vere/pkg/noun/jets/f/flip.c
new file mode 100644
index 0000000..9eb922e
--- /dev/null
+++ b/vere/pkg/noun/jets/f/flip.c
@@ -0,0 +1,39 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_flip(u3_noun hel)
+ {
+ if ( c3y == u3r_sing(1, u3h(hel)) ) {
+ if ( (c3y == u3t(hel)) ) {
+ return u3nc(1, c3n);
+ }
+ else {
+ u3_assert((c3n == u3t(hel)));
+
+ return u3nc(1, c3y);
+ }
+ }
+ else {
+ return u3nq(6,
+ u3k(hel),
+ u3nc(1, c3n),
+ u3nc(1, c3y));
+ }
+ }
+ u3_noun
+ u3wf_flip_139(u3_noun cor)
+ {
+ u3_noun hel;
+
+ if ( u3_none == (hel = u3r_at(u3x_sam, cor)) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_flip(hel);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/flor.c b/vere/pkg/noun/jets/f/flor.c
new file mode 100644
index 0000000..031168e
--- /dev/null
+++ b/vere/pkg/noun/jets/f/flor.c
@@ -0,0 +1,47 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_flor(u3_noun bos,
+ u3_noun nif)
+ {
+ if ( c3y == u3r_sing(bos, nif) ) {
+ return u3k(bos);
+ }
+ if ( c3y == u3r_sing(1, u3h(bos)) ) {
+ if ( (u3_nul == u3t(bos)) ) {
+ return u3k(bos);
+ }
+ else return u3k(nif);
+ }
+ else {
+ if ( c3y == u3r_sing(1, u3h(nif)) ) {
+ if ( (u3_nul == u3t(nif)) ) {
+ return u3k(nif);
+ }
+ else return u3k(bos);
+ }
+ else {
+ return u3nq(6,
+ u3k(bos),
+ u3nc(1, c3y),
+ u3k(nif));
+ }
+ }
+ }
+ u3_noun
+ u3wf_flor_139(u3_noun cor)
+ {
+ u3_noun bos, nif;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_flor(bos, nif);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/fork.c b/vere/pkg/noun/jets/f/fork.c
new file mode 100644
index 0000000..b2a68eb
--- /dev/null
+++ b/vere/pkg/noun/jets/f/fork.c
@@ -0,0 +1,79 @@
+/// @file
+
+#include "jets/k.h"
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_forq(u3_noun hoz,
+ u3_noun bur)
+ {
+ if ( c3y == u3r_sing(hoz, bur) ) {
+ return u3k(hoz);
+ }
+ else if ( c3__void == bur ) {
+ return u3k(hoz);
+ }
+ else if ( c3__void == hoz ) {
+ return u3k(bur);
+ }
+ else return u3kf_fork(u3nt(u3k(hoz), u3k(bur), u3_nul));
+ }
+
+ u3_noun
+ u3qf_fork(u3_noun yed)
+ {
+ u3_noun lez = u3_nul;
+
+ while ( u3_nul != yed ) {
+ u3_noun i_yed = u3h(yed);
+
+ if ( c3__void != i_yed ) {
+ if ( (c3y == u3du(i_yed)) && (c3__fork == u3h(i_yed)) ) {
+ lez = u3kdi_uni(lez, u3k(u3t(i_yed)));
+ }
+ else {
+ lez = u3kdi_put(lez, u3k(i_yed));
+ }
+ }
+
+ yed = u3t(yed);
+ }
+
+ if ( u3_nul == lez ) {
+ return c3__void;
+ }
+ else if ( (u3_nul == u3h(u3t(lez))) && (u3_nul == u3t(u3t(lez))) ) {
+ u3_noun ret = u3k(u3h(lez));
+
+ u3z(lez);
+ return ret;
+ }
+ else {
+ return u3nc(c3__fork, lez);
+ }
+ }
+
+ u3_noun
+ u3wf_fork(u3_noun cor)
+ {
+ u3_noun yed;
+
+ if ( c3n == u3r_mean(cor, u3x_sam, &yed, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_fork(yed);
+ }
+ }
+
+ u3_noun
+ u3kf_fork(u3_noun yed)
+ {
+ u3_noun ret = u3qf_fork(yed);
+
+ u3z(yed);
+ return ret;
+ }
diff --git a/vere/pkg/noun/jets/f/help.c b/vere/pkg/noun/jets/f/help.c
new file mode 100644
index 0000000..41fe7fb
--- /dev/null
+++ b/vere/pkg/noun/jets/f/help.c
@@ -0,0 +1,31 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_help(u3_noun sag,
+ u3_noun tip)
+ {
+ if ( c3__void == tip ) {
+ return c3__void;
+ }
+ else return u3nt(c3__help,
+ u3k(sag),
+ u3k(tip));
+ }
+ u3_noun
+ u3wf_help(u3_noun cor)
+ {
+ u3_noun sag, tip;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_help(sag, tip);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/f/hint.c b/vere/pkg/noun/jets/f/hint.c
new file mode 100644
index 0000000..175c3fb
--- /dev/null
+++ b/vere/pkg/noun/jets/f/hint.c
@@ -0,0 +1,32 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+ u3_noun
+ u3qf_hint(u3_noun sag,
+ u3_noun tip)
+ {
+ if ( c3__void == tip ) {
+ return c3__void;
+ }
+ if ( c3__noun == tip ) {
+ return c3__noun;
+ }
+ else return u3nt(c3__hint, u3k(sag), u3k(tip));
+ }
+ u3_noun
+ u3wf_hint(u3_noun cor)
+ {
+ u3_noun sag, tip;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_hint(sag, tip);
+ }
+ }
+
diff --git a/vere/pkg/noun/jets/f/look.c b/vere/pkg/noun/jets/f/look.c
new file mode 100644
index 0000000..e50e914
--- /dev/null
+++ b/vere/pkg/noun/jets/f/look.c
@@ -0,0 +1,134 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+/* internals
+*/
+ static u3_noun
+ _look_in(u3_noun cog,
+ u3_noun dab,
+ u3_atom axe)
+ {
+ if ( u3_nul == dab ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_dab, l_dab, r_dab;
+
+ u3r_trel(dab, &n_dab, &l_dab, &r_dab);
+ if ( c3n == u3du(n_dab) ) {
+ // return u3m_bail(c3__fail);
+ u3l_log("bad look");
+ return u3m_bail(c3__exit) ;
+ }
+ else {
+ u3_noun pn_dab = u3h(n_dab);
+ u3_noun qn_dab = u3t(n_dab);
+
+ if ( (u3_nul == l_dab) && (u3_nul == r_dab) ) {
+ if ( (c3y == u3du(qn_dab)) &&
+ (c3y == u3r_sing(cog, pn_dab)) ) {
+ return u3nt(u3_nul,
+ u3k(axe),
+ u3k(qn_dab));
+ }
+ else {
+ return u3_nul;
+ }
+ }
+ else if ( (u3_nul == l_dab) ) {
+ if ( (c3y == u3du(qn_dab)) &&
+ (c3y == u3r_sing(cog, pn_dab)) ) {
+ return u3nt(u3_nul,
+ u3qc_peg(axe, 2),
+ u3k(qn_dab));
+ }
+ else {
+ if ( c3y == u3qc_gor(cog, pn_dab) ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun pro;
+
+ axe = u3qc_peg(axe, 3);
+ pro = _look_in(cog, r_dab, axe);
+ u3z(axe);
+ return pro;
+ }
+ }
+ }
+ else if ( (u3_nul == r_dab) ) {
+ if ( (c3y == u3du(qn_dab)) &&
+ (c3y == u3r_sing(cog, pn_dab)) ) {
+ return u3nt(u3_nul,
+ u3qc_peg(axe, 2),
+ u3k(qn_dab));
+ }
+ else {
+ if ( c3y == u3qc_gor(cog, pn_dab) ) {
+ u3_noun pro;
+
+ axe = u3qc_peg(axe, 3);
+ pro = _look_in(cog, l_dab, axe);
+ u3z(axe);
+ return pro;
+ }
+ else {
+ return u3_nul;
+ }
+ }
+ }
+ else {
+ if ( (c3y == u3du(qn_dab)) &&
+ (c3y == u3r_sing(cog, pn_dab)) ) {
+ return u3nt(u3_nul,
+ u3qc_peg(axe, 2),
+ u3k(qn_dab));
+ }
+ else {
+ if ( c3y == u3qc_gor(cog, pn_dab) ) {
+ u3_noun pro;
+
+ axe = u3qc_peg(axe, 6);
+ pro = _look_in(cog, l_dab, axe);
+ u3z(axe);
+ return pro;
+ }
+ else {
+ u3_noun pro;
+
+ axe = u3qc_peg(axe, 7);
+ pro = _look_in(cog, r_dab, axe);
+ u3z(axe);
+ return pro;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+ u3_noun
+ u3qf_look(u3_noun cog,
+ u3_noun dab)
+ {
+ return _look_in(cog, dab, 1);
+ }
+ u3_noun
+ u3wf_look(u3_noun cor)
+ {
+ u3_noun cog, dab;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dab, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_look(cog, dab);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/loot.c b/vere/pkg/noun/jets/f/loot.c
new file mode 100644
index 0000000..d1a7bef
--- /dev/null
+++ b/vere/pkg/noun/jets/f/loot.c
@@ -0,0 +1,133 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+
+/* internals
+*/
+ static u3_noun
+ _loot_in(u3_noun cog,
+ u3_noun dom,
+ u3_atom axe)
+ {
+ if ( u3_nul == dom ) {
+ return u3_nul;
+ }
+ else {
+ u3_noun n_dom, l_dom, r_dom;
+
+ u3r_trel(dom, &n_dom, &l_dom, &r_dom);
+ if ( c3n == u3du(n_dom) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun qqn_dom = u3t(u3t(n_dom));
+ u3_noun yep = u3qf_look(cog, qqn_dom);
+
+ if ( (u3_nul == l_dom) && (u3_nul == r_dom) ) {
+ if ( u3_nul == yep ) {
+ return u3_nul;
+ } else {
+ u3_noun u_yep = u3t(yep);
+ u3_noun pro;
+
+ pro = u3nt(u3_nul, u3qc_peg(axe, u3h(u_yep)), u3k(u3t(u_yep)));
+ u3z(yep);
+ return pro;
+ }
+ }
+ else if ( (u3_nul == l_dom) ) {
+ if ( u3_nul == yep ) {
+ u3_noun nax = u3qc_peg(axe, 3);
+ u3_noun pro;
+
+ pro = _loot_in(cog, r_dom, nax);
+ u3z(nax);
+ return pro;
+ }
+ else {
+ u3_noun u_yep = u3t(yep);
+ u3_noun nax = u3qc_peg(axe, 2);
+ u3_noun pro;
+
+ pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep)));
+ u3z(nax);
+ u3z(yep);
+ return pro;
+ }
+ }
+ else if ( (u3_nul == r_dom) ) {
+ if ( u3_nul == yep ) {
+ u3_noun nax = u3qc_peg(axe, 3);
+ u3_noun pro;
+
+ pro = _loot_in(cog, l_dom, nax);
+ u3z(nax);
+ return pro;
+ }
+ else {
+ u3_noun u_yep = u3t(yep);
+ u3_noun nax = u3qc_peg(axe, 2);
+ u3_noun pro;
+
+ pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep)));
+ u3z(nax);
+ u3z(yep);
+ return pro;
+ }
+ }
+ else {
+ if ( u3_nul == yep ) {
+ u3_noun nax = u3qc_peg(axe, 6);
+ u3_noun pey;
+
+ pey = _loot_in(cog, l_dom, nax);
+ u3z(nax);
+
+ if ( u3_nul != pey ) {
+ return pey;
+ }
+ else {
+ u3_noun nax = u3qc_peg(axe, 7);
+ u3_noun pro;
+
+ pro = _loot_in(cog, r_dom, nax);
+ u3z(nax);
+ return pro;
+ }
+ }
+ else {
+ u3_noun u_yep = u3t(yep);
+ u3_noun nax = u3qc_peg(axe, 2);
+ u3_noun pro;
+
+ pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep)));
+ u3z(nax);
+ u3z(yep);
+ return pro;
+ }
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3qf_loot(u3_noun cog,
+ u3_noun dom)
+ {
+ return _loot_in(cog, dom, 1);
+ }
+ u3_noun
+ u3wf_loot(u3_noun cor)
+ {
+ u3_noun cog, dom;
+
+ if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dom, 0) ) {
+ return u3m_bail(c3__fail);
+ } else {
+ return u3qf_loot(cog, dom);
+ }
+ }
diff --git a/vere/pkg/noun/jets/f/ut_crop.c b/vere/pkg/noun/jets/f/ut_crop.c
new file mode 100644
index 0000000..189564d
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_crop.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_crop(u3_noun cor)
+{
+ u3_noun bat, sut, ref, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__crop + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, ref, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_fish.c b/vere/pkg/noun/jets/f/ut_fish.c
new file mode 100644
index 0000000..e8acbd4
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_fish.c
@@ -0,0 +1,35 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_fish(u3_noun cor)
+{
+ u3_noun bat, sut, axe, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &axe, u3x_con, &van, 0))
+ || (c3n == u3ud(axe))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__fish + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, axe, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_fuse.c b/vere/pkg/noun/jets/f/ut_fuse.c
new file mode 100644
index 0000000..8e4e1a6
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_fuse.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_fuse(u3_noun cor)
+{
+ u3_noun bat, sut, ref, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__fuse + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, ref, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_mint.c b/vere/pkg/noun/jets/f/ut_mint.c
new file mode 100644
index 0000000..618e729
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_mint.c
@@ -0,0 +1,36 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_mint(u3_noun cor)
+{
+ u3_noun bat, sut, gol, gen, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol,
+ u3x_sam_3, &gen,
+ u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_m fun_m = 141 + c3__mint;
+ u3_noun vet = u3r_at(u3qfu_van_vet, van);
+ u3_noun key = u3z_key_5(fun_m, vet, sut, gol, gen, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_mull.c b/vere/pkg/noun/jets/f/ut_mull.c
new file mode 100644
index 0000000..767ab3c
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_mull.c
@@ -0,0 +1,37 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_mull(u3_noun cor)
+{
+ u3_noun bat, sut, gol, dox, gen, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol,
+ u3x_sam_6, &dox,
+ u3x_sam_7, &gen,
+ u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__mull + ((!!vet) << 8);
+ u3_noun key = u3z_key_5(fun_m, sut, gol, dox, gen, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_nest.c b/vere/pkg/noun/jets/f/ut_nest.c
new file mode 100644
index 0000000..9bc53bf
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_nest.c
@@ -0,0 +1,50 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_nest_dext(u3_noun dext_core)
+{
+ u3_noun nest_in_core, nest_core;
+ u3_noun bat, sut, ref, van, seg, reg, gil;
+
+ if ( (u3_none == (nest_in_core = u3r_at(3, dext_core)))
+ || (c3n == u3r_mean(nest_in_core, u3x_sam_2, &seg,
+ u3x_sam_6, &reg,
+ u3x_sam_7, &gil,
+ u3x_con, &nest_core, 0))
+ || (c3n == u3r_mean(nest_core, u3x_sam_3, &ref,
+ u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__dext + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, ref, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(dext_core), u3k(u3x_at(u3x_bat, dext_core)));
+
+ if ( ((c3y == pro) && (u3_nul == reg)) ||
+ ((c3n == pro) && (u3_nul == seg)) )
+ {
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ else {
+ u3z(key);
+ return pro;
+ }
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_redo.c b/vere/pkg/noun/jets/f/ut_redo.c
new file mode 100644
index 0000000..43fb06c
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_redo.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_redo(u3_noun cor)
+{
+ u3_noun bat, sut, ref, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__redo + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, ref, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/f/ut_rest.c b/vere/pkg/noun/jets/f/ut_rest.c
new file mode 100644
index 0000000..87ff60f
--- /dev/null
+++ b/vere/pkg/noun/jets/f/ut_rest.c
@@ -0,0 +1,34 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3wfu_rest(u3_noun cor)
+{
+ u3_noun bat, sut, leg, van;
+
+ if ( (c3n == u3r_mean(cor, u3x_sam, &leg, u3x_con, &van, 0))
+ || (u3_none == (bat = u3r_at(u3x_bat, van)))
+ || (u3_none == (sut = u3r_at(u3x_sam, van))) )
+ {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_weak vet = u3r_at(u3qfu_van_vet, van);
+ c3_m fun_m = 141 + c3__rest + ((!!vet) << 8);
+ u3_noun key = u3z_key_3(fun_m, sut, leg, bat);
+ u3_weak pro = u3z_find(u3z_memo_toss, key);
+
+ if ( u3_none != pro ) {
+ u3z(key);
+ return pro;
+ }
+ else {
+ pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor)));
+ return u3z_save(u3z_memo_toss, key, pro);
+ }
+ }
+}
diff --git a/vere/pkg/noun/jets/g/plot.c b/vere/pkg/noun/jets/g/plot.c
new file mode 100644
index 0000000..18c8ab0
--- /dev/null
+++ b/vere/pkg/noun/jets/g/plot.c
@@ -0,0 +1,364 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+// XX optimize
+//
+static c3_w
+_met_plat_m(c3_g a_g, c3_w fum_w, c3_w met_w, u3_atom vat)
+{
+ c3_w len_w, wor_w;
+
+ {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, a_g, met_w);
+ u3r_chop(a_g, fum_w, met_w, 0, sab_u.buf_w, vat);
+
+ len_w = sab_u.len_w;
+
+ while ( len_w && !sab_u.buf_w[len_w - 1] ) {
+ len_w--;
+ }
+
+ wor_w = !len_w ? 0 : sab_u.buf_w[len_w - 1];
+
+ u3i_slab_free(&sab_u);
+ }
+
+
+ if ( !len_w ) {
+ return 0;
+ }
+
+ {
+ c3_w gal_w = len_w - 1;
+ c3_w daz_w = wor_w;
+ c3_y a_y = a_g;
+
+ // inlined from u3r_met
+ if (a_y < 5) {
+ c3_y max_y = (1 << a_y) - 1;
+ c3_y gow_y = 5 - a_y;
+
+ if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y)) {
+ return u3m_bail(c3__fail);
+ }
+
+ return (gal_w << gow_y)
+ + ((c3_bits_word(daz_w) + max_y)
+ >> a_y);
+ }
+
+ {
+ c3_y gow_y = (a_y - 5);
+ return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y;
+ }
+ }
+}
+
+static c3_w
+_met_list(c3_g a_g,
+ c3_w sep_w,
+ u3_noun b_p);
+
+static c3_w
+_met_pair(c3_g* las_g,
+ c3_w sep_w,
+ u3_noun a_p,
+ u3_noun b_p,
+ c3_g* new_g)
+{
+ c3_g res_g, a_g;
+
+ while ( c3y == u3a_is_cell(a_p) ) {
+ sep_w = _met_pair(las_g, sep_w, u3h(a_p), u3t(a_p), &res_g);
+ las_g = &res_g;
+ a_p = u3h(b_p);
+ b_p = u3t(b_p);
+ }
+
+ if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ a_g = (c3_g)a_p;
+
+ if ( las_g && (a_g != *las_g) ) {
+ sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow
+ }
+
+ *new_g = a_g;
+ return _met_list(a_g, sep_w, b_p);
+}
+
+static c3_w
+_met_list(c3_g a_g,
+ c3_w sep_w,
+ u3_noun b_p)
+{
+ if ( u3_nul != b_p ) {
+ c3_w met_w;
+ u3_noun i, t = b_p;
+
+ do {
+ u3x_cell(t, &i, &t);
+
+ // ?@ i.b.p
+ if ( c3y == u3a_is_atom(i) ) {
+ met_w = u3r_met(a_g, i);
+ sep_w += met_w; // XX overflow
+ }
+ else {
+ u3_noun i_i, t_i;
+ u3x_cell(i, &i_i, &t_i);
+
+ // ?=(@ -.i.b.p)
+ if ( c3y == u3a_is_atom(i_i) ) {
+ if ( !_(u3a_is_cat(i_i)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = (c3_w)i_i;
+ sep_w += met_w; // XX overflow
+ }
+ else {
+ u3_noun l, r;
+ c3_o cel_o = u3r_cell(i_i, &l, &r);
+
+ // ?=([%c ~] -.i.b.p)
+ if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) {
+ u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i)));
+ u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i)));
+ u3_atom q_t_i = u3x_atom(u3t(t_i));
+
+ if ( !_(u3a_is_cat(p_p_t_i))
+ || !_(u3a_is_cat(q_p_t_i))
+ || !_(u3a_is_cat(q_t_i)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = (c3_w)q_p_t_i;
+ sep_w += met_w; // XX overflow
+ }
+ // ?=([%m ~] -.i.b.p)
+ else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) {
+ u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i)));
+ u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i)));
+ u3_atom q_t_i = u3x_atom(u3t(t_i));
+
+ if ( !_(u3a_is_cat(p_p_t_i))
+ || !_(u3a_is_cat(q_p_t_i))
+ || !_(u3a_is_cat(q_t_i)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i);
+ sep_w += met_w; // XX overflow
+ }
+ // ?=([%s ~] -.i.b.p) (assumed)
+ else {
+ c3_g new_g;
+ u3x_cell(t_i, &l, &r);
+
+ sep_w = _met_pair(&a_g, sep_w, l, r, &new_g);
+
+ if ( new_g != a_g ) {
+ sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow
+ }
+ }
+ }
+ }
+ }
+ while ( u3_nul != t );
+ }
+
+ return sep_w;
+}
+
+static c3_w
+_fax_list(u3i_slab* sab_u,
+ c3_g a_g,
+ c3_w sep_w,
+ u3_noun b_p);
+
+static c3_w
+_fax_pair(u3i_slab* sab_u,
+ c3_g* las_g,
+ c3_w sep_w,
+ u3_noun a_p,
+ u3_noun b_p,
+ c3_g* new_g)
+{
+ c3_g res_g, a_g;
+
+ while ( c3y == u3a_is_cell(a_p) ) {
+ sep_w = _fax_pair(sab_u, las_g, sep_w, u3h(a_p), u3t(a_p), &res_g);
+ las_g = &res_g;
+ a_p = u3h(b_p);
+ b_p = u3t(b_p);
+ }
+
+ if ( !_(u3a_is_cat(a_p)) || (a_p >= 32) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ a_g = (c3_g)a_p;
+
+ if ( las_g && (a_g != *las_g) ) {
+ sep_w = u3qc_rig_s(*las_g, sep_w, a_g); // XX overflow
+ }
+
+ *new_g = a_g;
+ return _fax_list(sab_u, a_g, sep_w, b_p);
+}
+
+static c3_w
+_fax_list(u3i_slab* sab_u,
+ c3_g a_g,
+ c3_w sep_w,
+ u3_noun b_p)
+{
+ if ( u3_nul != b_p ) {
+ c3_w met_w;
+ u3_noun i, t = b_p;
+
+ do {
+ u3x_cell(t, &i, &t);
+
+ // ?@ i.b.p
+ if ( c3y == u3a_is_atom(i) ) {
+ met_w = u3r_met(a_g, i);
+
+ u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, i);
+
+ sep_w += met_w; // XX overflow
+ }
+ else {
+ u3_noun i_i, t_i;
+ u3x_cell(i, &i_i, &t_i);
+
+ // ?=(@ -.i.b.p)
+ if ( c3y == u3a_is_atom(i_i) ) {
+ if ( !_(u3a_is_cat(i_i)) ) {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = (c3_w)i_i;
+
+ u3r_chop(a_g, 0, met_w, sep_w, sab_u->buf_w, u3x_atom(t_i));
+
+ sep_w += met_w; // XX overflow
+ }
+ else {
+ u3_noun l, r;
+ c3_o cel_o = u3r_cell(i_i, &l, &r);
+
+ // ?=([%c ~] -.i.b.p)
+ if ( (c3y == cel_o) && ('c' == l) && (u3_nul == r) ) {
+ u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i)));
+ u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i)));
+ u3_atom q_t_i = u3x_atom(u3t(t_i));
+
+ if ( !_(u3a_is_cat(p_p_t_i))
+ || !_(u3a_is_cat(q_p_t_i))
+ || !_(u3a_is_cat(q_t_i)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = (c3_w)q_p_t_i;
+
+ u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i);
+
+ sep_w += met_w; // XX overflow
+ }
+ // ?=([%m ~] -.i.b.p)
+ else if ( (c3y == cel_o) && ('m' == l) && (u3_nul == r) ) {
+ u3_atom p_p_t_i = u3x_atom(u3h(u3h(t_i)));
+ u3_atom q_p_t_i = u3x_atom(u3t(u3h(t_i)));
+ u3_atom q_t_i = u3x_atom(u3t(t_i));
+
+ if ( !_(u3a_is_cat(p_p_t_i))
+ || !_(u3a_is_cat(q_p_t_i))
+ || !_(u3a_is_cat(q_t_i)) )
+ {
+ return u3m_bail(c3__fail);
+ }
+
+ met_w = _met_plat_m(a_g, (c3_w)p_p_t_i, (c3_w)q_p_t_i, q_t_i);
+
+ u3r_chop(a_g, (c3_w)p_p_t_i, met_w, sep_w, sab_u->buf_w, q_t_i);
+
+ sep_w += met_w; // XX overflow
+ }
+ // ?=([%s ~] -.i.b.p) (assumed)
+ else {
+ c3_g new_g;
+ u3x_cell(t_i, &l, &r);
+
+ sep_w = _fax_pair(sab_u, &a_g, sep_w, l, r, &new_g);
+
+ if ( new_g != a_g ) {
+ sep_w = u3qc_rig_s(new_g, sep_w, a_g); // XX overflow
+ }
+ }
+ }
+ }
+ }
+ while ( u3_nul != t );
+ }
+
+ return sep_w;
+}
+
+u3_noun
+u3qg_plot_met(u3_noun a_p, u3_noun b_p)
+{
+ c3_g out_g;
+ c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g);
+
+ return u3nc(out_g, u3i_word(sep_w));
+}
+
+u3_noun
+u3wg_plot_met(u3_noun cor)
+{
+ u3_noun a_p, b_p;
+ {
+ u3_noun sam = u3h(u3t(cor));
+ a_p = u3h(sam);
+ b_p = u3t(sam);
+ }
+ return u3qg_plot_met(a_p, b_p);
+}
+
+u3_noun
+u3qg_plot_fax(u3_noun a_p, u3_noun b_p)
+{
+ c3_g out_g;
+ c3_w sep_w = _met_pair(NULL, 0, a_p, b_p, &out_g);
+ u3i_slab sab_u;
+
+ u3i_slab_init(&sab_u, out_g, sep_w);
+
+ _fax_pair(&sab_u, NULL, 0, a_p, b_p, &out_g);
+
+ return u3nt(u3i_slab_mint(&sab_u), out_g, u3i_word(sep_w));
+}
+
+u3_noun
+u3wg_plot_fax(u3_noun cor)
+{
+ u3_noun a_p, b_p;
+ {
+ u3_noun sam = u3h(u3t(cor));
+ a_p = u3h(sam);
+ b_p = u3t(sam);
+ }
+ return u3qg_plot_fax(a_p, b_p);
+}
diff --git a/vere/pkg/noun/jets/i/lagoon.c b/vere/pkg/noun/jets/i/lagoon.c
new file mode 100644
index 0000000..db7088b
--- /dev/null
+++ b/vere/pkg/noun/jets/i/lagoon.c
@@ -0,0 +1,3315 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "c3/motes.h"
+
+#include "noun.h"
+#include "softfloat.h"
+#include "softblas.h"
+
+#include <math.h> // for pow()
+#include <stdio.h>
+
+#define f16_ceil(a) f16_roundToInt( a, softfloat_round_max, false )
+#define f32_ceil(a) f32_roundToInt( a, softfloat_round_max, false )
+#define f64_ceil(a) f64_roundToInt( a, softfloat_round_max, false )
+#define f128M_ceil(a, b) f128M_roundToInt( a, softfloat_round_max, false, b )
+
+ union half {
+ float16_t h;
+ c3_w c;
+ };
+
+ union sing {
+ float32_t s;
+ c3_w c;
+ };
+
+ union doub {
+ float64_t d;
+ c3_d c;
+ };
+
+ union quad {
+ float128_t q;
+ c3_d c[2];
+ };
+
+ // $?(%n %u %d %z %a)
+ static inline void
+ _set_rounding(c3_w a)
+ {
+ // We could use SoftBLAS set_rounding() to set the SoftFloat
+ // mode as well, but it's more explicit to do it here since
+ // we may use SoftFloat in any given Lagoon jet and we want
+ // you, dear developer, to see it set here.
+ switch ( a )
+ {
+ default:
+ u3m_bail(c3__fail);
+ break;
+ // %n - near
+ case c3__n:
+ softfloat_roundingMode = softfloat_round_near_even;
+ softblas_roundingMode = 'n';
+ break;
+ // %z - zero
+ case c3__z:
+ softfloat_roundingMode = softfloat_round_minMag;
+ softblas_roundingMode = 'z';
+ break;
+ // %u - up
+ case c3__u:
+ softfloat_roundingMode = softfloat_round_max;
+ softblas_roundingMode = 'u';
+ break;
+ // %d - down
+ case c3__d:
+ softfloat_roundingMode = softfloat_round_min;
+ softblas_roundingMode = 'd';
+ break;
+ // %a - away
+ case c3__a:
+ softfloat_roundingMode = softfloat_round_near_maxMag;
+ softblas_roundingMode = 'a';
+ break;
+ }
+ }
+
+/* length of shape = x * y * z * w * ...
+*/
+ static inline c3_d _get_length(u3_noun shape)
+ {
+ c3_d len = 1;
+ while (u3_nul != shape) {
+ len = len * u3x_atom(u3h(shape));
+ shape = u3t(shape);
+ }
+ return len;
+ }
+
+/* get dims from shape as array [x y z w ...]
+*/
+ static inline c3_d* _get_dims(u3_noun shape)
+ {
+ u3_atom len = u3qb_lent(shape);
+ c3_d len_d = u3r_chub(0, len);
+ c3_d* dims = (c3_d*)u3a_malloc(len_d*sizeof(c3_d));
+ for (c3_d i = 0; i < len_d; i++) {
+ dims[i] = u3r_chub(0, u3x_atom(u3h(shape)));
+ shape = u3t(shape);
+ }
+ u3z(len);
+ return dims;
+ }
+
+/* check consistency of array shape and bloq size
+ |= =ray
+ ^- ?
+ .= (roll shape.meta.ray ^mul)
+ (dec (met bloq.meta.ray data.ray))
+*/
+ static inline c3_o _check(u3_noun ray)
+ {
+ // Calculate expected size.
+ u3_atom shp = u3h(u3h(ray)); // (reported) shape of ray, +4
+ u3_atom blq = u3h(u3t(u3h(ray))); // block size of ray, +10
+ u3_atom sin = _get_length(shp); // calculated length of ray
+
+ // Calculate actual size.
+ u3_atom len = u3r_met(blq, u3t(ray)); // length of ray
+ u3_atom dex = u3qa_dec(len); // decrement length b/c of pinned 1
+
+ return __(sin == dex);
+ }
+
+/* add - axpy = 1*x+y
+*/
+ u3_noun
+ u3qi_la_add_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq
+ )
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1);
+ break;
+
+ case 5:
+ saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1);
+ break;
+
+ case 6:
+ daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1);
+ break;
+
+ case 7:
+ qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* sub - axpy = -1*y+x
+*/
+ u3_noun
+ u3qi_la_sub_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq
+ )
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1);
+ break;
+
+ case 5:
+ saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1);
+ break;
+
+ case 6:
+ daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1);
+ break;
+
+ case 7:
+ qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+
+/* mul - x.*y
+ elementwise multiplication
+*/
+ u3_noun
+ u3qi_la_mul_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float16_t*)y_bytes)[i] = f16_mul(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float32_t*)y_bytes)[i] = f32_mul(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float64_t*)y_bytes)[i] = f64_mul(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ f128M_mul(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i]));
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* div - x/y
+ elementwise division
+*/
+ u3_noun
+ u3qi_la_div_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float16_t*)y_bytes)[i] = f16_div(((float16_t*)x_bytes)[i], ((float16_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float32_t*)y_bytes)[i] = f32_div(((float32_t*)x_bytes)[i], ((float32_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float64_t*)y_bytes)[i] = f64_div(((float64_t*)x_bytes)[i], ((float64_t*)y_bytes)[i]);
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ f128M_div(&(((float128_t*)y_bytes)[i]), &(((float128_t*)x_bytes)[i]), &(((float128_t*)y_bytes)[i]));
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* mod - x % y = x - r*floor(x/r)
+ remainder after division
+*/
+ u3_noun
+ u3qi_la_mod_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ float16_t y_val16 = ((float16_t*)y_bytes)[i];
+ // Perform division x/n
+ float16_t div_result16 = f16_div(x_val16, y_val16);
+ // Compute floor of the division result
+ c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false);
+ float16_t floor_float16 = i64_to_f16(floor_result16);
+ // Multiply n by floor(x/n)
+ float16_t mult_result16 = f16_mul(y_val16, floor_float16);
+ // Compute remainder: x - n * floor(x/n)
+ ((float16_t*)y_bytes)[i] = f16_sub(x_val16, mult_result16);
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ float32_t y_val32 = ((float32_t*)y_bytes)[i];
+ // Perform division x/n
+ float32_t div_result32 = f32_div(x_val32, y_val32);
+ // Compute floor of the division result
+ c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false);
+ float32_t floor_float32 = i64_to_f32(floor_result32);
+ // Multiply n by floor(x/n)
+ float32_t mult_result32 = f32_mul(y_val32, floor_float32);
+ // Compute remainder: x - n * floor(x/n)
+ ((float32_t*)y_bytes)[i] = f32_sub(x_val32, mult_result32);
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ float64_t y_val64 = ((float64_t*)y_bytes)[i];
+ // Perform division x/n
+ float64_t div_result64 = f64_div(x_val64, y_val64);
+ // Compute floor of the division result
+ c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false);
+ float64_t floor_float64 = i64_to_f64(floor_result64);
+ // Multiply n by floor(x/n)
+ float64_t mult_result64 = f64_mul(y_val64, floor_float64);
+ // Compute remainder: x - n * floor(x/n)
+ ((float64_t*)y_bytes)[i] = f64_sub(x_val64, mult_result64);
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ float128_t y_val128 = ((float128_t*)y_bytes)[i];
+ // Perform division x/n
+ float128_t div_result128;
+ f128M_div((float128_t*)&x_val128, (float128_t*)&y_val128, (float128_t*)&div_result128);
+ // Compute floor of the division result
+ c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false);
+ float128_t floor_float128;
+ i64_to_f128M(floor_result128, &floor_float128);
+ // Multiply n by floor(x/n)
+ float128_t mult_result128;
+ f128M_mul(((float128_t*)&y_val128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128));
+ // Compute remainder: x - n * floor(x/n)
+ f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)y_bytes)[i]));
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* cumsum - x[0] + x[1] + ... x[n]
+*/
+ u3_noun
+ u3qi_la_cumsum_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by for range)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+
+ u3_noun r_data;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t sum16[2];
+ sum16[0] = (float16_t){SB_REAL16_ZERO};
+ for (c3_d i = len_x; i > 0; i--) {
+ sum16[0] = f16_add(sum16[0], ((float16_t*)x_bytes)[i-1]);
+ }
+ sum16[1].v = 0x1;
+ r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)sum16);
+ break;}
+
+ case 5: {
+ float32_t sum32[2];
+ sum32[0] = (float32_t){SB_REAL32_ZERO};
+ for (c3_d i = len_x; i > 0; i--) {
+ sum32[0] = f32_add(sum32[0], ((float32_t*)x_bytes)[i-1]);
+ }
+ sum32[1].v = 0x1;
+ r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)sum32);
+ break;}
+
+ case 6: {
+ float64_t sum64[2];
+ sum64[0] = (float64_t){SB_REAL64_ZERO};
+ for (c3_d i = len_x; i > 0; i--) {
+ sum64[0] = f64_add(sum64[0], ((float64_t*)x_bytes)[i-1]);
+ }
+ sum64[1].v = 0x1;
+ r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)sum64);
+ break;}
+
+ case 7: {
+ float128_t sum128[2];
+ sum128[0] = (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO};
+ for (c3_d i = len_x; i > 0; i--) {
+ f128M_add(&(sum128[0]), &(((float128_t*)x_bytes)[i-1]), &(sum128[0]));
+ }
+ sum128[1] = (float128_t){0x1, 0x0};
+ r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)sum128);
+ break;}
+ }
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* argmin - argmin(x)
+*/
+ u3_noun
+ u3qi_la_argmin_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1, which doesn't matter here)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ c3_w min_idx = 0;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t min_val16 = ((float16_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f16_lt(((float16_t*)x_bytes)[i], min_val16)) {
+ min_val16 = ((float16_t*)x_bytes)[i];
+ min_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 5: {
+ float32_t min_val32 = ((float32_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f32_lt(((float32_t*)x_bytes)[i], min_val32)) {
+ min_val32 = ((float32_t*)x_bytes)[i];
+ min_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 6: {
+ float64_t min_val64 = ((float64_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f64_lt(((float64_t*)x_bytes)[i], min_val64)) {
+ min_val64 = ((float64_t*)x_bytes)[i];
+ min_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 7: {
+ float128_t min_val128 = ((float128_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f128M_lt(&(((float128_t*)x_bytes)[i]), &min_val128)) {
+ min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]);
+ min_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+ }
+
+ u3_noun r_data = u3i_chub(min_idx);
+
+ return r_data;
+ }
+
+/* argmax - argmax(x)
+*/
+ u3_noun
+ u3qi_la_argmax_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1, which doesn't matter here)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ c3_w max_idx = 0;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t max_val16 = ((float16_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f16_gt(((float16_t*)x_bytes)[i], max_val16)) {
+ max_val16 = ((float16_t*)x_bytes)[i];
+ max_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 5: {
+ float32_t max_val32 = ((float32_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f32_gt(((float32_t*)x_bytes)[i], max_val32)) {
+ max_val32 = ((float32_t*)x_bytes)[i];
+ max_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 6: {
+ float64_t max_val64 = ((float64_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f64_gt(((float64_t*)x_bytes)[i], max_val64)) {
+ max_val64 = ((float64_t*)x_bytes)[i];
+ max_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+
+ case 7: {
+ float128_t max_val128 = ((float128_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ if(f128M_gt(&(((float128_t*)x_bytes)[i]), &max_val128)) {
+ max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]);
+ max_idx = (len_x - i - 1);
+ }
+ }
+ break;}
+ }
+
+ u3_noun r_data = u3i_chub(max_idx);
+
+ return r_data;
+ }
+
+/* ravel - x -> ~[x[0], x[1], ... x[n]]
+ entire nd-array busted out as a linear list
+*/
+ u3_noun
+ u3qi_la_ravel_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3_nul;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ r_data = u3nc(u3i_word(x_val16.v), r_data);
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ r_data = u3nc(u3i_word(x_val32.v), r_data);
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ r_data = u3nc(u3i_chub(x_val64.v), r_data);
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ r_data = u3nc(u3i_chubs(2, (c3_d*)&(x_val128.v)), r_data);
+ }
+ break;
+ }
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* min - min(x,y)
+*/
+ u3_noun
+ u3qi_la_min_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by for range)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+
+ u3_noun r_data;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t min_val16 = ((float16_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ min_val16 = f16_min(min_val16, ((float16_t*)x_bytes)[i]);
+ }
+ float16_t r16[2];
+ r16[0] = min_val16;
+ r16[1].v = 0x1;
+ r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16);
+ break;}
+
+ case 5: {
+ float32_t min_val32 = ((float32_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ min_val32 = f32_min(min_val32, ((float32_t*)x_bytes)[i]);
+ }
+ float32_t r32[2];
+ r32[0] = min_val32;
+ r32[1].v = 0x1;
+ r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32);
+ break;}
+
+ case 6: {
+ float64_t min_val64 = ((float64_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ min_val64 = f64_min(min_val64, ((float64_t*)x_bytes)[i]);
+ }
+ float64_t r64[2];
+ r64[0] = min_val64;
+ r64[1].v = 0x1;
+ r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64);
+ break;}
+
+ case 7: {
+ float128_t min_val128 = ((float128_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ min_val128 = *f128M_min(&min_val128, &((float128_t*)x_bytes)[i]);
+ }
+ float128_t r128[2];
+ r128[0] = min_val128;
+ r128[1] = (float128_t){0x1, 0x0};
+ r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128);
+ break;}
+ }
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* max - max(x,y)
+*/
+ u3_noun
+ u3qi_la_max_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by for range)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+
+ u3_noun r_data;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t max_val16 = ((float16_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ max_val16 = f16_max(max_val16, ((float16_t*)x_bytes)[i]);
+ }
+ float16_t r16[2];
+ r16[0] = max_val16;
+ r16[1].v = 0x1;
+ r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16);
+ break;}
+
+ case 5: {
+ float32_t max_val32 = ((float32_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ max_val32 = f32_max(max_val32, ((float32_t*)x_bytes)[i]);
+ }
+ float32_t r32[2];
+ r32[0] = max_val32;
+ r32[1].v = 0x1;
+ r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32);
+ break;}
+
+ case 6: {
+ float64_t max_val64 = ((float64_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ max_val64 = f64_max(max_val64, ((float64_t*)x_bytes)[i]);
+ }
+ float64_t r64[2];
+ r64[0] = max_val64;
+ r64[1].v = 0x1;
+ r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64);
+ break;}
+
+ case 7: {
+ float128_t max_val128 = ((float128_t*)x_bytes)[0];
+ for (c3_d i = 0; i < len_x; i++) {
+ max_val128 = *f128M_max(&max_val128, &((float128_t*)x_bytes)[i]);
+ }
+ float128_t r128[2];
+ r128[0] = max_val128;
+ r128[1] = (float128_t){0x1, 0x0};
+ r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128);
+ break;}
+ }
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* abs - |x|
+*/
+ u3_noun
+ u3qi_la_abs_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by for range)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float16_t*)x_bytes)[i] = f16_abs(((float16_t*)x_bytes)[i]);
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float32_t*)x_bytes)[i] = f32_abs(((float32_t*)x_bytes)[i]);
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float64_t*)x_bytes)[i] = f64_abs(((float64_t*)x_bytes)[i]);
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float128_t*)x_bytes)[i] = f128_abs(((float128_t*)x_bytes)[i]);
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* gth - x > y
+*/
+ u3_noun
+ u3qi_la_gth_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ float16_t y_val16 = ((float16_t*)y_bytes)[i];
+ ((float16_t*)y_bytes)[i] = f16_gt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO};
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ float32_t y_val32 = ((float32_t*)y_bytes)[i];
+ ((float32_t*)y_bytes)[i] = f32_gt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO};
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ float64_t y_val64 = ((float64_t*)y_bytes)[i];
+ ((float64_t*)y_bytes)[i] = f64_gt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO};
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ float128_t y_val128 = ((float128_t*)y_bytes)[i];
+ ((float128_t*)y_bytes)[i] = f128M_gt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO};
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* gte - x > y
+*/
+ u3_noun
+ u3qi_la_gte_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ float16_t y_val16 = ((float16_t*)y_bytes)[i];
+ ((float16_t*)y_bytes)[i] = f16_ge(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO};
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ float32_t y_val32 = ((float32_t*)y_bytes)[i];
+ ((float32_t*)y_bytes)[i] = f32_ge(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO};
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ float64_t y_val64 = ((float64_t*)y_bytes)[i];
+ ((float64_t*)y_bytes)[i] = f64_ge(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO};
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ float128_t y_val128 = ((float128_t*)y_bytes)[i];
+ ((float128_t*)y_bytes)[i] = f128M_ge(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO};
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* lth - x > y
+*/
+ u3_noun
+ u3qi_la_lth_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ float16_t y_val16 = ((float16_t*)y_bytes)[i];
+ ((float16_t*)y_bytes)[i] = f16_lt(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO};
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ float32_t y_val32 = ((float32_t*)y_bytes)[i];
+ ((float32_t*)y_bytes)[i] = f32_lt(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO};
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ float64_t y_val64 = ((float64_t*)y_bytes)[i];
+ ((float64_t*)y_bytes)[i] = f64_lt(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO};
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ float128_t y_val128 = ((float128_t*)y_bytes)[i];
+ ((float128_t*)y_bytes)[i] = f128M_lt(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO};
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* lte - x > y
+*/
+ u3_noun
+ u3qi_la_lte_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ float16_t y_val16 = ((float16_t*)y_bytes)[i];
+ ((float16_t*)y_bytes)[i] = f16_le(x_val16, y_val16) ? (float16_t){SB_REAL16_ONE} : (float16_t){SB_REAL16_ZERO};
+ }
+ break;
+
+ case 5:
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ float32_t y_val32 = ((float32_t*)y_bytes)[i];
+ ((float32_t*)y_bytes)[i] = f32_le(x_val32, y_val32) ? (float32_t){SB_REAL32_ONE} : (float32_t){SB_REAL32_ZERO};
+ }
+ break;
+
+ case 6:
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ float64_t y_val64 = ((float64_t*)y_bytes)[i];
+ ((float64_t*)y_bytes)[i] = f64_le(x_val64, y_val64) ? (float64_t){SB_REAL64_ONE} : (float64_t){SB_REAL64_ZERO};
+ }
+ break;
+
+ case 7:
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ float128_t y_val128 = ((float128_t*)y_bytes)[i];
+ ((float128_t*)y_bytes)[i] = f128M_le(((float128_t*)&x_val128), ((float128_t*)&y_val128)) ? (float128_t){SB_REAL128L_ONE, SB_REAL128U_ONE} : (float128_t){SB_REAL128L_ZERO, SB_REAL128U_ZERO};
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* adds - axpy = 1*x+[n]
+*/
+ u3_noun
+ u3qi_la_adds_i754(u3_noun x_data,
+ u3_noun n,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+
+ float16_t n16;
+ float32_t n32;
+ float64_t n64;
+ float128_t n128;
+
+ // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ u3r_bytes(0, 2, (c3_y*)&(n16.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float16_t*)y_bytes)[i] = n16;
+ }
+ haxpy(len_x, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1);
+ break;
+
+ case 5:
+ u3r_bytes(0, 4, (c3_y*)&(n32.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float32_t*)y_bytes)[i] = n32;
+ }
+ saxpy(len_x, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1);
+ break;
+
+ case 6:
+ u3r_bytes(0, 8, (c3_y*)&(n64.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float64_t*)y_bytes)[i] = n64;
+ }
+ daxpy(len_x, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1);
+ break;
+
+ case 7:
+ u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]};
+ }
+ qaxpy(len_x, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ y_bytes[syz_x] = 0x1; // pin head
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* subs - axpy = -1*[n]+x
+*/
+ u3_noun
+ u3qi_la_subs_i754(u3_noun x_data,
+ u3_noun n,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/o leading 0x1)
+ c3_y* y_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+
+ float16_t n16;
+ float32_t n32;
+ float64_t n64;
+ float128_t n128;
+
+ // Switch on the block size. We assume that n fits in the target block size; Hoon typecheck should prevent.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ u3r_bytes(0, 2, (c3_y*)&(n16.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float16_t*)y_bytes)[i] = n16;
+ }
+ haxpy(len_x, (float16_t){SB_REAL16_NEGONE}, (float16_t*)y_bytes, 1, (float16_t*)x_bytes, 1);
+ break;
+
+ case 5:
+ u3r_bytes(0, 4, (c3_y*)&(n32.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float32_t*)y_bytes)[i] = n32;
+ }
+ saxpy(len_x, (float32_t){SB_REAL32_NEGONE}, (float32_t*)y_bytes, 1, (float32_t*)x_bytes, 1);
+ break;
+
+ case 6:
+ u3r_bytes(0, 8, (c3_y*)&(n64.v), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float64_t*)y_bytes)[i] = n64;
+ }
+ daxpy(len_x, (float64_t){SB_REAL64_NEGONE}, (float64_t*)y_bytes, 1, (float64_t*)x_bytes, 1);
+ break;
+
+ case 7:
+ u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n);
+ // set y to [n]
+ for (c3_d i = 0; i < len_x; i++) {
+ ((float128_t*)y_bytes)[i] = (float128_t){n128.v[0], n128.v[1]};
+ }
+ qaxpy(len_x, (float128_t){SB_REAL128L_NEGONE,SB_REAL128U_NEGONE}, (float128_t*)y_bytes, 1, (float128_t*)x_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ x_bytes[syz_x] = 0x1; // pin head
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* muls - ?scal n * x
+ elementwise multiplication
+*/
+ u3_noun
+ u3qi_la_muls_i754(u3_noun x_data,
+ u3_noun n,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+ x_bytes[syz_x] = 0x1; // pin head
+
+ float16_t n16;
+ float32_t n32;
+ float64_t n64;
+ float128_t n128;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ u3r_bytes(0, 2, (c3_y*)&(n16.v), n);
+ hscal(len_x, n16, (float16_t*)x_bytes, 1);
+ break;
+
+ case 5:
+ u3r_bytes(0, 4, (c3_y*)&(n32.v), n);
+ sscal(len_x, n32, (float32_t*)x_bytes, 1);
+ break;
+
+ case 6:
+ u3r_bytes(0, 8, (c3_y*)&(n64.v), n);
+ dscal(len_x, n64, (float64_t*)x_bytes, 1);
+ break;
+
+ case 7:
+ u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n);
+ qscal(len_x, n128, (float128_t*)x_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* divs - ?scal 1/n * x
+ elementwise division
+*/
+ u3_noun
+ u3qi_la_divs_i754(u3_noun x_data,
+ u3_noun n,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+ x_bytes[syz_x] = 0x1; // pin head
+
+ float16_t in16;
+ float32_t in32;
+ float64_t in64;
+ float128_t in128;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ // XX note that in16 is doing double duty here
+ u3r_bytes(0, 2, (c3_y*)&(in16.v), n);
+ in16 = f16_div((float16_t){SB_REAL16_ONE}, in16);
+ hscal(len_x, in16, (float16_t*)x_bytes, 1);
+ break;
+
+ case 5:
+ // XX note that in32 is doing double duty here
+ u3r_bytes(0, 4, (c3_y*)&(in32.v), n);
+ in32 = f32_div((float32_t){SB_REAL32_ONE}, in32);
+ sscal(len_x, in32, (float32_t*)x_bytes, 1);
+ break;
+
+ case 6:
+ // XX note that in64 is doing double duty here
+ u3r_bytes(0, 8, (c3_y*)&(in64.v), n);
+ in64 = f64_div((float64_t){SB_REAL64_ONE}, in64);
+ dscal(len_x, in64, (float64_t*)x_bytes, 1);
+ break;
+
+ case 7:
+ // XX note that in128 is doing double duty here
+ u3r_bytes(0, 16, (c3_y*)&(in128.v[0]), n);
+ f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}), &in128, &in128);
+ qscal(len_x, in128, (float128_t*)x_bytes, 1);
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* mods - x % [n] = x - r*floor(x/r)
+ remainder after scalar division
+*/
+ u3_noun
+ u3qi_la_mods_i754(u3_noun x_data,
+ u3_noun n,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ // we reuse it for results for parsimony
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+
+ float16_t n16, in16;
+ float32_t n32, in32;
+ float64_t n64, in64;
+ float128_t n128, in128;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ u3r_bytes(0, 2, (c3_y*)&(n16.v), n);
+ in16 = f16_div((float16_t){SB_REAL16_ONE}, n16);
+
+ for (c3_d i = 0; i < len_x; i++) {
+ float16_t x_val16 = ((float16_t*)x_bytes)[i];
+ // Perform division x/n
+ float16_t div_result16 = f16_mul(in16, x_val16);
+ // Compute floor of the division result
+ c3_ds floor_result16 = f16_to_i64(div_result16, softfloat_round_minMag, false);
+ float16_t floor_float16 = i64_to_f16(floor_result16);
+ // Multiply n by floor(x/n)
+ float16_t mult_result16 = f16_mul(n16, floor_float16);
+ // Compute remainder: x - n * floor(x/n)
+ ((float16_t*)x_bytes)[i] = f16_sub(x_val16, mult_result16);
+ }
+ break;
+
+ case 5:
+ u3r_bytes(0, 4, (c3_y*)&(n32.v), n);
+ in32 = f32_div((float32_t){SB_REAL32_ONE}, n32);
+
+ for (c3_d i = 0; i < len_x; i++) {
+ float32_t x_val32 = ((float32_t*)x_bytes)[i];
+ // Perform division x/n
+ float32_t div_result32 = f32_mul(in32, x_val32);
+ // Compute floor of the division result
+ c3_ds floor_result32 = f32_to_i64(div_result32, softfloat_round_minMag, false);
+ float32_t floor_float32 = i64_to_f32(floor_result32);
+ // Multiply n by floor(x/n)
+ float32_t mult_result32 = f32_mul(n32, floor_float32);
+ // Compute remainder: x - n * floor(x/n)
+ ((float32_t*)x_bytes)[i] = f32_sub(x_val32, mult_result32);
+ }
+ break;
+
+ case 6:
+ u3r_bytes(0, 8, (c3_y*)&(n64.v), n);
+ in64 = f64_div((float64_t){SB_REAL64_ONE}, n64);
+
+ for (c3_d i = 0; i < len_x; i++) {
+ float64_t x_val64 = ((float64_t*)x_bytes)[i];
+ // Perform division x/n
+ float64_t div_result64 = f64_mul(in64, x_val64);
+ // Compute floor of the division result
+ c3_ds floor_result64 = f64_to_i64(div_result64, softfloat_round_minMag, false);
+ float64_t floor_float64 = i64_to_f64(floor_result64);
+ // Multiply n by floor(x/n)
+ float64_t mult_result64 = f64_mul(n64, floor_float64);
+ // Compute remainder: x - n * floor(x/n)
+ ((float64_t*)x_bytes)[i] = f64_sub(x_val64, mult_result64);
+ }
+ break;
+
+ case 7:
+ u3r_bytes(0, 16, (c3_y*)&(n128.v[0]), n);
+ f128M_div(&((float128_t){SB_REAL128L_ONE,SB_REAL128U_ZERO}), &n128, &in128);
+
+ for (c3_d i = 0; i < len_x; i++) {
+ float128_t x_val128 = ((float128_t*)x_bytes)[i];
+ // Perform division x/n
+ float128_t div_result128;
+ f128M_mul((float128_t*)&in128, (float128_t*)&x_val128, (float128_t*)&div_result128);
+ // Compute floor of the division result
+ c3_ds floor_result128 = f128M_to_i64(&div_result128, softfloat_round_minMag, false);
+ float128_t floor_float128;
+ i64_to_f128M(floor_result128, &floor_float128);
+ // Multiply n by floor(x/n)
+ float128_t mult_result128;
+ f128M_mul(((float128_t*)&n128), ((float128_t*)&floor_float128), ((float128_t*)&mult_result128));
+ // Compute remainder: x - n * floor(x/n)
+ f128M_sub(((float128_t*)&x_val128), ((float128_t*)&mult_result128), &(((float128_t*)x_bytes)[i]));
+ }
+ break;
+ }
+
+ // r_data is the result noun of [data]
+ u3_noun r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), x_bytes);
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+
+ return r_data;
+ }
+
+/* dot - ?dot = x · y
+*/
+ u3_noun
+ u3qi_la_dot_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(shape);
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3);
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // y_bytes is the data array (w/ leading 0x1, skipped by ?axpy)
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, y_bytes, y_data);
+
+ u3_noun r_data;
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t r16[2];
+ r16[0] = hdot(len_x, (float16_t*)x_bytes, 1, (float16_t*)y_bytes, 1);
+ r16[1].v = 0x1;
+ r_data = u3i_bytes((2+1)*sizeof(c3_y), (c3_y*)r16);
+ break;}
+
+ case 5: {
+ float32_t r32[2];
+ r32[0] = sdot(len_x, (float32_t*)x_bytes, 1, (float32_t*)y_bytes, 1);
+ r32[1].v = 0x1;
+ r_data = u3i_bytes((4+1)*sizeof(c3_y), (c3_y*)r32);
+ break;}
+
+ case 6: {
+ float64_t r64[2];
+ r64[0] = ddot(len_x, (float64_t*)x_bytes, 1, (float64_t*)y_bytes, 1);
+ r64[1].v = 0x1;
+ r_data = u3i_bytes((8+1)*sizeof(c3_y), (c3_y*)r64);
+ break;}
+
+ case 7: {
+ float128_t r128[2];
+ r128[0] = qdot(len_x, (float128_t*)x_bytes, 1, (float128_t*)y_bytes, 1);
+ r128[1] = (float128_t){0x1, 0x0};
+ r_data = u3i_bytes((16+1)*sizeof(c3_y), (c3_y*)r128);
+ break;}
+ }
+
+ // Clean up and return.
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+
+ return r_data;
+ }
+
+/* diag - diag(x)
+*/
+ u3_noun
+ u3qi_la_diag(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+ // Assert length of dims is 2.
+ if (u3qb_lent(shape) != 2) {
+ return u3m_bail(c3__exit);
+ }
+ // Unpack shape into an array of dimensions.
+ c3_d *dims = _get_dims(shape);
+ if (dims[0] != dims[1]) {
+ return u3m_bail(c3__exit);
+ }
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ c3_d len_x = _get_length(shape);
+ c3_d syz_x = len_x * pow(2, bloq - 3);
+ c3_d wyd = pow(2, bloq - 3);
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+ c3_d syz_y = wyd * dims[1];
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_y+1)*sizeof(c3_y));
+
+ u3_noun r_data;
+
+ // Grab the index at i*n_x+j in bytes; put it at j.
+ for (c3_d i = 0; i < dims[1]; i++) {
+ // Scan across whole field width.
+ for (c3_y k = 0; k < wyd; k++) {
+ y_bytes[i*wyd+k] = x_bytes[(i*dims[0]+i)*wyd+k];
+ }
+ }
+ y_bytes[syz_y] = 0x1; // pin head
+
+ // Unpack the result back into a noun.
+ r_data = u3i_bytes((syz_y+1)*sizeof(c3_y), y_bytes);
+
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+ u3a_free(dims);
+
+ return r_data;
+ }
+
+/* transpose - x'
+*/
+ u3_noun
+ u3qi_la_transpose(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ // Assert length of dims is 2.
+ if (u3qb_lent(shape) != 2) {
+ return u3m_bail(c3__exit);
+ }
+ // Unpack shape into an array of dimensions.
+ c3_d *dims = _get_dims(shape);
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ c3_d len_x = _get_length(shape);
+ c3_d syz_x = len_x * pow(2, bloq - 3);
+ c3_d wyd = pow(2, bloq - 3);
+ c3_y* x_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+ u3r_bytes(0, syz_x+1, x_bytes, x_data);
+ c3_y* y_bytes = (c3_y*)u3a_malloc((syz_x+1)*sizeof(c3_y));
+
+ u3_noun r_data;
+
+ // Grab the index at i*n_x+j in bytes; put it at j.
+ for (c3_d i = 0; i < dims[1]; i++) {
+ for (c3_d j = 0; j < dims[0]; j++) {
+ // Scan across whole field width.
+ for (c3_y k = 0; k < wyd; k++) {
+ y_bytes[(j*dims[1]+i)*wyd+k] = x_bytes[(i*dims[0]+j)*wyd+k];
+ }
+ }
+ }
+ y_bytes[syz_x] = 0x1; // pin head
+
+ // Unpack the result back into a noun.
+ r_data = u3i_bytes((syz_x+1)*sizeof(c3_y), y_bytes);
+
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+ u3a_free(dims);
+
+ return r_data;
+ }
+
+/* linspace - [a a+(b-a)/n ... b]
+*/
+ u3_noun
+ u3qi_la_linspace_i754(u3_noun a,
+ u3_noun b,
+ u3_noun n,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ u3_noun r_data;
+
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t a16, b16;
+ u3r_bytes(0, 2, (c3_y*)&(a16.v), a);
+ u3r_bytes(0, 2, (c3_y*)&(b16.v), b);
+ float16_t span16 = f16_sub(b16, a16);
+ float16_t interval16 = f16_div(span16, i32_to_f16(n-1));
+ c3_y* x_bytes16 = (c3_y*)u3a_malloc((n*2+1)*sizeof(c3_y));
+ for (c3_d i = 1; i < n-1; i++) {
+ ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16));
+ }
+ // Assign in reverse order so that n=1 case is correctly left-hand bound.
+ ((float16_t*)x_bytes16)[n-1] = b16;
+ ((float16_t*)x_bytes16)[0] = a16;
+ x_bytes16[n*2] = 0x1; // pin head
+ r_data = u3i_bytes((n*2+1)*sizeof(c3_y), x_bytes16);
+ u3a_free(x_bytes16);
+ break;}
+
+ case 5: {
+ float32_t a32, b32;
+ u3r_bytes(0, 4, (c3_y*)&(a32.v), a);
+ u3r_bytes(0, 4, (c3_y*)&(b32.v), b);
+ float32_t span32 = f32_sub(b32, a32);
+ float32_t interval32 = f32_div(span32, i32_to_f32(n-1));
+ c3_y* x_bytes32 = (c3_y*)u3a_malloc((n*4+1)*sizeof(c3_y));
+ for (c3_d i = 1; i < n-1; i++) {
+ ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32));
+ }
+ ((float32_t*)x_bytes32)[n-1] = b32;
+ ((float32_t*)x_bytes32)[0] = a32;
+ x_bytes32[n*4] = 0x1; // pin head
+ r_data = u3i_bytes((n*4+1)*sizeof(c3_y), x_bytes32);
+ u3a_free(x_bytes32);
+ break;}
+
+ case 6: {
+ float64_t a64, b64;
+ u3r_bytes(0, 8, (c3_y*)&(a64.v), a);
+ u3r_bytes(0, 8, (c3_y*)&(b64.v), b);
+ float64_t span64 = f64_sub(b64, a64);
+ float64_t interval64 = f64_div(span64, i32_to_f64(n-1));
+ c3_y* x_bytes64 = (c3_y*)u3a_malloc((n*8+1)*sizeof(c3_y));
+ for (c3_d i = 1; i < n-1; i++) {
+ ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64));
+ }
+ ((float64_t*)x_bytes64)[n-1] = b64;
+ ((float64_t*)x_bytes64)[0] = a64;
+ x_bytes64[n*8] = 0x1; // pin head
+ r_data = u3i_bytes((n*8+1)*sizeof(c3_y), x_bytes64);
+ u3a_free(x_bytes64);
+ break;}
+
+ case 7: {
+ float128_t a128, b128;
+ u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a);
+ u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b);
+ float128_t span128;
+ f128M_sub(&b128, &a128, &span128);
+ float128_t interval128;
+ float128_t n128;
+ i32_to_f128M(n-1, &n128);
+ f128M_div(&span128, &n128, &interval128);
+ c3_y* x_bytes128 = (c3_y*)u3a_malloc((n*16+1)*sizeof(c3_y));
+ float128_t i128;
+ for (c3_d i = 1; i < n-1; i++) {
+ i32_to_f128M(i, &i128);
+ f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]);
+ f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]);
+ }
+ ((float128_t*)x_bytes128)[n-1] = b128;
+ ((float128_t*)x_bytes128)[0] = a128;
+ x_bytes128[n*16] = 0x1; // pin head
+ r_data = u3i_bytes((n*16+1)*sizeof(c3_y), x_bytes128);
+ u3a_free(x_bytes128);
+ break;}
+ }
+
+ return r_data;
+ }
+
+/* range - [a a+d ... b]
+*/
+ u3_noun
+ u3qi_la_range_i754(u3_noun a,
+ u3_noun b,
+ u3_noun d,
+ u3_noun bloq)
+ {
+ // Fence on valid bloq size.
+ if (bloq < 4 || bloq > 7) {
+ return u3_none;
+ }
+
+ u3_noun r_data;
+
+ switch (u3x_atom(bloq)) {
+ case 4: {
+ float16_t a16, b16, interval16;
+ u3r_bytes(0, 2, (c3_y*)&(a16.v), a);
+ u3r_bytes(0, 2, (c3_y*)&(b16.v), b);
+ u3r_bytes(0, 2, (c3_y*)&(interval16.v), d);
+ c3_d n16 = f16_to_i64(f16_ceil(f16_div(f16_sub(b16, a16), interval16)), softfloat_round_minMag, false);
+ c3_y* x_bytes16 = (c3_y*)u3a_malloc(((n16+1)*2)*sizeof(c3_y));
+ ((float16_t*)x_bytes16)[0] = a16;
+ for (c3_d i = 1; i < n16; i++) {
+ ((float16_t*)x_bytes16)[i] = f16_add(a16, f16_mul(i32_to_f16(i), interval16));
+ }
+ ((float16_t*)x_bytes16)[n16].v = 0x1; // pin head
+ r_data = u3i_bytes(((n16+1)*2)*sizeof(c3_y), x_bytes16);
+ u3a_free(x_bytes16);
+ break;}
+
+ case 5: {
+ float32_t a32, b32, interval32;
+ u3r_bytes(0, 4, (c3_y*)&(a32.v), a);
+ u3r_bytes(0, 4, (c3_y*)&(b32.v), b);
+ u3r_bytes(0, 4, (c3_y*)&(interval32.v), d);
+ c3_d n32 = f32_to_i64(f32_ceil(f32_div(f32_sub(b32, a32), interval32)), softfloat_round_minMag, false);
+ c3_y* x_bytes32 = (c3_y*)u3a_malloc(((n32+1)*4)*sizeof(c3_y));
+ ((float32_t*)x_bytes32)[0] = a32;
+ for (c3_d i = 1; i < n32; i++) {
+ ((float32_t*)x_bytes32)[i] = f32_add(a32, f32_mul(i32_to_f32(i), interval32));
+ }
+ ((float32_t*)x_bytes32)[n32].v = 0x1; // pin head
+ r_data = u3i_bytes(((n32+1)*4)*sizeof(c3_y), x_bytes32);
+ u3a_free(x_bytes32);
+ break;}
+
+ case 6: {
+ float64_t a64, b64, interval64;
+ u3r_bytes(0, 8, (c3_y*)&(a64.v), a);
+ u3r_bytes(0, 8, (c3_y*)&(b64.v), b);
+ u3r_bytes(0, 8, (c3_y*)&(interval64.v), d);
+ c3_d n64 = f64_to_i64(f64_ceil(f64_div(f64_sub(b64, a64), interval64)), softfloat_round_minMag, false);
+ c3_y* x_bytes64 = (c3_y*)u3a_malloc(((n64+1)*8)*sizeof(c3_y));
+ ((float64_t*)x_bytes64)[0] = a64;
+ for (c3_d i = 1; i < n64; i++) {
+ ((float64_t*)x_bytes64)[i] = f64_add(a64, f64_mul(i32_to_f64(i), interval64));
+ }
+ ((float64_t*)x_bytes64)[n64].v = 0x1; // pin head
+ r_data = u3i_bytes(((n64+1)*8)*sizeof(c3_y), x_bytes64);
+ u3a_free(x_bytes64);
+ break;}
+
+ case 7: {
+ float128_t a128, b128, interval128;
+ u3r_bytes(0, 16, (c3_y*)&(a128.v[0]), a);
+ u3r_bytes(0, 16, (c3_y*)&(b128.v[0]), b);
+ u3r_bytes(0, 16, (c3_y*)&(interval128.v[0]), d);
+ float128_t tmp;
+ f128M_sub(&b128, &a128, &tmp);
+ f128M_div(&tmp, &interval128, &tmp);
+ f128M_ceil(&tmp, &tmp);
+ c3_d n128 = f128M_to_i64(&tmp, softfloat_round_minMag, false);
+ c3_y* x_bytes128 = (c3_y*)u3a_malloc(((n128+1)*16)*sizeof(c3_y));
+ float128_t i128;
+ ((float128_t*)x_bytes128)[0] = a128;
+ for (c3_d i = 1; i < n128; i++) {
+ i32_to_f128M(i, &i128);
+ f128M_mul(&i128, &interval128, &((float128_t*)x_bytes128)[i]);
+ f128M_add(&a128, &((float128_t*)x_bytes128)[i], &((float128_t*)x_bytes128)[i]);
+ }
+ ((float128_t*)x_bytes128)[n128].v[0] = 0x1; // pin head
+ ((float128_t*)x_bytes128)[n128].v[1] = 0x0; // pin head
+ r_data = u3i_bytes(((n128+1)*16)*sizeof(c3_y), x_bytes128);
+ u3a_free(x_bytes128);
+ break;}
+ }
+
+ return r_data;
+ }
+
+/* trace - tr(x)
+*/
+ u3_noun
+ u3qi_la_trace_i754(u3_noun x_data,
+ u3_noun shape,
+ u3_noun bloq)
+ {
+ u3_noun d_data = u3qi_la_diag(x_data, shape, bloq);
+ c3_d len_x0 = _get_dims(shape)[0];
+ u3_noun r_data = u3qi_la_dot_i754(d_data, d_data, u3nt(len_x0, 0x1, u3_nul), u3k(bloq));
+ return r_data;
+ }
+
+/* mmul
+*/
+ u3_noun
+ u3qi_la_mmul_i754(u3_noun x_data,
+ u3_noun y_data,
+ u3_noun x_shape,
+ u3_noun y_shape,
+ u3_noun bloq)
+ {
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ c3_d M = u3x_atom(u3h(x_shape));
+ c3_d Na= u3x_atom(u3h(u3t(x_shape)));
+ c3_d Nb= u3x_atom(u3h(y_shape));
+ c3_d P = u3x_atom(u3h(u3t(y_shape)));
+
+ if ((u3_nul != u3t(u3t(x_shape))) ||
+ (u3_nul != u3t(u3t(y_shape))) ||
+ (Na != Nb)) {
+ return u3m_bail(c3__exit);
+ }
+ c3_d N = Na;
+
+ // Unpack the data as a byte array. We assume total length < 2**64.
+ // len_x is length in base units
+ c3_d len_x = _get_length(x_shape); // M*N
+
+ // syz_x is length in bytes
+ c3_d syz_x = len_x * pow(2, bloq-3); // M*N
+
+ // x_bytes is the data array (w/o leading 0x1)
+ c3_y* x_bytes = (c3_y*)u3a_malloc(syz_x*sizeof(c3_y));
+ u3r_bytes(0, syz_x, x_bytes, x_data);
+
+ // len_x is length in base units
+ c3_d len_y = _get_length(y_shape); // N*P
+
+ // syz_x is length in bytes
+ c3_d syz_y = len_y * pow(2, bloq-3); // N*P
+
+ // y_bytes is the data array (w/o leading 0x1)
+ c3_y* y_bytes = (c3_y*)u3a_malloc(syz_y*sizeof(c3_y));
+ u3r_bytes(0, syz_y, y_bytes, y_data);
+
+ // len_r is length in base units
+ c3_d len_r = M*P; // M*P
+
+ // syz_r is length in bytes
+ c3_d syz_r = len_r * pow(2, bloq-3); // M*P
+
+ // r_bytes is the result array
+ c3_y* r_bytes = (c3_y*)u3a_malloc((syz_r+1)*sizeof(c3_y));
+ r_bytes[syz_r] = 0x1; // pin head
+ // initialize with 0x0s
+ for (c3_d i = 0; i < syz_r; i++) {
+ r_bytes[i] = 0x0;
+ }
+
+ // Switch on the block size.
+ switch (u3x_atom(bloq)) {
+ case 4:
+ hgemm('N', 'N', M, N, P, (float16_t){SB_REAL16_ONE}, (float16_t*)x_bytes, N, (float16_t*)y_bytes, P, (float16_t){SB_REAL16_ZERO}, (float16_t*)r_bytes, P);
+ break;
+
+ case 5:
+ sgemm('N', 'N', M, N, P, (float32_t){SB_REAL32_ONE}, (float32_t*)x_bytes, N, (float32_t*)y_bytes, P, (float32_t){SB_REAL32_ZERO}, (float32_t*)r_bytes, P);
+ break;
+
+ case 6:
+ dgemm('N', 'N', M, N, P, (float64_t){SB_REAL64_ONE}, (float64_t*)x_bytes, N, (float64_t*)y_bytes, P, (float64_t){SB_REAL64_ZERO}, (float64_t*)r_bytes, P);
+ break;
+
+ case 7:
+ qgemm('N', 'N', M, N, P, (float128_t){SB_REAL128L_ONE,SB_REAL128U_ONE}, (float128_t*)x_bytes, N, (float128_t*)y_bytes, P, (float128_t){SB_REAL128L_ZERO,SB_REAL128U_ZERO}, (float128_t*)r_bytes, P);
+ break;
+ }
+
+ // Unpack the result back into a noun.
+ u3_noun r_data = u3i_bytes(syz_r+1, r_bytes);
+ u3_noun M_ = u3i_chub(M);
+ u3_noun P_ = u3i_chub(P);
+
+ u3a_free(x_bytes);
+ u3a_free(y_bytes);
+ u3a_free(r_bytes);
+
+ return u3nc(u3nq(u3nt(M_, P_, u3_nul), u3k(bloq), c3__i754, u3_nul), r_data);
+ }
+
+ u3_noun
+ u3wi_la_add(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(rnd)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_add_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_sub(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(rnd)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_sub_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_mul(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(rnd)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_mul_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_div(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(rnd)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_div_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_mod(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(rnd)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_mod_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_cumsum(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_cumsum_i754(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3nc(0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_argmin(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_argmin_i754(x_data, x_shape, x_bloq);
+ // bare atom (@ index)
+ return r_data;}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_ravel(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_ravel_i754(x_data, x_shape, x_bloq);
+ // (list @)
+ return r_data;}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_argmax(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_argmax_i754(x_data, x_shape, x_bloq);
+ // bare atom (@ index)
+ return r_data;}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_min(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_min_i754(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_max(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(u3nc(x_meta, x_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_max_i754(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_abs(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_abs_i754(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_gth(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_gth_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3k(x_meta), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_gte(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_gte_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3k(x_meta), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_lth(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_lth_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3k(x_meta), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_lte(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_lte_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3k(x_meta), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_adds(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data, n;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_3, &n,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(n) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_adds_i754(x_data, n, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_subs(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data, n;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_3, &n,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(n) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_subs_i754(x_data, n, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_muls(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data, n;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_3, &n,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(n) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_muls_i754(x_data, n, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_divs(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data, n;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_3, &n,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(n) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_divs_i754(x_data, n, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_mods(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data, n;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_3, &n,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(n) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_mods_i754(x_data, n, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_dot(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3r_sing(x_meta, y_meta) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_dot_i754(x_data, y_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ c3_d len_x0 = _get_dims(x_shape)[0];
+ return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_transpose(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(cor)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun r_data = u3qi_la_transpose(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3nt(u3k(u3h(x_shape)), u3k(u3h(u3t(x_shape))), u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_linspace(u3_noun cor)
+ {
+ u3_noun x_meta, a, b, n, rnd;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_12, &a,
+ u3x_sam_13, &b,
+ u3x_sam_7, &n,
+ 0))
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == u3ud(n) ||
+ (n < 1) // crash on zero size
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_linspace_i754(a, b, n, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ x_shape = u3nc(u3x_atom(n), u3_nul);
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_range(u3_noun cor)
+ {
+ u3_noun x_meta, a, b, d, rnd;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_12, &a,
+ u3x_sam_13, &b,
+ u3x_sam_7, &d,
+ 0))
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_range_i754(a, b, d, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ c3_d a_, b_, d_;
+ c3_ds n_;
+ switch (x_bloq) {
+ case 4:
+ u3r_bytes(0, 2, (c3_y*)&a_, a);
+ u3r_bytes(0, 2, (c3_y*)&b_, b);
+ u3r_bytes(0, 2, (c3_y*)&d_, d);
+ n_ = f16_to_i64(f16_ceil(f16_div(f16_sub((float16_t){b_}, (float16_t){a_}), (float16_t){d_})), softfloat_round_minMag, false) - 1;
+ break;
+ case 5:
+ u3r_bytes(0, 4, (c3_y*)&a_, a);
+ u3r_bytes(0, 4, (c3_y*)&b_, b);
+ u3r_bytes(0, 4, (c3_y*)&d_, d);
+ n_ = f32_to_i64(f32_ceil(f32_div(f32_sub((float32_t){b_}, (float32_t){a_}), (float32_t){d_})), softfloat_round_minMag, false) - 1;
+ break;
+ case 6:
+ u3r_bytes(0, 8, (c3_y*)&a_, a);
+ u3r_bytes(0, 8, (c3_y*)&b_, b);
+ u3r_bytes(0, 8, (c3_y*)&d_, d);
+ n_ = f64_to_i64(f64_ceil(f64_div(f64_sub((float64_t){b_}, (float64_t){a_}), (float64_t){d_})), softfloat_round_minMag, false) - 1;
+ break;
+ case 7: {
+ c3_d a__[2], b__[2], d__[2];
+ u3r_bytes(0, 16, (c3_y*)&a__, a);
+ u3r_bytes(0, 16, (c3_y*)&b__, b);
+ u3r_bytes(0, 16, (c3_y*)&d__, d);
+ float128_t tmp;
+ f128M_sub((float128_t*)&b__, (float128_t*)&a__, &tmp);
+ f128M_div(&tmp, (float128_t*)&d__, &tmp);
+ f128M_ceil(&tmp, &tmp);
+ n_ = f128M_to_i64(&tmp, softfloat_round_minMag, false) - 1;
+ break;}
+ }
+ u3_noun n = u3i_chub(n_+1);
+ x_shape = u3nc(u3k(n), u3_nul);
+ return u3nc(u3nq(u3k(x_shape), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_diag(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ x_tail = u3t(u3t(u3t(x_meta))); // 15
+ if ( c3n == u3ud(x_bloq) ||
+ c3n == u3ud(x_kind) ||
+ c3n == _check(cor)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun r_data = u3qi_la_diag(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ c3_d len_x0 = _get_dims(x_shape)[0];
+ return u3nc(u3nq(u3nt(len_x0, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_trace(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_2, &x_meta,
+ u3x_sam_3, &x_data,
+ 0) ||
+ c3n == u3ud(x_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind, x_tail;
+ if ( c3n == u3r_mean(x_meta,
+ 2, &x_shape,
+ 6, &x_bloq,
+ 14, &x_kind,
+ 15, &x_tail,
+ 0)
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754: {
+ u3_noun r_data = u3qi_la_trace_i754(x_data, x_shape, x_bloq);
+ if (r_data == u3_none) { return u3_none; }
+ return u3nc(u3nq(u3nt(0x1, 0x1, u3_nul), u3k(x_bloq), u3k(x_kind), u3k(x_tail)), r_data);}
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
+
+ u3_noun
+ u3wi_la_mmul(u3_noun cor)
+ {
+ // Each argument is a ray, [=meta data=@ux]
+ u3_noun x_meta, x_data,
+ y_meta, y_data;
+
+ if ( c3n == u3r_mean(cor,
+ u3x_sam_4, &x_meta,
+ u3x_sam_5, &x_data,
+ u3x_sam_6, &y_meta,
+ u3x_sam_7, &y_data,
+ 0) ||
+ c3n == u3ud(x_data) ||
+ c3n == u3ud(y_data) )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ u3_noun x_shape, x_bloq, x_kind,
+ y_shape,
+ rnd;
+ x_shape = u3h(x_meta); // 2
+ x_bloq = u3h(u3t(x_meta)); // 6
+ x_kind = u3h(u3t(u3t(x_meta))); // 14
+ y_shape = u3h(y_meta); // 2
+ rnd = u3h(u3t(u3t(u3t(cor)))); // 30
+ if ( c3n == _check(u3nc(x_meta, x_data)) ||
+ c3n == _check(u3nc(y_meta, y_data))
+ )
+ {
+ return u3m_bail(c3__exit);
+ } else {
+ switch (x_kind) {
+ case c3__i754:
+ _set_rounding(rnd);
+ u3_noun r_data = u3qi_la_mmul_i754(x_data, y_data, x_shape, y_shape, x_bloq);
+ // result is already [meta data]
+ return r_data;
+
+ default:
+ return u3_none;
+ }
+ }
+ }
+ }
diff --git a/vere/pkg/noun/jets/k.h b/vere/pkg/noun/jets/k.h
new file mode 100644
index 0000000..27733fb
--- /dev/null
+++ b/vere/pkg/noun/jets/k.h
@@ -0,0 +1,185 @@
+/// @file
+
+#ifndef U3_JETS_K_H
+#define U3_JETS_K_H
+
+#include "types.h"
+
+ /** Tier 1.
+ **/
+ u3_noun u3ka_add(u3_noun a, u3_noun b);
+ u3_noun u3ka_dec(u3_atom a);
+ u3_noun u3ka_div(u3_noun a, u3_noun b);
+ u3_noun u3ka_sub(u3_noun a, u3_noun b);
+ u3_noun u3ka_max(u3_noun a, u3_noun b);
+ u3_noun u3ka_min(u3_noun a, u3_noun b);
+ u3_noun u3ka_mod(u3_noun a, u3_noun b);
+ u3_noun u3ka_mul(u3_noun a, u3_noun b);
+ u3_noun u3ka_gth(u3_noun a, u3_noun b);
+ u3_noun u3ka_lte(u3_noun a, u3_noun b);
+
+ /** Tier 2.
+ **/
+ u3_noun u3kb_lent(u3_noun a);
+ u3_noun u3kb_weld(u3_noun a, u3_noun b);
+ u3_noun u3kb_flop(u3_noun a);
+
+/* u3kc: tier 3 functions
+*/
+ /* u3kc_bex(): binary exponent.
+ */
+ u3_noun
+ u3kc_bex(u3_atom);
+
+ /* u3kc_con(): binary loobean conjunction.
+ */
+ u3_noun
+ u3kc_con(u3_noun a,
+ u3_noun b);
+
+ /* u3kc_mix(): binary xor.
+ */
+ u3_noun
+ u3kc_mix(u3_atom a, u3_atom b);
+
+ /* u3kc_lsh(): left shift.
+ */
+ u3_noun
+ u3kc_lsh(u3_noun a, u3_noun b, u3_noun c);
+
+ /* u3kc_rsh(): right shift.
+ */
+ u3_noun
+ u3kc_rsh(u3_noun a, u3_noun b, u3_noun c);
+
+ /* u3kc_rep(): assemble single.
+ */
+ u3_noun
+ u3kc_rep(u3_atom a,
+ u3_atom b,
+ u3_noun c);
+
+ /* u3kc_rip(): disassemble.
+ */
+ u3_noun
+ u3kc_rip(u3_atom a,
+ u3_atom b,
+ u3_atom c);
+
+ /* u3kc_rev(): reverse block order, accounting for leading zeroes.
+ */
+ u3_noun
+ u3kc_rev(u3_atom boz, u3_atom len, u3_atom dat);
+
+ /* u3kc_swp(): reverse block order.
+ */
+ u3_noun
+ u3kc_swp(u3_atom a, u3_atom b);
+
+/* u3kd: tier 4 functions
+*/
+ /* u3kdb_get(): map get for key `b` in map `a` with u3_none.
+ */
+ u3_weak
+ u3kdb_get(u3_noun a, u3_noun b);
+
+ /* u3kdb_got(): map get for key `b` in map `a` with bail.
+ */
+ u3_noun
+ u3kdb_got(u3_noun a, u3_noun b);
+
+ /* u3kdb_put(): map put for key `b`, value `c` in map `a`.
+ */
+ u3_weak
+ u3kdb_put(u3_noun a, u3_noun b, u3_noun c);
+
+ /* u3kdb_del(): map del for key `b`
+ */
+ u3_weak
+ u3kdb_del(u3_noun a, u3_noun b);
+
+ /* u3kdb_has(): test for get.
+ */
+ u3_noun
+ u3kdb_has(u3_noun a, u3_noun b);
+
+ /* u3kdb_gas(): list to map.
+ */
+ u3_noun
+ u3kdb_gas(u3_noun a, u3_noun b);
+
+ /* u3kdb_uni(): map union.
+ */
+ u3_noun
+ u3kdb_uni(u3_noun a, u3_noun b);
+
+ /* u3kdi_gas(): list to map.
+ */
+ u3_noun
+ u3kdi_gas(u3_noun a, u3_noun b);
+
+ /* u3kdi_has(): test for presence.
+ */
+ u3_noun
+ u3kdi_has(u3_noun a, u3_noun b);
+
+ /* u3kdi_tap(): map/set convert to list. (solves by_tap also.)
+ */
+ u3_noun
+ u3kdi_tap(u3_noun a);
+
+ /* u3kdi_put(): put in set.
+ */
+ u3_weak
+ u3kdi_put(u3_noun a, u3_noun b);
+
+ /* u3kdi_uni(): set union.
+ */
+ u3_noun
+ u3kdi_uni(u3_noun a, u3_noun b);
+
+# define u3kdb_tap(a) u3kdi_tap(a)
+
+/* u3ke: tier 5 functions
+*/
+ /* u3ke_cue(): expand saved pill.
+ */
+ u3_noun
+ u3ke_cue(u3_atom a);
+
+ /* u3ke_jam(): pack noun as atom.
+ */
+ u3_atom
+ u3ke_jam(u3_noun a);
+
+ /* u3ke_trip(): atom to tape.
+ */
+ u3_noun
+ u3ke_trip(u3_noun a);
+
+ /* u3ke_json_de(): parse JSON from cord.
+ */
+ u3_noun
+ u3ke_json_de(u3_atom);
+
+ /* u3ke_json_en(): serialize JSON to cord.
+ */
+ u3_atom
+ u3ke_json_en(u3_noun);
+
+ /* u3kf_fork(): build %fork span.
+ */
+ u3_noun
+ u3kf_fork(u3_noun yed);
+
+ /* u3kz_fork(): build %fork span.
+ */
+ u3_noun
+ u3kz_fork(u3_noun yed);
+
+ /* u3kfu_repo():
+ */
+ u3_noun
+ u3kfu_repo(u3_noun, u3_noun);
+
+#endif /* ifndef U3_JETS_K_H */
diff --git a/vere/pkg/noun/jets/q.h b/vere/pkg/noun/jets/q.h
new file mode 100644
index 0000000..db1cfe1
--- /dev/null
+++ b/vere/pkg/noun/jets/q.h
@@ -0,0 +1,306 @@
+/// @file
+
+#ifndef U3_JETS_Q_H
+#define U3_JETS_Q_H
+
+#include "types.h"
+
+ /** Tier 1.
+ **/
+ u3_noun u3qa_add(u3_atom, u3_atom);
+ u3_noun u3qa_dec(u3_atom);
+ u3_noun u3qa_div(u3_atom, u3_atom);
+ u3_noun u3qa_gte(u3_atom, u3_atom);
+ u3_noun u3qa_gth(u3_atom, u3_atom);
+ u3_noun u3qa_inc(u3_atom);
+ u3_noun u3qa_lte(u3_atom, u3_atom);
+ u3_noun u3qa_lth(u3_atom, u3_atom);
+ u3_noun u3qa_max(u3_atom, u3_atom);
+ u3_noun u3qa_min(u3_atom, u3_atom);
+ u3_noun u3qa_mod(u3_atom, u3_atom);
+ u3_noun u3qa_mul(u3_atom, u3_atom);
+ u3_noun u3qa_sub(u3_atom, u3_atom);
+
+ /** Tier 2.
+ **/
+ u3_noun u3qb_bind(u3_noun, u3_noun);
+ u3_noun u3qb_clap(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qb_drop(u3_noun);
+ u3_noun u3qb_flop(u3_noun);
+ u3_noun u3qb_lent(u3_noun);
+ u3_noun u3qb_levy(u3_noun, u3_noun);
+ u3_noun u3qb_lien(u3_noun, u3_noun);
+ u3_noun u3qb_murn(u3_noun, u3_noun);
+ u3_noun u3qb_need(u3_noun);
+ u3_noun u3qb_mate(u3_noun, u3_noun);
+ u3_noun u3qb_reap(u3_atom, u3_noun);
+ u3_noun u3qb_reel(u3_noun, u3_noun);
+ u3_noun u3qb_roll(u3_noun, u3_noun);
+ u3_noun u3qb_skid(u3_noun, u3_noun);
+ u3_noun u3qb_skim(u3_noun, u3_noun);
+ u3_noun u3qb_skip(u3_noun, u3_noun);
+ u3_noun u3qb_scag(u3_atom, u3_noun);
+ u3_noun u3qb_slag(u3_atom, u3_noun);
+ u3_noun u3qb_snag(u3_atom, u3_noun);
+ u3_noun u3qb_sort(u3_noun, u3_noun);
+ u3_noun u3qb_turn(u3_noun, u3_noun);
+ u3_noun u3qb_weld(u3_noun, u3_noun);
+
+ /** Tier 3.
+ **/
+ u3_noun u3qc_aor(u3_atom, u3_atom);
+ u3_noun u3qc_bex(u3_atom);
+ u3_noun u3qc_xeb(u3_atom);
+ u3_noun u3qc_can(u3_atom, u3_noun);
+ u3_noun u3qc_cap(u3_atom);
+ u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_clz(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_con(u3_atom, u3_atom);
+ u3_noun u3qc_ctz(u3_atom);
+ u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_dis(u3_atom, u3_atom);
+ u3_noun u3qc_dor(u3_atom, u3_atom);
+ u3_noun u3qc_dvr(u3_atom, u3_atom);
+ u3_noun u3qc_end(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_gor(u3_atom, u3_atom);
+ u3_noun u3qc_ham(u3_atom);
+ u3_noun u3qc_hew(u3_atom, u3_atom, u3_atom, u3_noun);
+ u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_mas(u3_atom);
+ u3_noun u3qc_met(u3_atom, u3_atom);
+ u3_noun u3qc_mix(u3_atom, u3_atom);
+ u3_noun u3qc_mor(u3_atom, u3_atom);
+ u3_noun u3qc_muk(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_peg(u3_atom, u3_atom);
+ u3_noun u3qc_pow(u3_atom, u3_atom);
+ u3_noun u3qc_rap(u3_atom, u3_noun);
+ u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun);
+ u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_sew(u3_atom, u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qc_swp(u3_atom, u3_atom);
+ u3_noun u3qc_sqt(u3_atom);
+
+ c3_d u3qc_rig_s(c3_g, c3_w, c3_g);
+
+ u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three);
+ u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three);
+ void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c);
+ void u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c);
+
+ /** Tier 4.
+ **/
+ u3_noun u3qdb_all(u3_noun, u3_noun);
+ u3_noun u3qdb_any(u3_noun, u3_noun);
+ u3_noun u3qdb_apt(u3_noun);
+ u3_noun u3qdb_bif(u3_noun, u3_noun);
+ u3_noun u3qdb_del(u3_noun, u3_noun);
+ u3_noun u3qdb_dif(u3_noun, u3_noun);
+ u3_noun u3qdb_gas(u3_noun, u3_noun);
+ u3_noun u3qdb_get(u3_noun, u3_noun);
+ u3_noun u3qdb_has(u3_noun, u3_noun);
+ u3_noun u3qdb_int(u3_noun, u3_noun);
+ u3_noun u3qdb_key(u3_noun);
+ u3_noun u3qdb_put(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qdb_run(u3_noun, u3_noun);
+# define u3qdb_tap u3qdi_tap
+ u3_noun u3qdb_uni(u3_noun, u3_noun);
+ u3_noun u3qdb_urn(u3_noun, u3_noun);
+# define u3qdb_wyt u3qdi_wyt
+
+ u3_noun u3qdi_apt(u3_noun);
+ u3_noun u3qdi_bif(u3_noun, u3_noun);
+ u3_noun u3qdi_del(u3_noun, u3_noun);
+ u3_noun u3qdi_dif(u3_noun, u3_noun);
+ u3_noun u3qdi_gas(u3_noun, u3_noun);
+ u3_noun u3qdi_has(u3_noun, u3_noun);
+ u3_noun u3qdi_int(u3_noun, u3_noun);
+ u3_noun u3qdi_put(u3_noun, u3_noun);
+ u3_noun u3qdi_rep(u3_noun, u3_noun);
+ u3_noun u3qdi_run(u3_noun, u3_noun);
+ u3_noun u3qdi_tap(u3_noun);
+ u3_noun u3qdi_uni(u3_noun, u3_noun);
+ u3_noun u3qdi_wyt(u3_noun);
+
+ /** Tier 5.
+ **/
+ u3_noun u3qe_cue(u3_atom);
+ u3_noun u3qe_jam(u3_atom);
+ u3_noun u3qe_mat(u3_atom);
+ u3_noun u3qe_rub(u3_atom, u3_atom);
+ u3_noun u3qe_leer(u3_atom);
+ u3_noun u3qe_lore(u3_atom);
+ u3_noun u3qe_loss(u3_noun, u3_noun);
+ u3_noun u3qe_lune(u3_atom);
+ u3_noun u3qe_repg(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qe_rexp(u3_noun, u3_noun);
+ u3_noun u3qe_trip(u3_atom);
+
+ u3_atom u3qe_scot(u3_atom, u3_atom);
+ u3_atom u3qe_scow(u3_atom, u3_atom);
+
+ u3_noun u3qea_ecba_en(u3_atom, u3_atom);
+ u3_noun u3qea_ecba_de(u3_atom, u3_atom);
+ u3_noun u3qea_ecbb_en(u3_atom, u3_atom);
+ u3_noun u3qea_ecbb_de(u3_atom, u3_atom);
+ u3_noun u3qea_ecbc_en(u3_atom, u3_atom);
+ u3_noun u3qea_ecbc_de(u3_atom, u3_atom);
+
+ u3_noun u3qea_cbca_en(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qea_cbca_de(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qea_cbcb_en(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qea_cbcb_de(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qea_cbcc_en(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qea_cbcc_de(u3_atom, u3_atom, u3_atom);
+
+ u3_noun u3qea_de(u3_atom, u3_atom);
+ u3_noun u3qea_en(u3_atom, u3_atom);
+
+ u3_noun u3qee_recs(u3_atom);
+
+ u3_atom u3qe_fein_ob(u3_atom pyn);
+ u3_atom u3qe_fynd_ob(u3_atom pyn);
+
+ u3_noun u3qe_hmac(u3_noun, u3_atom, u3_atom,
+ u3_atom, u3_atom, u3_atom, u3_atom);
+
+ u3_noun u3qe_en_base16(u3_atom len, u3_atom dat);
+ u3_noun u3qe_de_base16(u3_atom inp);
+
+ u3_noun u3qe_json_de(u3_atom);
+ u3_atom u3qe_json_en(u3_noun);
+
+ u3_noun u3qeo_raw(u3_atom, u3_atom);
+
+ u3_noun u3qef_drg(u3_noun, u3_atom);
+ u3_noun u3qef_lug(u3_noun, u3_noun, u3_atom, u3_atom);
+
+ u3_noun u3qer_add(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qer_sub(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qer_mul(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qer_div(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qer_sqt(u3_atom, u3_atom);
+ u3_noun u3qer_fma(u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qer_lth(u3_atom, u3_atom);
+ u3_noun u3qer_lte(u3_atom, u3_atom);
+ u3_noun u3qer_equ(u3_atom, u3_atom);
+ u3_noun u3qer_gte(u3_atom, u3_atom);
+ u3_noun u3qer_gth(u3_atom, u3_atom);
+
+ u3_noun u3qet_add(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qet_sub(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qet_mul(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qet_div(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qet_sqt(u3_atom, u3_atom);
+ u3_noun u3qet_fma(u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qet_lth(u3_atom, u3_atom);
+ u3_noun u3qet_lte(u3_atom, u3_atom);
+ u3_noun u3qet_equ(u3_atom, u3_atom);
+ u3_noun u3qet_gte(u3_atom, u3_atom);
+ u3_noun u3qet_gth(u3_atom, u3_atom);
+
+ u3_noun u3qeq_add(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qeq_sub(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qeq_mul(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qeq_div(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qeq_sqt(u3_atom, u3_atom);
+ u3_noun u3qeq_fma(u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qeq_lth(u3_atom, u3_atom);
+ u3_noun u3qeq_lte(u3_atom, u3_atom);
+ u3_noun u3qeq_equ(u3_atom, u3_atom);
+ u3_noun u3qeq_gte(u3_atom, u3_atom);
+ u3_noun u3qeq_gth(u3_atom, u3_atom);
+
+ u3_noun u3qes_add(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qes_sub(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qes_mul(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qes_div(u3_atom, u3_atom, u3_atom);
+ u3_noun u3qes_sqt(u3_atom, u3_atom);
+ u3_noun u3qes_fma(u3_atom, u3_atom, u3_atom, u3_atom);
+ u3_noun u3qes_lth(u3_atom, u3_atom);
+ u3_noun u3qes_lte(u3_atom, u3_atom);
+ u3_noun u3qes_equ(u3_atom, u3_atom);
+ u3_noun u3qes_gte(u3_atom, u3_atom);
+ u3_noun u3qes_gth(u3_atom, u3_atom);
+
+ u3_noun u3qe_decompress_zlib(u3_atom, u3_noun);
+ u3_noun u3qe_decompress_gzip(u3_atom, u3_noun);
+
+ /** Tier 6.
+ **/
+ u3_noun u3qf_bull(u3_noun, u3_noun);
+ u3_noun u3qf_cell(u3_noun, u3_noun);
+ u3_noun u3qf_comb(u3_noun, u3_noun);
+ u3_noun u3qf_cons(u3_noun, u3_noun);
+ u3_noun u3qf_core(u3_noun, u3_noun);
+ u3_noun u3qf_cube(u3_noun, u3_noun);
+ u3_noun u3qf_face(u3_noun, u3_noun);
+ u3_noun u3qf_fine(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qf_fitz(u3_noun, u3_noun);
+ u3_noun u3qf_flay(u3_noun);
+ u3_noun u3qf_forq(u3_noun, u3_noun);
+ u3_noun u3qf_fork(u3_noun);
+ u3_noun u3qf_grof(u3_noun);
+ u3_noun u3qf_hint(u3_noun, u3_noun);
+ u3_noun u3qf_hike(u3_noun, u3_noun);
+ u3_noun u3qf_look(u3_noun, u3_noun);
+ u3_noun u3qf_loot(u3_noun, u3_noun);
+ u3_noun u3qf_slot(u3_atom, u3_noun);
+ u3_noun u3qf_type(u3_noun);
+
+ u3_noun u3qfl_bunt(u3_noun, u3_noun);
+ u3_noun u3qfl_whip(u3_noun, u3_noun, u3_noun);
+
+ u3_noun u3qfr_fish(u3_noun, u3_noun, u3_noun, u3_noun);
+
+ u3_noun u3qfp_hack(u3_noun, u3_noun);
+ u3_noun u3qfp_late(u3_noun);
+ u3_noun u3qfp_open(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qfp_nepo(u3_noun, u3_noun);
+ u3_noun u3qfp_rake(u3_noun);
+
+ u3_noun u3qi_la_add_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_sub_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_mul_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_div_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_mod_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_adds_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_subs_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_muls_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_divs_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_mods_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_dot_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_diag(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_transpose(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_cumsum_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_argmin_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_argmax_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_ravel_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_min_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_max_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_linspace_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_range_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_abs_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_gth_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_gte_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_lth_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_lte_i754(u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_trace_i754(u3_noun, u3_noun, u3_noun);
+ u3_noun u3qi_la_mmul_i754(u3_noun, u3_noun, u3_noun, u3_noun, u3_noun);
+
+# define u3qfu_van_fan 28
+# define u3qfu_van_rib 58
+# define u3qfu_van_vet 59
+
+ void u3qf_test(const c3_c*, u3_noun);
+
+
+ /** Tier 6.
+ **/
+ u3_noun u3qg_plot_fax(u3_noun, u3_noun);
+ u3_noun u3qg_plot_met(u3_noun, u3_noun);
+
+#endif /* ifndef U3_JETS_Q_H */
+
diff --git a/vere/pkg/noun/jets/tree.c b/vere/pkg/noun/jets/tree.c
new file mode 100644
index 0000000..1735f22
--- /dev/null
+++ b/vere/pkg/noun/jets/tree.c
@@ -0,0 +1,2658 @@
+/// @file
+
+/*
+ These hashes are deprecated, you should instead use no_hashes.
+
+ To generate the hashes, take the sha256 of the jammed battery. For example:
+
+ ```
+ > `@ux`(shax (jam -:rip))
+ 0x2759.a693.1e9e.f9a5.2c8e.ee43.1088.43d9.4d39.32a6.b04f.86cb.6ba1.5553.4329.3a28
+ ```
+
+ Becomes:
+
+ ```
+ 2759a6931e9ef9a52c8eee43108843d94d3932a6b04f86cb6ba1555343293a28
+ ```
+*/
+
+#include "c3/c3.h"
+#include "jets.h"
+#include "jets/w.h"
+
+static c3_c* no_hashes[] = { 0 };
+
+
+ static u3j_harm _140_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}};
+ static c3_c* _140_hex_mimes_base16_en_ha[] = {
+ "669807766b6802719769fcbfe149d77fb352fcf0922afaf35dc4ab8c201d84e5",
+ 0
+ };
+ static u3j_harm _140_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}};
+ static c3_c* _140_hex_mimes_base16_de_ha[] = {
+ "f1e04d0f452f2783e17b3bd5bbbcf95a651624fe7a2aca28dd9a7feae1319734",
+ 0
+ };
+ static u3j_core _140_hex_mimes_base16_d[] =
+ { { "en", 7, _140_hex_mimes_base16_en_a, 0, _140_hex_mimes_base16_en_ha },
+ { "de", 7, _140_hex_mimes_base16_de_a, 0, _140_hex_mimes_base16_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_mimes_base16_ha[] = {
+ "c71bdcc8542fd49aa307f296ac097e300a714fb3b3d1e475426f0916fa61f12c",
+ 0
+ };
+static u3j_core _140_hex_mimes_d[] =
+ { { "base16", 3, 0, _140_hex_mimes_base16_d, _140_hex_mimes_base16_ha },
+ {}
+ };
+static c3_c* _140_hex_mimes_ha[] = {
+ "bca2510fd7172643812f9d224deb95ddd69400c990db3d8cfb517a7292e8f06e",
+ 0
+};
+
+ static u3j_harm _140_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}};
+ static c3_c* _140_hex_aes_ecba_en_ha[] = {
+ "d7674ad72666a787580c52785c5d4d37ca462ba05e904efbeded5d1bd8b02b4b",
+ 0
+ };
+ static u3j_harm _140_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}};
+ static c3_c* _140_hex_aes_ecba_de_ha[] = {
+ "6e6599e93bea2e4297b621814bfb17a9b10849f920d50b14e808ef2e4fe62383",
+ 0
+ };
+ static u3j_core _140_hex_aes_ecba_d[] =
+ { { "en", 7, _140_hex_aes_ecba_en_a, 0, _140_hex_aes_ecba_en_ha },
+ { "de", 7, _140_hex_aes_ecba_de_a, 0, _140_hex_aes_ecba_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_ecba_ha[] = {
+ "693409d27b777f73ce92cebd38e9ebceebe1e9c27ad8c9de9afc091e31bd7d9f",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}};
+ static c3_c* _140_hex_aes_ecbb_en_ha[] = {
+ "2c0e3c8f4d741b37324563ecd0ab8fbf87721d1e017f1eeeaf8b6a60515c483b",
+ 0
+ };
+ static u3j_harm _140_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}};
+ static c3_c* _140_hex_aes_ecbb_de_ha[] = {
+ "cf78f314a1dbbc53b28d6405b98c66a4451350757872d8f7cf0477411e731acc",
+ 0
+ };
+ static u3j_core _140_hex_aes_ecbb_d[] =
+ { { "en", 7, _140_hex_aes_ecbb_en_a, 0, _140_hex_aes_ecbb_en_ha },
+ { "de", 7, _140_hex_aes_ecbb_de_a, 0, _140_hex_aes_ecbb_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_ecbb_ha[] = {
+ "7255c39f10e068007d0d64dd40e4f6e83492ed2e3222919440be0d28fd42a5e3",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}};
+ static c3_c* _140_hex_aes_ecbc_en_ha[] = {
+ "f56450f2662082e27ba1aecd2fe04c66aa8641d6eb155f8d3707e242a1e1cf1c",
+ 0
+ };
+ static u3j_harm _140_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}};
+ static c3_c* _140_hex_aes_ecbc_de_ha[] = {
+ "28c8c44002799fbe94d4aa07922f2b74dbbf234c84684cd8c3187622b4be6a5f",
+ 0
+ };
+ static u3j_core _140_hex_aes_ecbc_d[] =
+ { { "en", 7, _140_hex_aes_ecbc_en_a, 0, _140_hex_aes_ecbc_en_ha },
+ { "de", 7, _140_hex_aes_ecbc_de_a, 0, _140_hex_aes_ecbc_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_ecbc_ha[] = {
+ "65da73b8de06a6660ca2d36be881b708362e1f8bc12c01290aed90fdb2977667",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}};
+ static c3_c* _140_hex_aes_cbca_en_ha[] = {
+ "f85366d520b3179c5dabfb58ee1fa0554f5044f676340439db875841cd4058de",
+ 0
+ };
+ static u3j_harm _140_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}};
+ static c3_c* _140_hex_aes_cbca_de_ha[] = {
+ "8b876fbdb1849d8fbabba5e143aea0532a0e5dfff1c784d7ad15fd497ea376b1",
+ 0
+ };
+ static u3j_core _140_hex_aes_cbca_d[] =
+ { { "en", 7, _140_hex_aes_cbca_en_a, 0, _140_hex_aes_cbca_en_ha },
+ { "de", 7, _140_hex_aes_cbca_de_a, 0, _140_hex_aes_cbca_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_cbca_ha[] = {
+ "420d04c03b7816b656fe4e8d9fce04f7e6d51d3d274c6511e89cfdb43ebf107e",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}};
+ static c3_c* _140_hex_aes_cbcb_en_ha[] = {
+ "6f961e0629c5efce47793e6a352220d355bb8fba6656c6941a68efb3ba10999d",
+ 0
+ };
+ static u3j_harm _140_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}};
+ static c3_c* _140_hex_aes_cbcb_de_ha[] = {
+ "7ee2f33f80612e91fda1fd84201266dea6cab596a4e23a535d1a14fb0763f1a3",
+ 0
+ };
+ static u3j_core _140_hex_aes_cbcb_d[] =
+ { { "en", 7, _140_hex_aes_cbcb_en_a, 0, _140_hex_aes_cbcb_en_ha },
+ { "de", 7, _140_hex_aes_cbcb_de_a, 0, _140_hex_aes_cbcb_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_cbcb_ha[] = {
+ "1b84daab497795f2afd7238a6a6090be68b78eb6051b0ffa076b2ed9fedeebe5",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}};
+ static c3_c* _140_hex_aes_cbcc_en_ha[] = {
+ "b2578cf17a3095f48cc96cf7690dd7ab4f4e0b76b2578eadc1dce31a075f5b12",
+ 0
+ };
+ static u3j_harm _140_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}};
+ static c3_c* _140_hex_aes_cbcc_de_ha[] = {
+ "36586f89d702bedb8c2a01ea3614f61627e762488e373106cbb1b27c46e3493c",
+ 0
+ };
+ static u3j_core _140_hex_aes_cbcc_d[] =
+ { { "en", 7, _140_hex_aes_cbcc_en_a, 0, _140_hex_aes_cbcc_en_ha },
+ { "de", 7, _140_hex_aes_cbcc_de_a, 0, _140_hex_aes_cbcc_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_cbcc_ha[] = {
+ "3bab1a59c7673afeb659821d54754e8e5e281243e79624fdbe4d7f85cae192c5",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}};
+ static c3_c* _140_hex_aes_siva_en_ha[] = {
+ "2a137039301788b8540ed81cbfafe450c9306348d02a6576f5c14f6d6f20ba81",
+ 0
+ };
+ static u3j_harm _140_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}};
+ static c3_c* _140_hex_aes_siva_de_ha[] = {
+ "d0130e9229e71c589429dd87843dc104bc4ee5b426400a547081d8c91a548eaa",
+ 0
+ };
+ static u3j_core _140_hex_aes_siva_d[] =
+ { { "en", 7, _140_hex_aes_siva_en_a, 0, _140_hex_aes_siva_en_ha },
+ { "de", 7, _140_hex_aes_siva_de_a, 0, _140_hex_aes_siva_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_siva_ha[] = {
+ "435c5c769d2522d71ab60332bb57440d69c6803d5ca9a5faae88c825cb55d72e",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}};
+ static c3_c* _140_hex_aes_sivb_en_ha[] = {
+ "1638f56e8728f285e4175c7b514c5a4e1a24205acf33e105f0513cad7ae843cf",
+ 0
+ };
+ static u3j_harm _140_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}};
+ static c3_c* _140_hex_aes_sivb_de_ha[] = {
+ "64c9b199fffd6d31baf7457bf27d5a510121be45201b2ae5cc1d9565c0bdd0ff",
+ 0
+ };
+ static u3j_core _140_hex_aes_sivb_d[] =
+ { { "en", 7, _140_hex_aes_sivb_en_a, 0, _140_hex_aes_sivb_en_ha },
+ { "de", 7, _140_hex_aes_sivb_de_a, 0, _140_hex_aes_sivb_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_sivb_ha[] = {
+ "0683f3f9067c2a16f68805c778c404179dc5df9019bbbe0f8d680a99a69e61fc",
+ 0
+ };
+
+ static u3j_harm _140_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}};
+ static c3_c* _140_hex_aes_sivc_en_ha[] = {
+ "d721486dea943efd52d9e6450f4f48dd191c89637a2f842d3ff6edfd3beecbb9",
+ 0
+ };
+ static u3j_harm _140_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}};
+ static c3_c* _140_hex_aes_sivc_de_ha[] = {
+ "3ded831b992ea100582229a4d1d9b5c80380128ae6b59b5bb36403ed13dc5d55",
+ 0
+ };
+ static u3j_core _140_hex_aes_sivc_d[] =
+ { { "en", 7, _140_hex_aes_sivc_en_a, 0, _140_hex_aes_sivc_en_ha },
+ { "de", 7, _140_hex_aes_sivc_de_a, 0, _140_hex_aes_sivc_de_ha },
+ {}
+ };
+ static c3_c* _140_hex_aes_sivc_ha[] = {
+ "23ef582f110d28aff82b0795305b02e5a718d667bcae97091c08bc26790e7176",
+ 0
+ };
+static u3j_core _140_hex_aes_d[] =
+ { { "ecba", 7, 0, _140_hex_aes_ecba_d, _140_hex_aes_ecba_ha },
+ { "ecbb", 7, 0, _140_hex_aes_ecbb_d, _140_hex_aes_ecbb_ha },
+ { "ecbc", 7, 0, _140_hex_aes_ecbc_d, _140_hex_aes_ecbc_ha },
+ { "cbca", 7, 0, _140_hex_aes_cbca_d, _140_hex_aes_cbca_ha },
+ { "cbcb", 7, 0, _140_hex_aes_cbcb_d, _140_hex_aes_cbcb_ha },
+ { "cbcc", 7, 0, _140_hex_aes_cbcc_d, _140_hex_aes_cbcc_ha },
+ { "siva", 7, 0, _140_hex_aes_siva_d, _140_hex_aes_siva_ha },
+ { "sivb", 7, 0, _140_hex_aes_sivb_d, _140_hex_aes_sivb_ha },
+ { "sivc", 7, 0, _140_hex_aes_sivc_d, _140_hex_aes_sivc_ha },
+ {}
+ };
+static c3_c* _140_hex_aes_ha[] = {
+ "ca4c1b0cff03db74ceca1b844f0223d669aa42934152a784d431469f0eb71527",
+ 0
+};
+
+static u3j_harm _140_hex_leer_a[] = {{".2", u3we_leer}, {}};
+static c3_c* _140_hex_leer_ha[] = {
+ "8a4486bb09639f6b8cf7631f9bf883256529c6d7d9aa320ab6dfa5517611f0d7",
+ 0
+};
+static u3j_harm _140_hex_lore_a[] = {{".2", u3we_lore}, {}};
+static c3_c* _140_hex_lore_ha[] = {
+ "19b13cfea49fd14aafbb20b8b888ba454f809c3f50a7cfeebd43f87336fe052d",
+ 0
+};
+static u3j_harm _140_hex_loss_a[] = {{".2", u3we_loss}, {}};
+static c3_c* _140_hex_loss_ha[] = {
+ "67aacd21484078828ad4342297d44c38d9213b8809f83f695c2996378a92dc2a",
+ 0
+};
+static u3j_harm _140_hex_lune_a[] = {{".2", u3we_lune}, {}};
+static c3_c* _140_hex_lune_ha[] = {
+ "417472f35b885fe6dd0715e78fd0920cb59f68b738aadc9768e73bc5efa0e570",
+ 0
+};
+
+static u3j_harm _140_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}};
+static c3_c* _140_hex_coed__ed_puck_ha[] = {
+ "1bc694675842345c50b0e20a2193bb5bcbb42f163fc832431a3d1822a81e4c98",
+ 0
+};
+
+static u3j_harm _140_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}};
+
+static u3j_harm _140_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}};
+static c3_c* _140_hex_coed__ed_sign_octs_ha[] = {
+ "34ad749bf8443611cbf1f7de90a066318bd12be36f2f7f6f55281f6f7ed79754",
+ 0
+};
+
+static u3j_harm _140_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}};
+
+static u3j_harm _140_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}};
+static c3_c* _140_hex_coed__ed_veri_octs_ha[] = {
+ "047a7eeccb2e68aeeee631b6db86e11a5a3aa9e179660553eca6304327612dcf",
+ 0
+};
+static u3j_harm _140_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}};
+static c3_c* _140_hex_coed__ed_shar_ha[] = {
+ "52d3b0a2f51f2b0a9dd72bb33db38c73dc873029c365d871d0559a1472a80e72",
+ 0
+};
+
+ static u3j_harm _140_hex_coed__ed_point_add_a[] =
+ {{".2", u3wee_point_add}, {}};
+
+ static u3j_harm _140_hex_coed__ed_scalarmult_a[] =
+ {{".2", u3wee_scalarmult}, {}};
+ static c3_c* _140_hex_coed__ed_scalarmult_ha[] = {
+ "72e71cd3aa3af429cd65baa78632500c60edd1d4c82a39d3ba7f231ef97e6316",
+ 0
+ };
+
+ static u3j_harm _140_hex_coed__ed_scalarmult_base_a[] =
+ {{".2", u3wee_scalarmult_base}, {}};
+ static c3_c* _140_hex_coed__ed_scalarmult_base_ha[] = {
+ "976fdb8251f9b767af689a0d2c41b88941921bf53777c1ceeb5297511021f9d8",
+ 0
+ };
+
+ static u3j_harm _140_hex_coed__ed_add_scalarmult_scalarmult_base_a[] =
+ {{".2", u3wee_add_scalarmult_scalarmult_base}, {}};
+ static c3_c* _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha[] = {
+ "11819071c24a2d7b36daea6e16c78b2e05f9ca3e857cf4815ffe652ce677a61a",
+ 0
+ };
+
+ static u3j_harm _140_hex_coed__ed_add_double_scalarmult_a[] =
+ {{".2", u3wee_add_double_scalarmult}, {}};
+ static c3_c* _140_hex_coed__ed_add_double_scalarmult_ha[] = {
+ "0fab78a1e890e53cecade1c22b95813db77e066044e33417a0919695b6cde9ba",
+ 0
+ };
+
+static u3j_core _140_hex_coed__ed_d[] =
+ { { "sign", 7, _140_hex_coed__ed_sign_a, 0, no_hashes },
+ { "sign-octs", 7, _140_hex_coed__ed_sign_octs_a, 0, _140_hex_coed__ed_sign_octs_ha },
+ { "puck", 7, _140_hex_coed__ed_puck_a, 0, _140_hex_coed__ed_puck_ha },
+ { "veri", 7, _140_hex_coed__ed_veri_a, 0, no_hashes },
+ { "veri-octs", 7, _140_hex_coed__ed_veri_octs_a, 0, _140_hex_coed__ed_veri_octs_ha },
+ { "shar", 7, _140_hex_coed__ed_shar_a, 0, _140_hex_coed__ed_shar_ha },
+ { "point-add", 7, _140_hex_coed__ed_point_add_a, 0, 0 },
+ { "scalarmult", 7, _140_hex_coed__ed_scalarmult_a, 0,
+ _140_hex_coed__ed_scalarmult_ha },
+ { "scalarmult-base", 7, _140_hex_coed__ed_scalarmult_base_a, 0,
+ _140_hex_coed__ed_scalarmult_base_ha },
+ { "add-scalarmult-scalarmult-base", 7,
+ _140_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0,
+ _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha },
+ { "add-double-scalarmult", 7,
+ _140_hex_coed__ed_add_double_scalarmult_a, 0,
+ _140_hex_coed__ed_add_double_scalarmult_ha },
+ {}
+ };
+static c3_c* _140_hex_coed__ed_ha[] = {
+ "7a44a962aa72933588b5c99a8b68ebac21ce3c4710c081cb66b3599b45af9ced",
+ 0
+};
+
+static u3j_core _140_hex_coed_d[] =
+{ { "ed", 3, 0, _140_hex_coed__ed_d, _140_hex_coed__ed_ha },
+ {}
+};
+static c3_c* _140_hex_coed_ha[] = {
+ "4be0254f06d953b69509eb15550595ffad8767d3c3dc2dafcd7c22f92f7704c4",
+ 0
+};
+
+ static u3j_harm _140_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}};
+ static c3_c* _140_hex_hmac_hmac_ha[] = {
+ "d0dbd778156aef21d18f44a8cffd87296826120af5a4af020dd7aff0f95f03b1",
+ 0
+ };
+static u3j_core _140_hex_hmac_d[] =
+ { { "hmac", 7, _140_hex_hmac_hmac_a, 0, _140_hex_hmac_hmac_ha },
+ {}
+ };
+static c3_c* _140_hex_hmac_ha[] = {
+ "976bb4508dbe659eb12aa32d4a481dbd885e40f8a15c505762f1acf43b744234",
+ 0
+};
+
+ static u3j_harm _140_hex_argon2_a[] = {{".2", u3we_argon2}, {}};
+ static c3_c* _140_hex_argon2_ha[] = {
+ "4df7cec141ffa2cc76b058846474ca42cc9840666ee3e7e80e565803e83ea98b",
+ 0
+ };
+static u3j_core _140_hex_argon_d[] =
+ { { "argon2", 511, _140_hex_argon2_a, 0, _140_hex_argon2_ha },
+ {}
+ };
+static c3_c* _140_hex_argon_ha[] = {
+ "dc704c786192ecd09d4c206a8f28db3202b6e0eb03e3ce63a95987510ac312d6",
+ 0
+};
+
+ static u3j_harm _140_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}};
+ static c3_c* _140_hex_scr_pbk_ha[] = { 0 };
+ static u3j_harm _140_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}};
+ static c3_c* _140_hex_scr_pbl_ha[] = { 0 };
+ static u3j_harm _140_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}};
+ static c3_c* _140_hex_scr_hsh_ha[] = { 0 };
+ static u3j_harm _140_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}};
+ static c3_c* _140_hex_scr_hsl_ha[] = { 0 };
+static u3j_core _140_hex_scr_d[] =
+ { { "pbk", 7, _140_hex_scr_pbk_a, 0, _140_hex_scr_pbk_ha },
+ { "pbl", 7, _140_hex_scr_pbl_a, 0, _140_hex_scr_pbl_ha },
+ { "hsh", 7, _140_hex_scr_hsh_a, 0, _140_hex_scr_hsh_ha },
+ { "hsl", 7, _140_hex_scr_hsl_a, 0, _140_hex_scr_hsl_ha },
+ {}
+ };
+static c3_c* _140_hex_scr_ha[] = { 0 };
+
+ static u3j_harm _140_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}};
+ static c3_c* _140_hex_secp_secp256k1_make_ha[] = { 0 };
+ static u3j_harm _140_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}};
+ static c3_c* _140_hex_secp_secp256k1_sign_ha[] = { 0 };
+ static u3j_harm _140_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}};
+ static c3_c* _140_hex_secp_secp256k1_reco_ha[] = { 0 };
+
+ static u3j_harm _140_hex_secp_secp256k1_schnorr_sosi_a[] =
+ {{".2", u3we_sosi}, {}};
+ static c3_c* _140_hex_secp_secp256k1_schnorr_sosi_ha[] = { 0 };
+ static u3j_harm _140_hex_secp_secp256k1_schnorr_sove_a[] =
+ {{".2", u3we_sove}, {}};
+ static c3_c* _140_hex_secp_secp256k1_schnorr_sove_ha[] = { 0 };
+ static u3j_core _140_hex_secp_secp256k1_schnorr_d[] =
+ { { "sosi", 7,
+ _140_hex_secp_secp256k1_schnorr_sosi_a, 0,
+ _140_hex_secp_secp256k1_schnorr_sosi_ha },
+ { "sove", 7,
+ _140_hex_secp_secp256k1_schnorr_sove_a, 0,
+ _140_hex_secp_secp256k1_schnorr_sove_ha },
+ {}
+ };
+ static c3_c* _140_hex_secp_secp256k1_schnorr_ha[] = { 0 };
+
+ static u3j_core _140_hex_secp_secp256k1_d[] =
+ { { "make", 7, _140_hex_secp_secp256k1_make_a, 0, _140_hex_secp_secp256k1_make_ha },
+ { "sign", 7, _140_hex_secp_secp256k1_sign_a, 0, _140_hex_secp_secp256k1_sign_ha },
+ { "reco", 7, _140_hex_secp_secp256k1_reco_a, 0, _140_hex_secp_secp256k1_reco_ha },
+ { "schnorr", 7, 0,
+ _140_hex_secp_secp256k1_schnorr_d,
+ _140_hex_secp_secp256k1_schnorr_ha },
+ {}
+ };
+ static c3_c* _140_hex_secp_secp256k1_ha[] = {
+ "e7fc0971a970aba7ded43bd89e9c82623eb2f346c9c720c63b22f2a646927861",
+ 0
+ };
+static u3j_core _140_hex_secp_d[] =
+ { { "secp256k1", 3, 0, _140_hex_secp_secp256k1_d, _140_hex_secp_secp256k1_ha },
+ {}
+ };
+static c3_c* _140_hex_secp_ha[] = {
+ "9f5c23f0e7923b6cf1603388ba52401b6e43881be3560b3acfaab20b25071792",
+ 0
+};
+
+ static u3j_harm _140_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}};
+
+static u3j_core _140_hex_blake_d[] =
+ { { "blake2b", 7, _140_hex_blake2b_a, 0, no_hashes },
+ {}
+ };
+static c3_c* _140_hex_blake_ha[] = {
+ "ff30d99ffb3e13d8aa50b2b8461c8edfabf0e76de22312d16d1d6daaf3636b5f",
+ 0
+};
+
+ static u3j_harm _140_hex_kecc_k224_a[] =
+ {{".2", u3we_kecc224, c3y, c3y, c3y}, {}};
+ static u3j_harm _140_hex_kecc_k256_a[] =
+ {{".2", u3we_kecc256, c3y, c3y, c3y}, {}};
+ static u3j_harm _140_hex_kecc_k384_a[] =
+ {{".2", u3we_kecc384, c3y, c3y, c3y}, {}};
+ static u3j_harm _140_hex_kecc_k512_a[] =
+ {{".2", u3we_kecc512, c3y, c3y, c3y}, {}};
+static u3j_core _140_hex_kecc_d[] =
+ { { "k224", 7, _140_hex_kecc_k224_a, 0, no_hashes },
+ { "k256", 7, _140_hex_kecc_k256_a, 0, no_hashes },
+ { "k384", 7, _140_hex_kecc_k384_a, 0, no_hashes },
+ { "k512", 7, _140_hex_kecc_k512_a, 0, no_hashes },
+ {}
+ };
+
+ static u3j_harm _140_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}};
+ static c3_c* _140_hex_ripemd_160_ha[] = {
+ "176684b29926a01f5c60fa584e4691b0cbdc9b93608dcbe7d0cf3585683fa42f",
+ 0
+ };
+static u3j_core _140_hex_ripe_d[] =
+ { { "ripemd160", 7, _140_hex_ripemd_160_a, 0, _140_hex_ripemd_160_ha },
+ {}
+ };
+static c3_c* _140_hex_ripe_ha[] = {
+ "b0cb16bf206c0496bb480e5759ea1afa7dee1748b64e5243c23fddb09720ebd0",
+ 0
+};
+
+static u3j_core _140_hex_d[] =
+{ { "lore", 63, _140_hex_lore_a, 0, _140_hex_lore_ha },
+ { "leer", 63, _140_hex_leer_a, 0, _140_hex_leer_ha },
+ { "loss", 63, _140_hex_loss_a, 0, _140_hex_loss_ha },
+ { "lune", 127, _140_hex_lune_a, 0, _140_hex_lune_ha },
+
+ { "coed", 63, 0, _140_hex_coed_d, _140_hex_coed_ha },
+ { "aes", 31, 0, _140_hex_aes_d, _140_hex_aes_ha },
+
+ { "hmac", 63, 0, _140_hex_hmac_d, _140_hex_hmac_ha },
+ { "argon", 31, 0, _140_hex_argon_d, _140_hex_argon_ha },
+ { "blake", 31, 0, _140_hex_blake_d, _140_hex_blake_ha },
+ { "kecc", 31, 0, _140_hex_kecc_d, no_hashes },
+ { "ripemd", 31, 0, _140_hex_ripe_d, _140_hex_ripe_ha },
+ { "scr", 31, 0, _140_hex_scr_d, _140_hex_scr_ha },
+ { "secp", 6, 0, _140_hex_secp_d, _140_hex_secp_ha },
+ { "mimes", 31, 0, _140_hex_mimes_d, _140_hex_mimes_ha },
+ {}
+};
+static c3_c* _140_hex_ha[] = {
+ "7e393356dd7ac64eed5cd9f5cf0e320d401ca36a0a0ce0f954e7538824114844",
+ 0
+};
+
+
+/* layer five
+*/
+static u3j_harm _140_pen_cell_a[] = {{".2", u3wf_cell}, {}};
+static c3_c* _140_pen_cell_ha[] = {
+ "411649e69ff5c5d4a2976b300d213b99af3de724cec0e95f48404b808fc4f428",
+ 0
+};
+static u3j_harm _140_pen_comb_a[] = {{".2", u3wf_comb}, {}};
+static c3_c* _140_pen_comb_ha[] = {
+ "f9e37c3b3d5036c31af60f7047391594068638b54db7cf94bfea9dabbdffa547",
+ 0
+};
+static u3j_harm _140_pen_cons_a[] = {{".2", u3wf_cons}, {}};
+static c3_c* _140_pen_cons_ha[] = {
+ "b698cc6bc49ea0473e344c784075e99a433b4c5738f90fc58ab17c3eaa44b2e9",
+ 0
+};
+static u3j_harm _140_pen_core_a[] = {{".2", u3wf_core}, {}};
+static c3_c* _140_pen_core_ha[] = {
+ "1180e9371cf3465783ef192f9a7f580cd90533f5b52b77b456287f1d580a3535",
+ 0
+};
+static u3j_harm _140_pen_face_a[] = {{".2", u3wf_face}, {}};
+static c3_c* _140_pen_face_ha[] = {
+ "a184c44d57f5c94b84a3258b05bf891f3c96a4a4bbff3a8934d11cad0efa81d8",
+ 0
+};
+static u3j_harm _140_pen_fitz_a[] = {{".2", u3wf_fitz}, {}};
+static c3_c* _140_pen_fitz_ha[] = {
+ "469abe976ec15eeff9a87bce385f2c87c9bd89814ce2858aa9fee094beea1e5d",
+ 0
+};
+static u3j_harm _140_pen_flan_a[] = {{".2", u3wf_flan_139}, {}};
+static c3_c* _140_pen_flan_ha[] = {
+ "cc00cb9373b0274af4e17d7acd77f65d8a2fa886e422c949c12d9d9e7cb3525b",
+ 0
+};
+static u3j_harm _140_pen_flip_a[] = {{".2", u3wf_flip_139}, {}};
+static c3_c* _140_pen_flip_ha[] = {
+ "6e97fab9d039e715a30af5da93ef97389babfdcae7ef87655d278e77a1af0f0c",
+ 0
+};
+static u3j_harm _140_pen_flor_a[] = {{".2", u3wf_flor_139}, {}};
+static c3_c* _140_pen_flor_ha[] = {
+ "ab5360aacf0c9a325727e90e1caea9c42f5d94ccc248c9e1f253b0922b4c4e63",
+ 0
+};
+static u3j_harm _140_pen_fork_a[] = {{".2", u3wf_fork}, {}};
+static c3_c* _140_pen_fork_ha[] = {
+ "36f0ea0e2eb30328b8b83ed43a81c8c9a1f5b4c5a03fd68fd25701991a40b9dd",
+ 0
+};
+
+static u3j_harm _140_pen_look_a[] = {{".2", u3wf_look}, {}};
+static c3_c* _140_pen_look_ha[] = {
+ "fdda2166a2b9e1a9bda6ab375dd6fb6c610e18f54636a5e89896b45fd0a7169b",
+ 0
+};
+static u3j_harm _140_pen_loot_a[] = {{".2", u3wf_loot}, {}};
+static c3_c* _140_pen_loot_ha[] = {
+ "e275da4562ae6da9bd333aeae6b9829e886874c8b891898c0ef5306268eb45c1",
+ 0
+};
+
+ static u3j_harm _140_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}};
+ static c3_c* _140_pen__ut_crop_ha[] = {
+ "e2c6fc3e714a3a98ccd28423dcb9f2c6480935e26b54dd0581eb2ad7e5b16d6f",
+ 0
+ };
+ static u3j_harm _140_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}};
+ static c3_c* _140_pen__ut_fish_ha[] = {
+ "080caee60b5ee4616bf9568bdbceabbf044379c47466e0ae3968cb0146049a84",
+ 0
+ };
+ static u3j_harm _140_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}};
+ static c3_c* _140_pen__ut_fuse_ha[] = {
+ "519aac7b40b7018d5df00ddf3977c2ebe0c2e05bcee34796d56a1d54c15e0c84",
+ 0
+ };
+ static u3j_harm _140_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}};
+ static c3_c* _140_pen__ut_mint_ha[] = {
+ "7d980f7425b51bb10fbbd8b465b5d83f5dd4cb6e66d88758a9f7490b812a765e",
+ 0
+ };
+ static u3j_harm _140_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}};
+ static c3_c* _140_pen__ut_mull_ha[] = {
+ "c806329aefd920501ea0faa0cfb0ce3280a74408782efe6d82878ec43ec44fb7",
+ 0
+ };
+
+ static u3j_harm _140_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}};
+ static c3_c* _140_pen__ut_nest_dext_ha[] = {
+ "72f33df96800034fc63531293f9b110e6505027195bf8a10ff94b9a1f1ef719b",
+ 0
+ };
+ static u3j_core _140_pen__ut_nest_in_d[] =
+ {
+ { "nest-dext", 3, _140_pen__ut_nest_dext_a, 0, _140_pen__ut_nest_dext_ha },
+ {}
+ };
+ static c3_c* _140_pen__ut_nest_in_ha[] = {
+ "68378dfa1d1fee0b1cd9593fb561234cec2ae9371a5ffa287c3d2ab9620e198c",
+ 0
+ };
+ static u3j_core _140_pen__ut_nest_d[] =
+ {
+ { "nest-in", 7, 0, _140_pen__ut_nest_in_d, _140_pen__ut_nest_in_ha },
+ {}
+ };
+ static c3_c* _140_pen__ut_nest_ha[] = {
+ "1e8de5d1225facc1158c92c2ea5e0dc84129cbb317fde3691e224b8c2550d950",
+ 0
+ };
+
+ static u3j_harm _140_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}};
+ static c3_c* _140_pen__ut_rest_ha[] = {
+ "b4a83073f4cb03898ef099fab5722a046122dc96a5332ffc82f988df6c186e74",
+ 0
+ };
+
+static u3j_core _140_pen__ut_d[] =
+ {
+ { "crop", 7, _140_pen__ut_crop_a, 0, _140_pen__ut_crop_ha },
+ { "fish", 7, _140_pen__ut_fish_a, 0, _140_pen__ut_fish_ha },
+ { "fuse", 7, _140_pen__ut_fuse_a, 0, _140_pen__ut_fuse_ha },
+ { "mint", 7, _140_pen__ut_mint_a, 0, _140_pen__ut_mint_ha },
+ { "mull", 7, _140_pen__ut_mull_a, 0, _140_pen__ut_mull_ha },
+ { "nest", 7, 0, _140_pen__ut_nest_d, _140_pen__ut_nest_ha },
+ { "rest", 7, _140_pen__ut_rest_a, 0, _140_pen__ut_rest_ha },
+ {}
+ };
+static c3_c* _140_pen__ut_ha[] = {
+ "50c79204c82a3ba8f01e085a2e27e7716e5c7ab1929f94423ef1da92cf5ac631",
+ 0
+};
+
+static u3j_hood _140_pen__ut_ho[] =
+ { { "ar", 12282 },
+ { "fan", 28, c3n },
+ { "rib", 58, c3n },
+ { "vet", 59, c3n },
+
+ { "blow", 6015 },
+ { "burp", 342 },
+ { "busk", 1373 },
+ { "buss", 374 },
+ { "crop", 1494 },
+ { "duck", 1524 },
+ { "dune", 2991 },
+ { "dunk", 3066 },
+ { "epla", 12206 },
+ { "emin", 1534 },
+ { "emul", 6134 },
+ { "feel", 1502 },
+ { "felt", 94 },
+ { "fine", 49086 },
+ { "fire", 4 },
+ { "fish", 6006 },
+ { "fond", 12283 },
+ { "fund", 6014 },
+ // XX +funk is not part of +ut, and this hook appears to be unused
+ // remove from here and the +ut hint
+ //
+ { "funk", 0xbefafa, c3y, 31 },
+ { "fuse", 24021 },
+ { "gain", 380 },
+ { "lose", 0x2fefe },
+ { "mile", 382 },
+ { "mine", 372 },
+ { "mint", 49083 },
+ { "moot", 0x2feff },
+ { "mull", 24020 },
+ { "nest", 92 },
+ { "peel", 1526 },
+ { "play", 3006 },
+ { "peek", 1532 },
+ { "repo", 22 },
+ { "rest", 6102 },
+ { "tack", 6007 },
+ { "toss", 24540 },
+ { "wrap", 6140 },
+ {},
+ };
+
+static u3j_core _140_pen_d[] =
+{ { "hex", 7, 0, _140_hex_d, _140_hex_ha },
+
+ { "cell", 7, _140_pen_cell_a, 0, _140_pen_cell_ha },
+ { "comb", 7, _140_pen_comb_a, 0, _140_pen_comb_ha },
+ { "cons", 7, _140_pen_cons_a, 0, _140_pen_cons_ha },
+ { "core", 7, _140_pen_core_a, 0, _140_pen_core_ha },
+ { "face", 7, _140_pen_face_a, 0, _140_pen_face_ha },
+ { "fitz", 7, _140_pen_fitz_a, 0, _140_pen_fitz_ha },
+ { "flan", 7, _140_pen_flan_a, 0, _140_pen_flan_ha },
+ { "flip", 7, _140_pen_flip_a, 0, _140_pen_flip_ha },
+ { "flor", 7, _140_pen_flor_a, 0, _140_pen_flor_ha },
+ { "fork", 7, _140_pen_fork_a, 0, _140_pen_fork_ha },
+ { "look", 7, _140_pen_look_a, 0, _140_pen_look_ha },
+ { "loot", 7, _140_pen_loot_a, 0, _140_pen_loot_ha },
+ { "ut", 15, 0, _140_pen__ut_d, _140_pen__ut_ha, _140_pen__ut_ho },
+ {}
+};
+static c3_c* _140_pen_ha[] = {
+ "e6c9e2362bdf2d1f9a2837a0efa154c0b8b9d51aea03a86b5aece573ff423cb1",
+ 0
+};
+
+static u3j_hood _140_pen_ho[] = {
+ { "ap", 22 },
+ { "ut", 86 },
+ {},
+};
+
+
+/* layer four
+*/
+static u3j_harm _140_qua_trip_a[] = {{".2", u3we_trip}, {}};
+static c3_c* _140_qua_trip_ha[] = {
+ "05423b940d10d03891cc23f36eea14b233e5884ef539de3d985d6818dd427b05",
+ 0
+};
+
+static u3j_harm _140_qua_slaw_a[] = {{".2", u3we_slaw}, {}};
+static c3_c* _140_qua_slaw_ha[] = {
+ "306c9692f48e2700675ed6581e9df4feaee951e1bed3cad7f89aab392e80000f",
+ 0
+};
+static u3j_harm _140_qua_scot_a[] = {{".2", u3we_scot}, {}};
+static c3_c* _140_qua_scot_ha[] = {
+ 0
+};
+static u3j_harm _140_qua_scow_a[] = {{".2", u3we_scow}, {}};
+static c3_c* _140_qua_scow_ha[] = {
+ 0
+};
+
+ static u3j_harm _140_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}};
+ static c3_c* _140_qua__po_ind_ha[] = {
+ "95bbe9867dbbd1b9ce12671d64cf7b1dee8d987c6770955a83c73291c4537a61",
+ 0
+ };
+ static u3j_harm _140_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}};
+ static c3_c* _140_qua__po_ins_ha[] = {
+ "aae783fb258dff7f8ade49756e01f96a2d2100411a88a886732270dcf9f174f0",
+ 0
+ };
+ static u3j_harm _140_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}};
+ static c3_c* _140_qua__po_tod_ha[] = {
+ "153aeba45ca2a87aa918e9cea1b26e8104a6e4395979257b075546c1e2654a17",
+ 0
+ };
+ static u3j_harm _140_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}};
+ static c3_c* _140_qua__po_tos_ha[] = {
+ "7c5ffad03bcf8b4ea9bdf0c7f7500351923bc0431f3d62d6ce0472790f668fb4",
+ 0
+ };
+static u3j_core _140_qua__po_d[] =
+ { { "ind", 7, _140_qua__po_ind_a, 0, _140_qua__po_ind_ha },
+ { "ins", 7, _140_qua__po_ins_a, 0, _140_qua__po_ins_ha },
+ { "tod", 7, _140_qua__po_tod_a, 0, _140_qua__po_tod_ha },
+ { "tos", 7, _140_qua__po_tos_a, 0, _140_qua__po_tos_ha },
+ {}
+ };
+static c3_c* _140_qua__po_ha[] = {
+ "efc5fa7c0efedd490e9a270bb5cf9f90809e6b224f8a381a6b8a481253b237a1",
+ 0
+};
+
+ static u3j_harm _140_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}};
+ static c3_c* _140_qua__bend_fun_ha[] = {
+ "e6ea05e3d765a005fccde9eb88fb93e06f0b6ea198afa8ed599b056ba179396a",
+ 0
+ };
+static u3j_core _140_qua__bend_d[] =
+ { { "fun", 7, _140_qua__bend_fun_a, 0, _140_qua__bend_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__bend_ha[] = {
+ "adc59c6db6d5b26122bc6c04e25c3efe830c9eef68ecf81c492a59ee5e9e20a2",
+ 0
+};
+
+ static u3j_harm _140_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}};
+ static c3_c* _140_qua__cold_fun_ha[] = {
+ "ad5a0ab7405be9ffda0a9dd34580c6039f6bbb0301920fb2df0c31be3c72c58e",
+ 0
+ };
+static u3j_core _140_qua__cold_d[] =
+ { { "fun", 7, _140_qua__cold_fun_a, 0, _140_qua__cold_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__cold_ha[] = {
+ "06c49d8dab6cb057e3ae1d1164e96950944ea48e54ad72347239ea434f1d4b9c",
+ 0
+};
+
+ static u3j_harm _140_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}};
+ static c3_c* _140_qua__cook_fun_ha[] = {
+ "f2a45612ad9c279b723334ab0915d3ed3ece7727309968c2555f45e0668eeb27",
+ 0
+ };
+static u3j_core _140_qua__cook_d[] =
+ { { "fun", 7, _140_qua__cook_fun_a, 0, _140_qua__cook_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__cook_ha[] = {
+ "3ccd46dd21828d7be11f8c093536e305b1df982393a69c40ea73f63a574b3bb1",
+ 0
+};
+
+ static u3j_harm _140_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}};
+ static c3_c* _140_qua__comp_fun_ha[] = {
+ "bd7fdba84b05b00a63c24d19a03b882578ee9a3b922a3a688f7827c6e64daf96",
+ 0
+ };
+static u3j_core _140_qua__comp_d[] =
+ { { "fun", 7, _140_qua__comp_fun_a, 0, _140_qua__comp_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__comp_ha[] = {
+ "7baad25ba87bcbba8ce4fe328280a799765dcf62a8bb761ffd87b939dd8734f2",
+ 0
+};
+
+ static u3j_harm _140_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}};
+ static c3_c* _140_qua__easy_fun_ha[] = {
+ "4bbbc43ece463d961e572301d0824d3e3cab3ba09ec2756cbefae63ee106044b",
+ 0
+ };
+static u3j_core _140_qua__easy_d[] =
+ { { "fun", 7, _140_qua__easy_fun_a, 0, _140_qua__easy_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__easy_ha[] = {
+ "fdcf833943e24323deb6b071497498933ce6c4ba7d4742f2752b6ddb7fb9634e",
+ 0
+};
+
+ static u3j_harm _140_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}};
+ static c3_c* _140_qua__glue_fun_ha[] = {
+ "ffe0fe8815a2298c51a58e963efbbb7af90830abf11ce50bf9a47f479ce452fb",
+ 0
+ };
+static u3j_core _140_qua__glue_d[] =
+ { { "fun", 7, _140_qua__glue_fun_a, 0, _140_qua__glue_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__glue_ha[] = {
+ "079c8a395428c2921b266a84bcf271fbe62f3d873b26680661e13a78df1a3989",
+ 0
+};
+
+ static u3j_harm _140_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}};
+ static c3_c* _140_qua__here_fun_ha[] = {
+ "47ec445fcfa89d266dae3c3590ed041d1b05f92d1bce360f232da5d496e4f2eb",
+ 0
+ };
+static u3j_core _140_qua__here_d[] =
+ { { "fun", 7, _140_qua__here_fun_a, 0, _140_qua__here_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__here_ha[] = {
+ "4600093be5becba9a65a14b67624e3d9e4c66e0c97ba57b2bc271907eea32ffe",
+ 0
+};
+
+ static u3j_harm _140_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}};
+ static c3_c* _140_qua__just_fun_ha[] = {
+ "38bf1fb843bc29837868f2828f32d7e2bbb419b0cb9a1236adea28dfc6ce1040",
+ 0
+ };
+static u3j_core _140_qua__just_d[] =
+ { { "fun", 7, _140_qua__just_fun_a, 0, _140_qua__just_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__just_ha[] = {
+ "7d6b2165e52dec478d96cf72478a35b7a92b014e6a15f046f026c0c8cb07679b",
+ 0
+};
+
+ static u3j_harm _140_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}};
+ static c3_c* _140_qua__mask_fun_ha[] = {
+ "892dfcd5f3d90981fa6e7608e93f0517000d316e7d9c07b3bd390c4966c97f5f",
+ 0
+ };
+static u3j_core _140_qua__mask_d[] =
+ { { "fun", 7, _140_qua__mask_fun_a, 0, _140_qua__mask_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__mask_ha[] = {
+ "48e11fc12d7c453cda6ca42577d68e968446aa4d0ad3b99cc674affc7f4507b4",
+ 0
+};
+
+ static u3j_harm _140_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}};
+ static c3_c* _140_qua__shim_fun_ha[] = {
+ "4e26a0e98adb13ee6718fd68d90910c630df9bb7023b3e3ef40cda6710075fc9",
+ 0
+ };
+static u3j_core _140_qua__shim_d[] =
+ { { "fun", 7, _140_qua__shim_fun_a, 0, _140_qua__shim_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__shim_ha[] = {
+ "226b96d1a59daada23a1ea80227c2dbf32ddd748d4c6363f316147ab7f292ced",
+ 0
+};
+
+ static u3j_harm _140_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}};
+ static c3_c* _140_qua__stag_fun_ha[] = {
+ "f76c7205c23e77809af793bc506f4727071fd029d234317fe78a7f65e2b7d6ea",
+ 0
+ };
+static u3j_core _140_qua__stag_d[] =
+ { { "fun", 7, _140_qua__stag_fun_a, 0, _140_qua__stag_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__stag_ha[] = {
+ "fc978af18fb13dc0d77501b6f3eeb538b079b4345eb9195c3dd44c516e69424a",
+ 0
+};
+
+ static u3j_harm _140_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}};
+ static c3_c* _140_qua__stew_fun_ha[] = {
+ "a700f6bdfdb83ba33b2a3fe92fda3cb1bbfe95e595401538c8371b55fcc61447",
+ 0
+ };
+static u3j_core _140_qua__stew_d[] =
+ { { "fun", 31, _140_qua__stew_fun_a, 0, _140_qua__stew_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__stew_ha[] = {
+ "29303fd6ab78cbbccdfc5bcf23d0bff126a0ef2bf4fa11ce70fcf4e6aa5fe60b",
+ 0
+};
+
+ static u3j_harm _140_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}};
+ static c3_c* _140_qua__stir_fun_ha[] = {
+ "6251308ea3c741e76ef9cb2dc5a71c9d8706d6cce6fdb420fef12915e0c032d6",
+ 0
+ };
+static u3j_core _140_qua__stir_d[] =
+ { { "fun", 7, _140_qua__stir_fun_a, 0, _140_qua__stir_fun_ha },
+ {}
+ };
+static c3_c* _140_qua__stir_ha[] = {
+ "4e466aef4d91f0ced008c00e8a4330afb3a43ef81dc1a6d93f1853685f69b9ca",
+ 0
+};
+
+static u3j_harm _140_qua_pfix_a[] = {{".2", u3we_pfix}, {}};
+static c3_c* _140_qua_pfix_ha[] = {
+ "f7019bccc8b3b04a969878ffed84c9eba4dfa60ee32f984119cacb0c2381656b",
+ 0
+};
+
+static u3j_harm _140_qua_plug_a[] = {{".2", u3we_plug}, {}};
+static c3_c* _140_qua_plug_ha[] = {
+ "5f5a9824e0952fd565748cc0a20f96cf883a41e2f5707c8a7797e6edd617b79c",
+ 0
+};
+static u3j_harm _140_qua_pose_a[] = {{".2", u3we_pose}, {}};
+static c3_c* _140_qua_pose_ha[] = {
+ "5c77203f288ef0f7bcd87871c69673db7fc804b647ecc42992707dc32f0f4611",
+ 0
+};
+
+static u3j_harm _140_qua_sfix_a[] = {{".2", u3we_sfix}, {}};
+static c3_c* _140_qua_sfix_ha[] = {
+ "00987ed37104b902c5264d4d013826d762bfa80a6b29cfe4b7fa61b1ddd9cfac",
+ 0
+};
+
+static u3j_harm _140_qua_mink_a[] = {{".2", u3we_mink}, {}};
+static c3_c* _140_qua_mink_ha[] = {
+ "99b653da6a21fa3375424811af288f59164592ece4a072abc460df03e81abcaf",
+ 0
+};
+static u3j_harm _140_qua_mole_a[] = {{".2", u3we_mole}, {}};
+static c3_c* _140_qua_mole_ha[] = {
+ "029c1acaff1911c54ce31a3693397394604ea970bf076078c1a1cfa23d2fa74e",
+ 0
+};
+static u3j_harm _140_qua_mule_a[] = {{".2", u3we_mule}, {}};
+static c3_c* _140_qua_mule_ha[] = {
+ "d54688d726565ddade7f2636741cad7209ea40fab28d3335555d8a02ff6001c4",
+ 0
+};
+
+static u3j_core _140_qua_d[] =
+{ { "pen", 3, 0, _140_pen_d, _140_pen_ha, _140_pen_ho },
+
+ { "po", 7, 0, _140_qua__po_d, _140_qua__po_ha },
+
+ { "trip", 7, _140_qua_trip_a, 0, _140_qua_trip_ha },
+
+ { "bend", 7, 0, _140_qua__bend_d, _140_qua__bend_ha },
+ { "cold", 7, 0, _140_qua__cold_d, _140_qua__cold_ha },
+ { "comp", 7, 0, _140_qua__comp_d, _140_qua__comp_ha },
+ { "cook", 7, 0, _140_qua__cook_d, _140_qua__cook_ha },
+ { "easy", 7, 0, _140_qua__easy_d, _140_qua__easy_ha },
+ { "glue", 7, 0, _140_qua__glue_d, _140_qua__glue_ha },
+ { "here", 7, 0, _140_qua__here_d, _140_qua__here_ha },
+ { "just", 7, 0, _140_qua__just_d, _140_qua__just_ha },
+ { "mask", 7, 0, _140_qua__mask_d, _140_qua__mask_ha },
+ { "shim", 7, 0, _140_qua__shim_d, _140_qua__shim_ha },
+ { "stag", 7, 0, _140_qua__stag_d, _140_qua__stag_ha },
+ { "stew", 7, 0, _140_qua__stew_d, _140_qua__stew_ha },
+ { "stir", 7, 0, _140_qua__stir_d, _140_qua__stir_ha },
+
+ { "pfix", 7, _140_qua_pfix_a, 0, _140_qua_pfix_ha },
+ { "plug", 7, _140_qua_plug_a, 0, _140_qua_plug_ha },
+ { "pose", 7, _140_qua_pose_a, 0, _140_qua_pose_ha },
+ { "sfix", 7, _140_qua_sfix_a, 0, _140_qua_sfix_ha },
+
+ { "mink", 7, _140_qua_mink_a, 0, _140_qua_mink_ha },
+ { "mole", 7, _140_qua_mole_a, 0, _140_qua_mole_ha },
+ { "mule", 7, _140_qua_mule_a, 0, _140_qua_mule_ha },
+
+ { "scot", 7, _140_qua_scot_a, 0, _140_qua_scot_ha },
+ { "scow", 7, _140_qua_scow_a, 0, _140_qua_scow_ha },
+ { "slaw", 7, _140_qua_slaw_a, 0, _140_qua_slaw_ha },
+ {}
+};
+static c3_c* _140_qua_ha[] = {
+ "db9b4b21c0a8a8324105cbccc1421ef2a715ef0562c280b943fe1d96651cd9cc",
+ 0
+};
+
+static u3j_hood _140_qua_ho[] = {
+ { "mute", 0x2fbabe },
+ { "show", 24406 },
+ { "mure", 1404 },
+ {},
+};
+
+
+/* layer three
+*/
+ static u3j_harm _140_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}};
+ static c3_c* _140_tri__cofl__drg_ha[] = {
+ "6063adb8cac639f7b20d5e7700c8108266be04f99cce4434f906240b424bf36d",
+ 0
+ };
+ static u3j_harm _140_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}};
+ static c3_c* _140_tri__cofl__lug_ha[] = {
+ "f146a84731447e5c4b1e7b6e9331b33d1babed09bb0618e134c9535062154a87",
+ 0
+ };
+static u3j_core _140_tri__cofl_d[] =
+ { { "drg", 7, _140_tri__cofl__drg_a, 0, _140_tri__cofl__drg_ha },
+ { "lug", 7, _140_tri__cofl__lug_a, 0, _140_tri__cofl__lug_ha },
+ {}
+ };
+static c3_c* _140_tri__cofl_ha[] = {
+ "f320c5bf51db85f55b900f4160f7e0ab9ef267f43ddb698900de034c6e2600d5",
+ 0
+};
+
+ static u3j_harm _140_tri__rd_add_a[] = {{".2", u3wer_add}, {}};
+ static c3_c* _140_tri__rd_add_ha[] = {
+ "90dfaaadb2878d6d89a808ce4199e5bb239fa981e1c2edf24dc54aa3fcab55a5",
+ 0
+ };
+ static u3j_harm _140_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}};
+ static c3_c* _140_tri__rd_sub_ha[] = {
+ "5898a2424ba815d66d83917953f01860e63207f4200a447f632d9a5cc77a8a9c",
+ 0
+ };
+ static u3j_harm _140_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}};
+ static c3_c* _140_tri__rd_mul_ha[] = {
+ "a3af44ef4cd89afe78f1088bddb7d56dfa7fc209153256557c98ff34b67976bc",
+ 0
+ };
+ static u3j_harm _140_tri__rd_div_a[] = {{".2", u3wer_div}, {}};
+ static c3_c* _140_tri__rd_div_ha[] = {
+ "9be3b38b9b4b0b0cd0bb060529c8f439cb0589aa9c3528efc519fbcc6845e98d",
+ 0
+ };
+ static u3j_harm _140_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}};
+ static c3_c* _140_tri__rd_sqt_ha[] = {
+ "0413678ac8ec89c3425ba762cd24b2a8a455543ec9b5dd719524e6b834e0c99c",
+ 0
+ };
+ static u3j_harm _140_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}};
+ static c3_c* _140_tri__rd_fma_ha[] = {
+ "7c920238dd42fb645c057cc950ed7ece775d5f502a0faf6ef5d17d348e0fc3e3",
+ 0
+ };
+ static u3j_harm _140_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}};
+ static c3_c* _140_tri__rd_lth_ha[] = {
+ "a108f1ac15c1d4e2c86457c9afc97a97a5954003c709c3c19c722b37255bcba9",
+ 0
+ };
+ static u3j_harm _140_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}};
+ static c3_c* _140_tri__rd_lte_ha[] = {
+ "ef9a6b2c5cdd0d4de550a32679d242693131cdc3cf40ac914eadfa7d6d9f1bac",
+ 0
+ };
+ static u3j_harm _140_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}};
+ static c3_c* _140_tri__rd_equ_ha[] = {
+ "c93cdb951dca3b0ac61070780f95e1baa3718fe519d0268305c032cf14a21e39",
+ 0
+ };
+ static u3j_harm _140_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}};
+ static c3_c* _140_tri__rd_gte_ha[] = {
+ "6857077d97e2fc203b555dc20748c33d34b694d33c48f628543bea6491e722a6",
+ 0
+ };
+ static u3j_harm _140_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}};
+ static c3_c* _140_tri__rd_gth_ha[] = {
+ "87fd815913fa590c715d3a96ada5bae6298f3e7823af90ffcdf235f493c56330",
+ 0
+ };
+static u3j_core _140_tri__rd_d[] =
+ { { "add", 7, _140_tri__rd_add_a, 0, _140_tri__rd_add_ha },
+ { "sub", 7, _140_tri__rd_sub_a, 0, _140_tri__rd_sub_ha },
+ { "mul", 7, _140_tri__rd_mul_a, 0, _140_tri__rd_mul_ha },
+ { "div", 7, _140_tri__rd_div_a, 0, _140_tri__rd_div_ha },
+ { "sqt", 7, _140_tri__rd_sqt_a, 0, _140_tri__rd_sqt_ha },
+ { "fma", 7, _140_tri__rd_fma_a, 0, _140_tri__rd_fma_ha },
+ { "lth", 7, _140_tri__rd_lth_a, 0, _140_tri__rd_lth_ha },
+ { "lte", 7, _140_tri__rd_lte_a, 0, _140_tri__rd_lte_ha },
+ { "equ", 7, _140_tri__rd_equ_a, 0, _140_tri__rd_equ_ha },
+ { "gte", 7, _140_tri__rd_gte_a, 0, _140_tri__rd_gte_ha },
+ { "gth", 7, _140_tri__rd_gth_a, 0, _140_tri__rd_gth_ha },
+ {}
+ };
+static c3_c* _140_tri__rd_ha[] = {
+ "0afab285837f9c88faff3ac8f3f49b5e259da253e0505cd823a53d4e826261f7",
+ 0
+};
+
+ static u3j_harm _140_tri__rs_add_a[] = {{".2", u3wet_add}, {}};
+ static c3_c* _140_tri__rs_add_ha[] = {
+ "b89a1e348628fd9b4fd520aabbf6c53e12be5bbf661b9094f7a9841be3f51de9",
+ 0
+ };
+ static u3j_harm _140_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}};
+ static c3_c* _140_tri__rs_sub_ha[] = {
+ "9d13b86d17908830f93b920e80e1a985105583597f6fb640f175c98052e357f1",
+ 0
+ };
+ static u3j_harm _140_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}};
+ static c3_c* _140_tri__rs_mul_ha[] = {
+ "5c61a9e335f6c139332523d871ca5773ab476365b623444370474fde08639061",
+ 0
+ };
+ static u3j_harm _140_tri__rs_div_a[] = {{".2", u3wet_div}, {}};
+ static c3_c* _140_tri__rs_div_ha[] = {
+ "a7147a81be3ef5a1c0de6587edb2990e30057d7871d73632eabc8dc567e751c8",
+ 0
+ };
+ static u3j_harm _140_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}};
+ static c3_c* _140_tri__rs_sqt_ha[] = {
+ "c403bb48d78bcfa9cd4128b7f9eb362e71e5269ab6578fb0bb5e70b4244c5781",
+ 0
+ };
+ static u3j_harm _140_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}};
+ static c3_c* _140_tri__rs_fma_ha[] = {
+ "afc14914eb8f579a0c6620db69bc951329325747a8ef01c2d0e5feb29e9a9ddd",
+ 0
+ };
+ static u3j_harm _140_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}};
+ static c3_c* _140_tri__rs_lth_ha[] = {
+ "e7efa422def6b6dbd25b5f664462adb3895b8b45f9531877c9dbfe40a96612bf",
+ 0
+ };
+ static u3j_harm _140_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}};
+ static c3_c* _140_tri__rs_lte_ha[] = {
+ "b45e1ef16c47dc9b99865c7e75d4c2094c0e206ed538818a38da0adb7fbe2ce3",
+ 0
+ };
+ static u3j_harm _140_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}};
+ static c3_c* _140_tri__rs_equ_ha[] = {
+ "8c1178311ded837292c297380e48cf7e0bc4d83962dadcafda0c9ef9f20e39f2",
+ 0
+ };
+ static u3j_harm _140_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}};
+ static c3_c* _140_tri__rs_gte_ha[] = {
+ "50f5eb237b74e772eb6a3257441078461450cd4a25cf9bd97cb1a5e00f4ff4d2",
+ 0
+ };
+ static u3j_harm _140_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}};
+ static c3_c* _140_tri__rs_gth_ha[] = {
+ "505842ff486f0bb8fa63f04d2fd6f806dc760f9b4a12a3bf2d57da92f560785b",
+ 0
+ };
+static u3j_core _140_tri__rs_d[] =
+ { { "add", 7, _140_tri__rs_add_a, 0, _140_tri__rs_add_ha },
+ { "sub", 7, _140_tri__rs_sub_a, 0, _140_tri__rs_sub_ha },
+ { "mul", 7, _140_tri__rs_mul_a, 0, _140_tri__rs_mul_ha },
+ { "div", 7, _140_tri__rs_div_a, 0, _140_tri__rs_div_ha },
+ { "sqt", 7, _140_tri__rs_sqt_a, 0, _140_tri__rs_sqt_ha },
+ { "fma", 7, _140_tri__rs_fma_a, 0, _140_tri__rs_fma_ha },
+ { "lth", 7, _140_tri__rs_lth_a, 0, _140_tri__rs_lth_ha },
+ { "lte", 7, _140_tri__rs_lte_a, 0, _140_tri__rs_lte_ha },
+ { "equ", 7, _140_tri__rs_equ_a, 0, _140_tri__rs_equ_ha },
+ { "gte", 7, _140_tri__rs_gte_a, 0, _140_tri__rs_gte_ha },
+ { "gth", 7, _140_tri__rs_gth_a, 0, _140_tri__rs_gth_ha },
+ {}
+ };
+static c3_c* _140_tri__rs_ha[] = {
+ "6c7027c5de34540a4b1548039e5423fb44727079af054b7135a3e961ec8dede8",
+ 0
+};
+
+ static u3j_harm _140_tri__rq_add_a[] = {{".2", u3weq_add}, {}};
+ static c3_c* _140_tri__rq_add_ha[] = {
+ "9c4c2a37550930605495401886d41fb9fbc2eba487e0ba845130fe88e4c52a01",
+ 0
+ };
+ static u3j_harm _140_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}};
+ static c3_c* _140_tri__rq_sub_ha[] = {
+ "f3b027090a1bb5af74234301facfbf64503b3e0599501ade12cb05aa158a79a3",
+ 0
+ };
+ static u3j_harm _140_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}};
+ static c3_c* _140_tri__rq_mul_ha[] = {
+ "15c03b1f3081514c4767d86297aaebf1d62af7f3437f30821f011b17ed769f3a",
+ 0
+ };
+ static u3j_harm _140_tri__rq_div_a[] = {{".2", u3weq_div}, {}};
+ static c3_c* _140_tri__rq_div_ha[] = {
+ "094105c77e37e548ea1b8d49a132ab97d90a0ab5f329340400c381bcd44de347",
+ 0
+ };
+ static u3j_harm _140_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}};
+ static c3_c* _140_tri__rq_sqt_ha[] = {
+ "a031cd5b8e05f997323b0ca1ca9d2419401d7d2acc2da6fc6387fe57701b84b0",
+ 0
+ };
+ static u3j_harm _140_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}};
+ static c3_c* _140_tri__rq_fma_ha[] = {
+ "871664a9305808a671aacf1de0e83f8e951611033170d86370352afb363b79bc",
+ 0
+ };
+ static u3j_harm _140_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}};
+ static c3_c* _140_tri__rq_lth_ha[] = {
+ "b10822caa442c8e9f6b9eb52aac5796a42bed5ae0eef7fe49d4075b38bf78ddd",
+ 0
+ };
+ static u3j_harm _140_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}};
+ static c3_c* _140_tri__rq_lte_ha[] = {
+ "3316346be3e9464fbb5b0feff16cd2252086004229d08f8eaa320f9509d6a029",
+ 0
+ };
+ static u3j_harm _140_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}};
+ static c3_c* _140_tri__rq_equ_ha[] = {
+ "154be82a7b8ecf4571015d9ef6c0e90ffd8c3e8803441d9c2df5a4ea484ccf3b",
+ 0
+ };
+ static u3j_harm _140_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}};
+ static c3_c* _140_tri__rq_gte_ha[] = {
+ "edbe94f9cfefa89deef7f6c11f4ce8240fd93970dbd6130e632d0447452a612a",
+ 0
+ };
+ static u3j_harm _140_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}};
+ static c3_c* _140_tri__rq_gth_ha[] = {
+ "50e85936cfad61659ed1bfdab26fda2b2696571b9aa4b4c55dc5c0d919edc296",
+ 0
+ };
+static u3j_core _140_tri__rq_d[] =
+ { { "add", 7, _140_tri__rq_add_a, 0, _140_tri__rq_add_ha },
+ { "sub", 7, _140_tri__rq_sub_a, 0, _140_tri__rq_sub_ha },
+ { "mul", 7, _140_tri__rq_mul_a, 0, _140_tri__rq_mul_ha },
+ { "div", 7, _140_tri__rq_div_a, 0, _140_tri__rq_div_ha },
+ { "sqt", 7, _140_tri__rq_sqt_a, 0, _140_tri__rq_sqt_ha },
+ { "fma", 7, _140_tri__rq_fma_a, 0, _140_tri__rq_fma_ha },
+ { "lth", 7, _140_tri__rq_lth_a, 0, _140_tri__rq_lth_ha },
+ { "lte", 7, _140_tri__rq_lte_a, 0, _140_tri__rq_lte_ha },
+ { "equ", 7, _140_tri__rq_equ_a, 0, _140_tri__rq_equ_ha },
+ { "gte", 7, _140_tri__rq_gte_a, 0, _140_tri__rq_gte_ha },
+ { "gth", 7, _140_tri__rq_gth_a, 0, _140_tri__rq_gth_ha },
+ {}
+ };
+static c3_c* _140_tri__rq_ha[] = {
+ "b772cd5901a18dc91852fada74c2a1e4b1bbf4e7465451b0d8bdcc86d2288c22",
+ 0
+};
+
+ static u3j_harm _140_tri__rh_add_a[] = {{".2", u3wes_add}, {}};
+ static c3_c* _140_tri__rh_add_ha[] = {
+ "7e2b600eced08d774800a6a3d82e18189db85010b870c26905ee38008d3d301e",
+ 0
+ };
+ static u3j_harm _140_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}};
+ static c3_c* _140_tri__rh_sub_ha[] = {
+ "827dfb41660cb4743a88d921b4185bd2000ee6f0708ec36ac8aba2e4e19c0875",
+ 0
+ };
+ static u3j_harm _140_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}};
+ static c3_c* _140_tri__rh_mul_ha[] = {
+ "ec2a010128aca0a6f74196f3de4fe7b6617fd810d3b19f7bf5878afb787e8b86",
+ 0
+ };
+ static u3j_harm _140_tri__rh_div_a[] = {{".2", u3wes_div}, {}};
+ static c3_c* _140_tri__rh_div_ha[] = {
+ "067a3dafb0158bc2441729beb2c0934c6c6ccf0a9b5193db9c16f22b490b27c6",
+ 0
+ };
+ static u3j_harm _140_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}};
+ static c3_c* _140_tri__rh_sqt_ha[] = {
+ "3fdbba47626d91d41fcdf460ad38018c78b0233d7ec4d0fac406a8c5357a2384",
+ 0
+ };
+ static u3j_harm _140_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}};
+ static c3_c* _140_tri__rh_fma_ha[] = {
+ "ada2adf5a88ba61759219926aef950e72ae6926c6e10c30ecd0f9c99e79beca0",
+ 0
+ };
+ static u3j_harm _140_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}};
+ static c3_c* _140_tri__rh_lth_ha[] = {
+ "70c9bc0073d23371d8155c28795f5acbff1a9504a5a3881c8693aa7c1f3d35d4",
+ 0
+ };
+ static u3j_harm _140_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}};
+ static c3_c* _140_tri__rh_lte_ha[] = {
+ "6157e766050f9697c05b111ad2a582459a63a98b3b1ec70881f9ad943f951a0d",
+ 0
+ };
+ static u3j_harm _140_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}};
+ static c3_c* _140_tri__rh_equ_ha[] = {
+ "72664392e2a00137383aa5a55e947c5e95c7b3172f71a7238dc0d55050196884",
+ 0
+ };
+ static u3j_harm _140_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}};
+ static c3_c* _140_tri__rh_gte_ha[] = {
+ "145355b13712b9471031e755d0ab271907efdb9a287b1bacb2f1d0338d28dbf6",
+ 0
+ };
+ static u3j_harm _140_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}};
+ static c3_c* _140_tri__rh_gth_ha[] = {
+ "d53219ee10acdd291a1e2b34fa5f543c780a0301357e93cfebd466e556f9824e",
+ 0
+ };
+static u3j_core _140_tri__rh_d[] =
+ { { "add", 7, _140_tri__rh_add_a, 0, _140_tri__rh_add_ha },
+ { "sub", 7, _140_tri__rh_sub_a, 0, _140_tri__rh_sub_ha },
+ { "mul", 7, _140_tri__rh_mul_a, 0, _140_tri__rh_mul_ha },
+ { "div", 7, _140_tri__rh_div_a, 0, _140_tri__rh_div_ha },
+ { "sqt", 7, _140_tri__rh_sqt_a, 0, _140_tri__rh_sqt_ha },
+ { "fma", 7, _140_tri__rh_fma_a, 0, _140_tri__rh_fma_ha },
+ { "lth", 7, _140_tri__rh_lth_a, 0, _140_tri__rh_lth_ha },
+ { "lte", 7, _140_tri__rh_lte_a, 0, _140_tri__rh_lte_ha },
+ { "equ", 7, _140_tri__rh_equ_a, 0, _140_tri__rh_equ_ha },
+ { "gte", 7, _140_tri__rh_gte_a, 0, _140_tri__rh_gte_ha },
+ { "gth", 7, _140_tri__rh_gth_a, 0, _140_tri__rh_gth_ha },
+ {}
+ };
+static c3_c* _140_tri__rh_ha[] = {
+ "c38f8c0a7e2f1fccb52c459f60a30ec5d21635cafaf1aa120b70c1fa91cf7da5",
+ 0
+};
+
+ static u3j_harm _140_tri__og_raw_a[] = {{".2", u3weo_raw}, {}};
+ static c3_c* _140_tri__og_raw_ha[] = {
+ "bbcbefc237dbebf6c141ba14fd9e0464a836127fd123d10da5f121e82d49ebdb",
+ 0
+ };
+static u3j_core _140_tri__og_d[] =
+ { { "raw", 7, _140_tri__og_raw_a, 0, _140_tri__og_raw_ha },
+ {}
+ };
+static c3_c* _140_tri__og_ha[] = {
+ "74b9ae67eeabbffcff969ac7fdc7f4f0f4f67af64931e969bcac50d084e15fc0",
+ 0
+};
+
+ static u3j_harm _140_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}};
+ static c3_c* _140_tri__sha_sha1_ha[] = {
+ "75aababa0688619d9df36238269119302a64ad2e3c69c53bd0057fe6b1abaf0c",
+ 0
+ };
+static u3j_core _140_tri__sha_d[] =
+ { { "sha1", 7, _140_tri__sha_sha1_a, 0, _140_tri__sha_sha1_ha },
+ {}
+ };
+static c3_c* _140_tri__sha_ha[] = {
+ "3c22d2f8719cb626e8dfe1a4206bcbc14b678c1422c48322054b40f84416d557",
+ 0
+};
+
+static u3j_harm _140_tri_shax_a[] = {{".2", u3we_shax}, {}};
+static c3_c* _140_tri_shax_ha[] = {
+ "0fc53de3ddc8b8f84a46136f1728fa3ed66a5113888d14907589d16bf5927ad8",
+ 0
+};
+static u3j_harm _140_tri_shay_a[] = {{".2", u3we_shay}, {}};
+static c3_c* _140_tri_shay_ha[] = {
+ "b6dbc72e15c2204f83f902619b7a60328f29c9d302ddb35c435111dea28c5470",
+ 0
+};
+static u3j_harm _140_tri_shas_a[] = {{".2", u3we_shas}, {}};
+static c3_c* _140_tri_shas_ha[] = {
+ "5230583767b7625b3496248ed03b6b94c1d4ee9b26342f9390bf999ec9b6cfdb",
+ 0
+};
+static u3j_harm _140_tri_shal_a[] = {{".2", u3we_shal}, {}};
+static c3_c* _140_tri_shal_ha[] = {
+ "3242912e29e3e1ed8d1a395cc860a82d78961b4278ed79bbdeb37cb5615bbf20",
+ 0
+};
+
+ static u3j_harm _140_ob_fein_a[] = {{".2", u3we_fein_ob}, {}};
+ static c3_c* _140_ob_fein_ha[] = {
+ 0
+ };
+ static u3j_harm _140_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}};
+ static c3_c* _140_ob_fynd_ha[] = {
+ 0
+ };
+static u3j_core _140_ob_d[] = {
+ { "fein", 7, _140_ob_fein_a, 0, _140_ob_fein_ha },
+ { "fynd", 7, _140_ob_fynd_a, 0, _140_ob_fynd_ha },
+ {}
+};
+static c3_c* _140_ob_ha[] = {
+ "13ebfbdee69396bc1d980fc4dcbcdaa9cc3fb9c011e6cf188e71311a8bffc8e6",
+ 0
+};
+static u3j_hood _140_ob_ho[] = {
+ { "fein", 42 },
+ { "fynd", 20 },
+ {},
+};
+
+static u3j_core _140_tri_d[] =
+{ { "qua", 3, 0, _140_qua_d, _140_qua_ha, _140_qua_ho },
+
+ { "cofl", 7, 0, _140_tri__cofl_d, _140_tri__cofl_ha },
+ { "rd", 7, 0, _140_tri__rd_d, _140_tri__rd_ha },
+ { "rs", 7, 0, _140_tri__rs_d, _140_tri__rs_ha },
+ { "rq", 7, 0, _140_tri__rq_d, _140_tri__rq_ha },
+ { "rh", 7, 0, _140_tri__rh_d, _140_tri__rh_ha },
+ { "og", 7, 0, _140_tri__og_d, _140_tri__og_ha },
+
+ { "sha", 7, 0, _140_tri__sha_d, _140_tri__sha_ha },
+ { "shax", 7, _140_tri_shax_a, 0, _140_tri_shax_ha },
+ { "shay", 7, _140_tri_shay_a, 0, _140_tri_shay_ha },
+ { "shas", 7, _140_tri_shas_a, 0, _140_tri_shas_ha },
+ { "shal", 7, _140_tri_shal_a, 0, _140_tri_shal_ha },
+
+ { "ob", 3, 0, _140_ob_d, _140_ob_ha, _140_ob_ho },
+ {}
+};
+static c3_c* _140_tri_ha[] = {
+ "e7339eb317038f64555717c5624e4571fe9654d471c1a78454129afdbcad9b53",
+ 0
+};
+
+static u3j_hood _140_tri_ho[] = {
+ { "ob", 20 },
+ { "yore", 5462 },
+ { "year", 44975 },
+ {},
+};
+
+
+/* layer two
+*/
+static u3j_harm _140_two_find_a[] = {{".2", u3wb_find, c3y}, {}};
+static c3_c* _140_two_find_ha[] = {
+ "cab18d537962b48d38fa061844f44c4635ee11c74fdf403aa80d3a6d1b15c177",
+ 0
+};
+static u3j_harm _140_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}};
+static c3_c* _140_two_flop_ha[] = {
+ "73d496aac2ce6fd9475645c76f949ae0228f8f5ae6738529b08ed9aeb58255fe",
+ 0
+};
+static u3j_harm _140_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}};
+static c3_c* _140_two_lent_ha[] = {
+ "1b98ab19350f6a6753ea4bd6daf4509a7c5681b7ac20c83204fe62846d46c2c3",
+ 0
+};
+static u3j_harm _140_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}};
+static c3_c* _140_two_levy_ha[] = {
+ "634f1f506b17b4b50e6902f6e21b290ffc5305d1546075cba745c9e195fcc56b",
+ 0
+};
+static u3j_harm _140_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}};
+static c3_c* _140_two_lien_ha[] = {
+ "2ffb70864f2be120b48869b27c614aadeed1390bde497d8940fe85b7861093ea",
+ 0
+};
+static u3j_harm _140_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}};
+static c3_c* _140_two_murn_ha[] = {
+ "53257aaee131c2a892529c2ee75271160811814086456e8fdf249eebdf31b990",
+ 0
+};
+static u3j_harm _140_two_need_a[] = {{".2", u3wb_need, c3y}, {}};
+static c3_c* _140_two_need_ha[] = {
+ "bfdd39af478811efe816e69e8c9202d10c41f646c0d27f39c23e4fe1aec807dd",
+ 0
+};
+static u3j_harm _140_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}};
+static c3_c* _140_two_reap_ha[] = {
+ "cf6bd10b97b418b67c645374712c768d9e7e9809c14ecf36a5c507e5fc4b4039",
+ 0
+};
+static u3j_harm _140_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}};
+static c3_c* _140_two_reel_ha[] = {
+ "36108d1ba09617cf62e739e0ff2dcf9286f322ca0e8faa3521ef127e9840eebf",
+ 0
+};
+static u3j_harm _140_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}};
+static c3_c* _140_two_roll_ha[] = {
+ "42abc6b3defd7c5eb8f6d14d57a14ba2a02d559907c03141c70a65e0803c01e5",
+ 0
+};
+static u3j_harm _140_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}};
+static c3_c* _140_two_skid_ha[] = {
+ "832366432a85005f9a9849d6de9a9045c8f9a591050519b06aec6a9a1a54c360",
+ 0
+};
+static u3j_harm _140_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}};
+static c3_c* _140_two_skim_ha[] = {
+ "ccbecb459b90d05ed6c1073859a58987bf9a479820b5550fa75f37b95f98a279",
+ 0
+};
+static u3j_harm _140_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}};
+static c3_c* _140_two_skip_ha[] = {
+ "873e3e4d6b8f16212911aa982065dd0d36b1f6e8834828d5eb5d59afa9da2384",
+ 0
+};
+static u3j_harm _140_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}};
+static c3_c* _140_two_scag_ha[] = {
+ "ddba868a28eb9655c9f6e06cfecb4ec9e9ff78277290579b9bb9b25339bb4ab9",
+ 0
+};
+static u3j_harm _140_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}};
+static c3_c* _140_two_slag_ha[] = {
+ "811f7f67de7ab3f33b85198a69b1bf344498cd4922b0273d918a48b803b7877d",
+ 0
+};
+static u3j_harm _140_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}};
+static c3_c* _140_two_snag_ha[] = {
+ "12a1d53541d4df9be60bda45f2dae6c6e6381f85edd4de062af23c6654860591",
+ 0
+};
+static u3j_harm _140_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}};
+static c3_c* _140_two_sort_ha[] = {
+ "dc14f91fdedacd3b77bdf241d22555fe2bf0a231e9cab58b4ae779791e54c4e7",
+ 0
+};
+static u3j_harm _140_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}};
+static c3_c* _140_two_turn_ha[] = {
+ "e13d9f52434ba810e182017f50a73d4d44eaa298a833231e90353f2a32ea6a78",
+ 0
+};
+static u3j_harm _140_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}};
+static c3_c* _140_two_weld_ha[] = {
+ "d855628821d57392f575c5da000c7326eaaa19e08cda967a4772859269669df2",
+ 0
+};
+static u3j_harm _140_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}};
+static c3_c* _140_two_welp_ha[] = {
+ "0bccae6625e62ce622c62f9e828a2a6469e2fbf42342d95e23c3b926f340140d",
+ 0
+};
+static u3j_harm _140_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}};
+static c3_c* _140_two_zing_ha[] = {
+ "113bdea043e9e05cf4a63dac793caf34634bc58414d00250af87139405521b9d",
+ 0
+};
+
+static u3j_harm _140_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}};
+static c3_c* _140_two_bex_ha[] = {
+ "ee7a095ea21b6438ec19ab235e73877b96108f0a14cae02cecbd8a48c44e70e3",
+ 0
+};
+static u3j_harm _140_two_can_a[] = {{".2", u3wc_can, c3y}, {}};
+static c3_c* _140_two_can_ha[] = {
+ "c49ee52487369ba17a0105a61aa658df60e7a537e3e8737ab582644fe00b3938",
+ 0
+};
+static u3j_harm _140_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}};
+static c3_c* _140_two_cat_ha[] = {
+ "467f007931110ac0755dcd44c5aaee65785a63b9042b8eea6a7838fa86cc5d8f",
+ 0
+};
+static u3j_harm _140_two_con_a[] = {{".2", u3wc_con, c3y}, {}};
+static c3_c* _140_two_con_ha[] = {
+ "d20f091bd4f28d37c1a78373df939f3d3a41e025129e9a2bb5e2b9a710358965",
+ 0
+};
+static u3j_harm _140_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}};
+static c3_c* _140_two_cut_ha[] = {
+ "96bb4e9a259d6a1ede5461956b6a6fb73f05cb8e745c4803c2bae4ec0b7f0800",
+ 0
+};
+static u3j_harm _140_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}};
+static c3_c* _140_two_dis_ha[] = {
+ "4b3987314451e20a45d2c7baff51d5d39be57e5970f23f86df4dd6569826ddff",
+ 0
+};
+static u3j_harm _140_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}};
+static c3_c* _140_two_dor_ha[] = {
+ "277927a2e49e4d942e81ffc7740a71e68a7b732df886a9f84dc7d914be911879",
+ 0
+};
+static u3j_harm _140_two_end_a[] = {{".2", u3wc_end, c3y}, {}};
+static c3_c* _140_two_end_ha[] = {
+ "403c9f12f2481966ffb07842006713149960c67c6bcad8edd78cdf837bc0d854",
+ 0
+};
+static u3j_harm _140_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}};
+static c3_c* _140_two_gor_ha[] = {
+ "8a1e3ed1de749ff2ff61d489466df618e4e0773498cb9693ec2e612e9733385c",
+ 0
+};
+static u3j_harm _140_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}};
+static c3_c* _140_two_lsh_ha[] = {
+ "3db89b02bc596a57c7fb72a991c9fbf3197de501c56b3d1df26911b664c45f3d",
+ 0
+};
+static u3j_harm _140_two_met_a[] = {{".2", u3wc_met, c3y}, {}};
+static c3_c* _140_two_met_ha[] = {
+ "39dc9b1d10d9e93414b43f315f9a375596c99b4e8172d71d26759996bb7bab08",
+ 0
+};
+static u3j_harm _140_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}};
+static c3_c* _140_two_mix_ha[] = {
+ "c84b3e487850d73dd5e4af18fb54b623028be3c45ae9b712718754233057fbc3",
+ 0
+};
+static u3j_harm _140_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}};
+static c3_c* _140_two_mor_ha[] = {
+ "7c2d86e952606e571e5bcd988e70ded072c0eaa45d1fd958849d76360a763ddf",
+ 0
+};
+static u3j_harm _140_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}};
+static c3_c* _140_two_mug_ha[] = {
+ "6da3f3aa1e951ef2d00e5131945d140fb52728558867237891e029160b7f5010",
+ 0
+};
+static u3j_harm _140_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}};
+static c3_c* _140_two_muk_ha[] = {
+ "5a04a09bf7d22c8ef048ba2cc86be8f3a02066eab84cf4a45bbdf2bf534ff9f6",
+ 0
+};
+static u3j_harm _140_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}};
+static c3_c* _140_two_pow_ha[] = {
+ "6cfcb9da6ad812eb72788e22e1370b4ab1b6ab64ab0628dfdff78ccead325406",
+ 0
+};
+static u3j_harm _140_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}};
+static c3_c* _140_two_rap_ha[] = {
+ "f694f96bcbf97b339285d6c73ed5d33d112b911f7a991acefdef223ff01d8834",
+ 0
+};
+static u3j_harm _140_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}};
+static c3_c* _140_two_rep_ha[] = {
+ "25aa2f1746e1cf2235117f22a3db152fa86e003d9bf9f9cfcda79e76e51f382f",
+ 0
+};
+static u3j_harm _140_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}};
+static c3_c* _140_two_rev_ha[] = {
+ "15e20592ac1d9c0c80d99589e67cadb4ed7566be1d21844bbe7ef936e0db4524",
+ 0
+};
+static u3j_harm _140_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}};
+static c3_c* _140_two_rip_ha[] = {
+ "16026c27499953978f69dbf81c1530b2dec8d5a2403c5561f7a5afcc180e129e",
+ 0
+};
+static u3j_harm _140_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}};
+static c3_c* _140_two_rsh_ha[] = {
+ "55bd777f239a2a7c849e0c7a35bb967b79279c79bbd985f31ba272761f97928f",
+ 0
+};
+static u3j_harm _140_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}};
+static c3_c* _140_two_swp_ha[] = {
+ "2c4583c36d73c9c2857052b893b87e1170a794e0edbbdba9d767ba7639e7c1ec",
+ 0
+};
+static u3j_harm _140_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}};
+static c3_c* _140_two_sqt_ha[] = {
+ "fc28ff327ae69f55ccf257b69a1477b845552ef9e615e85718902c249bdeca6f",
+ 0
+};
+static u3j_harm _140_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}};
+static c3_c* _140_two_xeb_ha[] = {
+ "41403aafe1e2ccb1a02edde96fe742085feffe028d02529eb2b13f925884a499",
+ 0
+};
+
+ static u3j_harm _140_two__in_apt_a[] = {{".2", u3wdi_apt_140}, {}};
+ static c3_c* _140_two__in_apt_ha[] = {
+ "a40812fa255f13afdaf196bff38d2d9bfcb38f09c48ace9139a2701a555a0c9a",
+ 0
+ };
+ static u3j_harm _140_two__in_bif_a[] = {{".2", u3wdi_bif}, {}};
+ static c3_c* _140_two__in_bif_ha[] = {
+ "edd0d727b9099e75c3e5b73b3025ad9737136eacedc2f8088b6edb02dbe06cb3",
+ 0
+ };
+ static u3j_harm _140_two__in_del_a[] = {{".2", u3wdi_del}, {}};
+ static c3_c* _140_two__in_del_ha[] = {
+ "33a21e7aaf71105e2d48e1af61ff463fb8a0b7e04f8a8c30a6f6a2d1f967795f",
+ 0
+ };
+ static u3j_harm _140_two__in_dif_a[] = {{".2", u3wdi_dif}, {}};
+ static c3_c* _140_two__in_dif_ha[] = {
+ "a488f0be5adbb1c04e2038a2315ac065591e7daadcafc1d47aea272979680468",
+ 0
+ };
+ static u3j_harm _140_two__in_gas_a[] = {{".2", u3wdi_gas}, {}};
+ static c3_c* _140_two__in_gas_ha[] = {
+ "223a60a43a10f1f90a3b205ecfce8e17af1adfcf9dbf3cff9b8b1362656b1af1",
+ 0
+ };
+ static u3j_harm _140_two__in_has_a[] = {{".2", u3wdi_has}, {}};
+ static c3_c* _140_two__in_has_ha[] = {
+ "a65e666e92176401040a883801e4f05bd650fe6c094a6c8d7f4afcaee9cf55ad",
+ 0
+ };
+ static u3j_harm _140_two__in_int_a[] = {{".2", u3wdi_int}, {}};
+ static c3_c* _140_two__in_int_ha[] = {
+ "a71b0e355fa02d18447c02922f69096f42043da451e8c79e7a9270460c3a44e6",
+ 0
+ };
+ static u3j_harm _140_two__in_put_a[] = {{".2", u3wdi_put}, {}};
+ static c3_c* _140_two__in_put_ha[] = {
+ "19b27267e18ef156d85d84d37e02692a17fec0b7a2a0fe4120a3ae02b841c8f4",
+ 0
+ };
+ static u3j_harm _140_two__in_rep_a[] = {{".2", u3wdi_rep}, {}};
+ static c3_c* _140_two__in_rep_ha[] = {
+ "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7",
+ 0
+ };
+ static u3j_harm _140_two__in_run_a[] = {{".2", u3wdi_run}, {}};
+ static c3_c* _140_two__in_run_ha[] = {
+ "7f2061dbee19fa20925bd5a80cc41ed71e462e0f49ee6e845fd750c219734864",
+ 0
+ };
+ static u3j_harm _140_two__in_tap_a[] = {{".2", u3wdi_tap}, {}};
+ static c3_c* _140_two__in_tap_ha[] = {
+ "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352",
+ 0
+ };
+ static u3j_harm _140_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}};
+ static c3_c* _140_two__in_wyt_ha[] = {
+ "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0",
+ 0
+ };
+ static u3j_harm _140_two__in_uni_a[] = {{".2", u3wdi_uni}, {}};
+ static c3_c* _140_two__in_uni_ha[] = {
+ "6bd72ef1fb12482a839f4435a2b163ace1b56036297a3cec6968be33d6863096",
+ 0
+ };
+static u3j_core _140_two__in_d[] =
+ { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha },
+ { "bif", 7, _140_two__in_bif_a, 0, _140_two__in_bif_ha },
+ { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha },
+ { "dif", 7, _140_two__in_dif_a, 0, _140_two__in_dif_ha },
+ { "gas", 7, _140_two__in_gas_a, 0, _140_two__in_gas_ha },
+ { "has", 7, _140_two__in_has_a, 0, _140_two__in_has_ha },
+ { "int", 7, _140_two__in_int_a, 0, _140_two__in_int_ha },
+ { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha },
+ { "rep", 7, _140_two__in_rep_a, 0, _140_two__in_rep_ha },
+ { "run", 7, _140_two__in_run_a, 0, _140_two__in_run_ha },
+ { "tap", 7, _140_two__in_tap_a, 0, _140_two__in_tap_ha },
+ { "uni", 7, _140_two__in_uni_a, 0, _140_two__in_uni_ha },
+ { "wyt", 3, _140_two__in_wyt_a, 0, _140_two__in_wyt_ha },
+ {}
+ };
+static c3_c* _140_two__in_ha[] = {
+ "8bbb90ce0a49d627194aa267f6cf1fd78df677111b553ce03119fea19f9d763c",
+ 0
+};
+
+ static u3j_harm _140_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}};
+ static c3_c* _140_two__by_all_ha[] = {
+ "c2e87d0047c14b4488d03aad98fa43080c736d86d2ff723a037aaf1843aa9285",
+ 0
+ };
+ static u3j_harm _140_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}};
+ static c3_c* _140_two__by_any_ha[] = {
+ "96b95c942dcbc97f5291fa6f7342c3e19a87d69cc254965b0f75d95133a19301",
+ 0
+ };
+ static u3j_harm _140_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}};
+ static c3_c* _140_two__by_apt_ha[] = {
+ "1f0a6f8b945b243520b77069060589938d9e651e34b24924db9528d02a98014f",
+ 0
+ };
+
+ static u3j_harm _140_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}};
+ static c3_c* _140_two__by_del_ha[] = {
+ "09f78d6235d3fce8303c7bc663988349b7d4592abdacfb09b833d2f43629b6b6",
+ 0
+ };
+ static u3j_harm _140_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}};
+ static c3_c* _140_two__by_dif_ha[] = {
+ "0334e6df6fd0bd5013b94a1b22c29e4c436da0a2d5573f1992faad1c8a059cc7",
+ 0
+ };
+ static u3j_harm _140_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}};
+ static c3_c* _140_two__by_gas_ha[] = {
+ "43046602e0b9e568b09448cfe18527e2331f3393a2f32e485d9707a14c346698",
+ 0
+ };
+ static u3j_harm _140_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}};
+ static c3_c* _140_two__by_get_ha[] = {
+ "4de4cea8fa98ef48e9faae10c90ba5bd77971670030ffb00483d0608af4c466f",
+ 0
+ };
+ static u3j_harm _140_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}};
+ static c3_c* _140_two__by_has_ha[] = {
+ "04ecc67ab25961bee1b7c9dbcf42965d16f32474b9bbdd2b286983f998e3957a",
+ 0
+ };
+ static u3j_harm _140_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}};
+ static c3_c* _140_two__by_int_ha[] = {
+ "a2345429482c271a1668f3c0675a559452bb7b13cb7393c3acb7de44c603aef9",
+ 0
+ };
+ static u3j_harm _140_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}};
+ static c3_c* _140_two__by_jab_ha[] = {
+ "48930133d9b26e912dce54d1bc486cfe9dcb32bb3c2b1ad76143382799aec156",
+ 0
+ };
+ static u3j_harm _140_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}};
+ static c3_c* _140_two__by_key_ha[] = {
+ "0096c77b93e9fe36b98d9f433eb73300f024283b93b3d73a4001afb9f9804d1b",
+ 0
+ };
+ static u3j_harm _140_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}};
+ static c3_c* _140_two__by_put_ha[] = {
+ "b7307589fed604bfb92e8ad5ffad611c82d835baf02a86c6911b279930f4e8d7",
+ 0
+ };
+ static u3j_harm _140_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}};
+ static c3_c* _140_two__by_rep_ha[] = {
+ "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7",
+ 0
+ };
+ static u3j_harm _140_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}};
+ static c3_c* _140_two__by_run_ha[] = {
+ "adea01e9036e0b40e4969814d4eed935d7d69a52e4a55de5520df2fa5204d8e7",
+ 0
+ };
+ static u3j_harm _140_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}};
+ static c3_c* _140_two__by_tap_ha[] = {
+ "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352",
+ 0
+ };
+ static u3j_harm _140_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}};
+ static c3_c* _140_two__by_uni_ha[] = {
+ "f18bc4dac19abe14a6f56afc15d838b7394d48969156f4b37c3c84edd5d46752",
+ 0
+ };
+ static u3j_harm _140_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}};
+ static c3_c* _140_two__by_urn_ha[] = {
+ "a409cf78e7f1c2ce8440115730f74367839b658cde2d6a1daa8af067b790eb83",
+ 0
+ };
+ static u3j_harm _140_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}};
+ static c3_c* _140_two__by_wyt_ha[] = {
+ "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0",
+ 0
+ };
+static u3j_core _140_two__by_d[] =
+ { { "all", 7, _140_two__by_all_a, 0, _140_two__by_all_ha },
+ { "any", 7, _140_two__by_any_a, 0, _140_two__by_any_ha },
+ { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha },
+ // disabled due to interface change in %138
+ //
+ // { "bif", 7, _140_two__by_bif_a, 0, _140_two__by_bif_ha },
+ { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha },
+ { "dif", 7, _140_two__by_dif_a, 0, _140_two__by_dif_ha },
+ { "gas", 7, _140_two__by_gas_a, 0, _140_two__by_gas_ha },
+ { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha },
+ { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha },
+ { "int", 7, _140_two__by_int_a, 0, _140_two__by_int_ha },
+ { "jab", 7, _140_two__by_jab_a, 0, _140_two__by_jab_ha },
+ { "key", 7, _140_two__by_key_a, 0, _140_two__by_key_ha },
+ { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha },
+ { "rep", 7, _140_two__by_rep_a, 0, _140_two__by_rep_ha },
+ { "run", 7, _140_two__by_run_a, 0, _140_two__by_run_ha },
+ { "tap", 7, _140_two__by_tap_a, 0, _140_two__by_tap_ha },
+ { "uni", 7, _140_two__by_uni_a, 0, _140_two__by_uni_ha },
+ { "urn", 7, _140_two__by_urn_a, 0, _140_two__by_urn_ha },
+ { "wyt", 3, _140_two__by_wyt_a, 0, _140_two__by_wyt_ha },
+ {}
+ };
+static c3_c* _140_two__by_ha[] = {
+ "9c70e973de46335405a7ff932d4742743f54db579f2584758ef2b02afd4fbfe8",
+ 0
+};
+
+static u3j_harm _140_two_cue_a[] = {{".2", u3we_cue}, {}};
+static c3_c* _140_two_cue_ha[] = {
+ "a52b584c5a92fc653e47f50c3389caf3427e13d20ddb8bd701a2d7bca12cb742",
+ 0
+};
+static u3j_harm _140_two_jam_a[] = {{".2", u3we_jam}, {}};
+static c3_c* _140_two_jam_ha[] = {
+ "61f86be74cb1fd5a1d7f531cc9588f8f34a972be8de487c93d25c8e026592ed2",
+ 0
+};
+static u3j_harm _140_two_mat_a[] = {{".2", u3we_mat}, {}};
+static c3_c* _140_two_mat_ha[] = {
+ "b5cd9fd1eded54fcb9bfd06af3c34460c1aa4cfc46f1ee9bd3f6476aa8fbb8c8",
+ 0
+};
+static u3j_harm _140_two_rub_a[] = {{".2", u3we_rub}, {}};
+static c3_c* _140_two_rub_ha[] = {
+ "87fcf40fb6fce8c3cb778373670d0682785ae650f785531db8ff69d431bc14c6",
+ 0
+};
+
+static u3j_core _140_two_d[] =
+{ { "tri", 3, 0, _140_tri_d, _140_tri_ha, _140_tri_ho },
+
+ { "find", 7, _140_two_find_a, 0, _140_two_find_ha },
+ { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha },
+ { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha },
+ { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha },
+ { "lien", 7, _140_two_lien_a, 0, _140_two_lien_ha },
+ { "murn", 7, _140_two_murn_a, 0, _140_two_murn_ha },
+ { "need", 7, _140_two_need_a, 0, _140_two_need_ha },
+ { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha },
+ { "reel", 7, _140_two_reel_a, 0, _140_two_reel_ha },
+ { "roll", 7, _140_two_roll_a, 0, _140_two_roll_ha },
+ { "skid", 7, _140_two_skid_a, 0, _140_two_skid_ha },
+ { "skim", 7, _140_two_skim_a, 0, _140_two_skim_ha },
+ { "skip", 7, _140_two_skip_a, 0, _140_two_skip_ha },
+ { "scag", 7, _140_two_scag_a, 0, _140_two_scag_ha },
+ { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha },
+ { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha },
+ { "sort", 7, _140_two_sort_a, 0, _140_two_sort_ha },
+ { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha },
+ { "weld", 7, _140_two_weld_a, 0, _140_two_weld_ha },
+ { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha },
+ { "zing", 7, _140_two_zing_a, 0, _140_two_zing_ha },
+
+ { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha },
+ { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha },
+ { "can", 7, _140_two_can_a, 0, _140_two_can_ha },
+ { "con", 7, _140_two_con_a, 0, _140_two_con_ha },
+ { "cue", 7, _140_two_cue_a, 0, _140_two_cue_ha },
+ { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha },
+ { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha },
+ { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha },
+ { "end", 7, _140_two_end_a, 0, _140_two_end_ha },
+ { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha },
+ { "jam", 7, _140_two_jam_a, 0, _140_two_jam_ha },
+ { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha },
+ { "mat", 7, _140_two_mat_a, 0, _140_two_mat_ha },
+ { "met", 7, _140_two_met_a, 0, _140_two_met_ha },
+ { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha },
+ { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha },
+ { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha },
+ { "muk", 59, _140_two_muk_a, 0, _140_two_muk_ha },
+ { "rap", 7, _140_two_rap_a, 0, _140_two_rap_ha },
+ { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha },
+ { "rev", 7, _140_two_rev_a, 0, _140_two_rev_ha },
+ { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha },
+ { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha },
+ { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha },
+ { "rub", 7, _140_two_rub_a, 0, _140_two_rub_ha },
+ { "pow", 7, _140_two_pow_a, 0, _140_two_pow_ha },
+ { "sqt", 7, _140_two_sqt_a, 0, _140_two_sqt_ha },
+ { "xeb", 7, _140_two_xeb_a, 0, _140_two_xeb_ha },
+
+ { "by", 7, 0, _140_two__by_d, _140_two__by_ha },
+ { "in", 7, 0, _140_two__in_d, _140_two__in_ha },
+ {}
+};
+static c3_c* _140_two_ha[] = {
+ "f693e1f5ff57ec741fe28a48a18252b3e12dead2bfe3bcd4ea8e904a36905c0b",
+ 0
+};
+
+
+/* layer one
+*/
+static u3j_harm _140_one_add_a[] = {{".2", u3wa_add, c3y}, {}};
+static c3_c* _140_one_add_ha[] = {
+ "46407e27fe5d7c20b3ba25c02657c227b37217ddab8501b2d3b70b818aca7a44",
+ 0
+};
+static u3j_harm _140_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}};
+static c3_c* _140_one_dec_ha[] = {
+ "6345d28d34c62c4b4f9da98828574bc9060ff0869789968d9045d90faeb3580c",
+ 0
+};
+static u3j_harm _140_one_div_a[] = {{".2", u3wa_div, c3y}, {}};
+static c3_c* _140_one_div_ha[] = {
+ "e3292e76feb274b9314e7693827de11e96677629c556b3a6c72cc15ebad45113",
+ 0
+};
+static u3j_harm _140_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}};
+static c3_c* _140_one_dvr_ha[] = {
+ "fc259f46d770f82767163544f3662dfd45b1484a7bcffad396c7420651f092a4",
+ 0
+};
+static u3j_harm _140_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}};
+static c3_c* _140_one_gte_ha[] = {
+ "f3ff2c0fc1f386226183e8834cff87420a1206583f8710e1e75f0e34ed8df5fe",
+ 0
+};
+static u3j_harm _140_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}};
+static c3_c* _140_one_gth_ha[] = {
+ "62692d64c8166c7d48bb2a00713064846da9629a1dd2d924c3b15cfd18a5912a",
+ 0
+};
+static u3j_harm _140_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}};
+static c3_c* _140_one_lte_ha[] = {
+ "6ca61752aa27b453f28f20e12f652610d45695c3bd965190d5b4fa8b9daa518c",
+ 0
+};
+static u3j_harm _140_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}};
+static c3_c* _140_one_lth_ha[] = {
+ "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e",
+ 0
+};
+static u3j_harm _140_one_max_a[] = {{".2", u3wa_max, c3y}, {}};
+static c3_c* _140_one_max_ha[] = {
+ "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e",
+ 0
+};
+static u3j_harm _140_one_min_a[] = {{".2", u3wa_min, c3y}, {}};
+static c3_c* _140_one_min_ha[] = {
+ "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e",
+ 0
+};
+static u3j_harm _140_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}};
+static c3_c* _140_one_mod_ha[] = {
+ "374d2f3cd0ece33f680bd7103b99891d7dae03590f9eb9faac03a4a501f17038",
+ 0
+};
+static u3j_harm _140_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}};
+static c3_c* _140_one_mul_ha[] = {
+ "51e45dbea29cf65a5c26ead095a20eb12ba078840652c88b9c1997820e670bc6",
+ 0
+};
+static u3j_harm _140_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}};
+static c3_c* _140_one_sub_ha[] = {
+ "016695719ffe93c177e8a03afa5d29fc428ff596bb8962ace50f7706cd6e53a6",
+ 0
+};
+
+static u3j_harm _140_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}};
+static c3_c* _140_one_cap_ha[] = {
+ "407e764ee978c712b81c9c3452932e0f7d33faeda36dfe99aaf81d543db16254",
+ 0
+};
+static u3j_harm _140_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}};
+static c3_c* _140_one_peg_ha[] = {
+ "8b608d2d2e2eccec3e2fc8cd2d92fd69504c72b26581bb9cbfa4ff51f997251f",
+ 0
+};
+static u3j_harm _140_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}};
+static c3_c* _140_one_mas_ha[] = {
+ "1439dcd809f0819b09fb5fe7e83bc1292ca6fd33b5819d78e706d402c053b02a",
+ 0
+};
+
+static u3j_core _140_one_d[] =
+{ { "two", 3, 0, _140_two_d, _140_two_ha },
+
+ { "add", 7, _140_one_add_a, 0, _140_one_add_ha },
+ { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha },
+ { "div", 7, _140_one_div_a, 0, _140_one_div_ha },
+ { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha },
+ { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha },
+ { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha },
+ { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha },
+ { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha },
+ { "max", 7, _140_one_max_a, 0, _140_one_max_ha },
+ { "min", 7, _140_one_min_a, 0, _140_one_min_ha },
+ { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha },
+ { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha },
+ { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha },
+
+ { "cap", 7, _140_one_cap_a, 0, _140_one_cap_ha },
+ { "mas", 7, _140_one_mas_a, 0, _140_one_mas_ha },
+ { "peg", 7, _140_one_peg_a, 0, _140_one_peg_ha },
+ {}
+};
+static c3_c* _140_one_ha[] = {
+ "2501f8dbe62384d144ab0f805501ed66325bd77a733eca0c80d1da673e4b16fb",
+ 0
+};
+
+u3j_core _k140_d[] =
+{ { "one", 3, 0, _140_one_d, _140_one_ha },
+ {}
+};
+static c3_c* _k140_ha[] = {
+ "9b82a903093c077afb3f0b9d4e95e1a9c9789d1ca605b57bbacf79857e3d5c52",
+ 0
+};
+
+/* new jets
+*/
+ static u3j_harm _139_hex_json_de_a[] = {{".2", u3we_json_de}, {}};
+ static u3j_harm _139_hex_json_en_a[] = {{".2", u3we_json_en}, {}};
+static u3j_core _139_hex_json_d[] =
+ { { "de", 15, _139_hex_json_de_a, 0, no_hashes },
+ { "en", 15, _139_hex_json_en_a, 0, no_hashes },
+ {}
+ };
+
+
+
+static u3j_core _139_hex_d[] =
+{
+ { "lore", 63, _140_hex_lore_a, 0, no_hashes },
+ { "leer", 63, _140_hex_leer_a, 0, no_hashes },
+ { "loss", 63, _140_hex_loss_a, 0, no_hashes },
+ { "lune", 127, _140_hex_lune_a, 0, no_hashes },
+
+ { "coed", 63, 0, _140_hex_coed_d, no_hashes },
+ { "aes", 31, 0, _140_hex_aes_d, no_hashes },
+
+ { "hmac", 63, 0, _140_hex_hmac_d, no_hashes },
+ { "argon", 31, 0, _140_hex_argon_d, no_hashes },
+ { "blake", 31, 0, _140_hex_blake_d, no_hashes },
+ { "kecc", 31, 0, _140_hex_kecc_d, no_hashes },
+ { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes },
+ { "scr", 31, 0, _140_hex_scr_d, no_hashes },
+ { "secp", 6, 0, _140_hex_secp_d, no_hashes },
+ { "mimes", 31, 0, _140_hex_mimes_d, no_hashes },
+ { "json", 31, 0, _139_hex_json_d, no_hashes },
+ {}
+};
+
+static u3j_core _139_pen_d[] =
+{ { "hex", 7, 0, _139_hex_d, no_hashes },
+
+ { "cell", 7, _140_pen_cell_a, 0, no_hashes },
+ { "comb", 7, _140_pen_comb_a, 0, no_hashes },
+ { "cons", 7, _140_pen_cons_a, 0, no_hashes },
+ { "core", 7, _140_pen_core_a, 0, no_hashes },
+ { "face", 7, _140_pen_face_a, 0, no_hashes },
+ { "fitz", 7, _140_pen_fitz_a, 0, no_hashes },
+ { "flan", 7, _140_pen_flan_a, 0, no_hashes },
+ { "flip", 7, _140_pen_flip_a, 0, no_hashes },
+ { "flor", 7, _140_pen_flor_a, 0, no_hashes },
+ { "fork", 7, _140_pen_fork_a, 0, no_hashes },
+ { "look", 7, _140_pen_look_a, 0, no_hashes },
+ { "loot", 7, _140_pen_loot_a, 0, no_hashes },
+ { "ut", 15, 0, _140_pen__ut_d, no_hashes, _140_pen__ut_ho },
+ {}
+};
+
+static u3j_core _139_qua_d[] =
+{ { "pen", 3, 0, _139_pen_d, no_hashes, _140_pen_ho },
+
+ { "po", 7, 0, _140_qua__po_d, no_hashes },
+
+ { "trip", 7, _140_qua_trip_a, 0, no_hashes },
+
+ { "bend", 7, 0, _140_qua__bend_d, no_hashes },
+ { "cold", 7, 0, _140_qua__cold_d, no_hashes },
+ { "comp", 7, 0, _140_qua__comp_d, no_hashes },
+ { "cook", 7, 0, _140_qua__cook_d, no_hashes },
+ { "easy", 7, 0, _140_qua__easy_d, no_hashes },
+ { "glue", 7, 0, _140_qua__glue_d, no_hashes },
+ { "here", 7, 0, _140_qua__here_d, no_hashes },
+ { "just", 7, 0, _140_qua__just_d, no_hashes },
+ { "mask", 7, 0, _140_qua__mask_d, no_hashes },
+ { "shim", 7, 0, _140_qua__shim_d, no_hashes },
+ { "stag", 7, 0, _140_qua__stag_d, no_hashes },
+ { "stew", 7, 0, _140_qua__stew_d, no_hashes },
+ { "stir", 7, 0, _140_qua__stir_d, no_hashes },
+
+ { "pfix", 7, _140_qua_pfix_a, 0, no_hashes },
+ { "plug", 7, _140_qua_plug_a, 0, no_hashes },
+ { "pose", 7, _140_qua_pose_a, 0, no_hashes },
+ { "sfix", 7, _140_qua_sfix_a, 0, no_hashes },
+
+ { "mink", 7, _140_qua_mink_a, 0, no_hashes },
+ { "mole", 7, _140_qua_mole_a, 0, no_hashes },
+ { "mule", 7, _140_qua_mule_a, 0, no_hashes },
+
+ { "scot", 7, _140_qua_scot_a, 0, no_hashes },
+ { "scow", 7, _140_qua_scow_a, 0, no_hashes },
+ { "slaw", 7, _140_qua_slaw_a, 0, no_hashes },
+ {}
+};
+
+static u3j_core _139_tri_d[] =
+{ { "qua", 3, 0, _139_qua_d, no_hashes, _140_qua_ho },
+
+ { "cofl", 7, 0, _140_tri__cofl_d, no_hashes },
+ { "rd", 7, 0, _140_tri__rd_d, no_hashes },
+ { "rs", 7, 0, _140_tri__rs_d, no_hashes },
+ { "rq", 7, 0, _140_tri__rq_d, no_hashes },
+ { "rh", 7, 0, _140_tri__rh_d, no_hashes },
+ { "og", 7, 0, _140_tri__og_d, no_hashes },
+
+ { "sha", 7, 0, _140_tri__sha_d, no_hashes },
+ { "shax", 7, _140_tri_shax_a, 0, no_hashes },
+ { "shay", 7, _140_tri_shay_a, 0, no_hashes },
+ { "shas", 7, _140_tri_shas_a, 0, no_hashes },
+ { "shal", 7, _140_tri_shal_a, 0, no_hashes },
+
+ { "ob", 3, 0, _140_ob_d, no_hashes, _140_ob_ho },
+ {}
+};
+
+static u3j_harm _139_two__in_apt_a[] = {{".2", u3wdi_apt}, {}};
+
+static u3j_core _139_two__in_d[] =
+ { { "apt", 7, _139_two__in_apt_a, 0, no_hashes },
+ { "bif", 7, _140_two__in_bif_a, 0, no_hashes },
+ { "del", 7, _140_two__in_del_a, 0, no_hashes },
+ { "dif", 7, _140_two__in_dif_a, 0, no_hashes },
+ { "gas", 7, _140_two__in_gas_a, 0, no_hashes },
+ { "has", 7, _140_two__in_has_a, 0, no_hashes },
+ { "int", 7, _140_two__in_int_a, 0, no_hashes },
+ { "put", 7, _140_two__in_put_a, 0, no_hashes },
+ { "rep", 7, _140_two__in_rep_a, 0, no_hashes },
+ { "run", 7, _140_two__in_run_a, 0, no_hashes },
+ { "tap", 7, _140_two__in_tap_a, 0, no_hashes },
+ { "uni", 7, _140_two__in_uni_a, 0, no_hashes },
+ { "wyt", 3, _140_two__in_wyt_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _139_two_d[] =
+{ { "tri", 3, 0, _139_tri_d, no_hashes, _140_tri_ho },
+
+ { "find", 7, _140_two_find_a, 0, no_hashes },
+ { "flop", 7, _140_two_flop_a, 0, no_hashes },
+ { "lent", 7, _140_two_lent_a, 0, no_hashes },
+ { "levy", 7, _140_two_levy_a, 0, no_hashes },
+ { "lien", 7, _140_two_lien_a, 0, no_hashes },
+ { "murn", 7, _140_two_murn_a, 0, no_hashes },
+ { "need", 7, _140_two_need_a, 0, no_hashes },
+ { "reap", 7, _140_two_reap_a, 0, no_hashes },
+ { "reel", 7, _140_two_reel_a, 0, no_hashes },
+ { "roll", 7, _140_two_roll_a, 0, no_hashes },
+ { "skid", 7, _140_two_skid_a, 0, no_hashes },
+ { "skim", 7, _140_two_skim_a, 0, no_hashes },
+ { "skip", 7, _140_two_skip_a, 0, no_hashes },
+ { "scag", 7, _140_two_scag_a, 0, no_hashes },
+ { "slag", 7, _140_two_slag_a, 0, no_hashes },
+ { "snag", 7, _140_two_snag_a, 0, no_hashes },
+ { "sort", 7, _140_two_sort_a, 0, no_hashes },
+ { "turn", 7, _140_two_turn_a, 0, no_hashes },
+ { "weld", 7, _140_two_weld_a, 0, no_hashes },
+ { "welp", 7, _140_two_welp_a, 0, no_hashes },
+ { "zing", 7, _140_two_zing_a, 0, no_hashes },
+
+ { "bex", 7, _140_two_bex_a, 0, no_hashes },
+ { "cat", 7, _140_two_cat_a, 0, no_hashes },
+ { "can", 7, _140_two_can_a, 0, no_hashes },
+ { "con", 7, _140_two_con_a, 0, no_hashes },
+ { "cue", 7, _140_two_cue_a, 0, no_hashes },
+ { "cut", 7, _140_two_cut_a, 0, no_hashes },
+ { "dis", 7, _140_two_dis_a, 0, no_hashes },
+ { "dor", 7, _140_two_dor_a, 0, no_hashes },
+ { "end", 7, _140_two_end_a, 0, no_hashes },
+ { "gor", 7, _140_two_gor_a, 0, no_hashes },
+ { "jam", 7, _140_two_jam_a, 0, no_hashes },
+ { "lsh", 7, _140_two_lsh_a, 0, no_hashes },
+ { "mat", 7, _140_two_mat_a, 0, no_hashes },
+ { "met", 7, _140_two_met_a, 0, no_hashes },
+ { "mix", 7, _140_two_mix_a, 0, no_hashes },
+ { "mor", 7, _140_two_mor_a, 0, no_hashes },
+ { "mug", 7, _140_two_mug_a, 0, no_hashes },
+ { "muk", 59, _140_two_muk_a, 0, no_hashes },
+ { "rap", 7, _140_two_rap_a, 0, no_hashes },
+ { "rep", 7, _140_two_rep_a, 0, no_hashes },
+ { "rev", 7, _140_two_rev_a, 0, no_hashes },
+ { "rip", 7, _140_two_rip_a, 0, no_hashes },
+ { "rsh", 7, _140_two_rsh_a, 0, no_hashes },
+ { "swp", 7, _140_two_swp_a, 0, no_hashes },
+ { "rub", 7, _140_two_rub_a, 0, no_hashes },
+ { "pow", 7, _140_two_pow_a, 0, no_hashes },
+ { "sqt", 7, _140_two_sqt_a, 0, no_hashes },
+ { "xeb", 7, _140_two_xeb_a, 0, no_hashes },
+
+ { "by", 7, 0, _140_two__by_d, no_hashes },
+ { "in", 7, 0, _139_two__in_d, no_hashes },
+ {}
+};
+
+static u3j_core _139_one_d[] =
+{ { "two", 3, 0, _139_two_d, no_hashes },
+
+ { "add", 7, _140_one_add_a, 0, no_hashes },
+ { "dec", 7, _140_one_dec_a, 0, no_hashes },
+ { "div", 7, _140_one_div_a, 0, no_hashes },
+ { "dvr", 7, _140_one_dvr_a, 0, no_hashes },
+ { "gte", 7, _140_one_gte_a, 0, no_hashes },
+ { "gth", 7, _140_one_gth_a, 0, no_hashes },
+ { "lte", 7, _140_one_lte_a, 0, no_hashes },
+ { "lth", 7, _140_one_lth_a, 0, no_hashes },
+ { "max", 7, _140_one_max_a, 0, no_hashes },
+ { "min", 7, _140_one_min_a, 0, no_hashes },
+ { "mod", 7, _140_one_mod_a, 0, no_hashes },
+ { "mul", 7, _140_one_mul_a, 0, no_hashes },
+ { "sub", 7, _140_one_sub_a, 0, no_hashes },
+
+ { "cap", 7, _140_one_cap_a, 0, no_hashes },
+ { "mas", 7, _140_one_mas_a, 0, no_hashes },
+ { "peg", 7, _140_one_peg_a, 0, no_hashes },
+ {}
+};
+
+u3j_core _k139_d[] =
+{ { "one", 3, 0, _139_one_d, no_hashes },
+ {}
+};
+
+ static u3j_harm _138_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}};
+ static u3j_harm _138_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}};
+ static u3j_harm _138_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}};
+ static u3j_core _138_hex_blake3_d[] =
+ { { "hash", 7, _138_hex_blake3_hash_a, 0, no_hashes },
+ { "chunk-output", 7, _138_hex_blake3_chunk_output_a, 0, no_hashes },
+ {}
+ };
+ static u3j_core _138_hex_blake3_impl_d[] =
+ { { "compress", 7, _138_hex_blake3_compress_a, 0, no_hashes },
+ { "blake3", 7, 0, _138_hex_blake3_d, no_hashes },
+ {}
+ };
+static u3j_core _138_hex_blake_d[] =
+ { { "blake2b", 7, _140_hex_blake2b_a, 0, no_hashes },
+ { "blake3-impl", 7, 0, _138_hex_blake3_impl_d, no_hashes },
+ {}
+ };
+
+ static u3j_harm _138_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}};
+ static u3j_harm _138_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}};
+static u3j_core _138_hex_chacha_d[] =
+ { { "crypt", 7, _138_hex_chacha_crypt_a, 0, no_hashes },
+ { "xchacha", 7, _138_hex_chacha_xchacha_a, 0, no_hashes },
+ {}
+ };
+
+static u3j_core _138_hex_d[] =
+{ { "lore", 63, _140_hex_lore_a, 0, no_hashes },
+ { "leer", 63, _140_hex_leer_a, 0, no_hashes },
+ { "loss", 63, _140_hex_loss_a, 0, no_hashes },
+ { "lune", 127, _140_hex_lune_a, 0, no_hashes },
+
+ { "coed", 63, 0, _140_hex_coed_d, no_hashes },
+ { "aes", 31, 0, _140_hex_aes_d, no_hashes },
+
+ { "hmac", 63, 0, _140_hex_hmac_d, no_hashes },
+ { "argon", 31, 0, _140_hex_argon_d, no_hashes },
+ { "blake", 31, 0, _138_hex_blake_d, no_hashes },
+ { "chacha", 31, 0, _138_hex_chacha_d, no_hashes },
+ { "kecc", 31, 0, _140_hex_kecc_d, no_hashes },
+ { "ripemd", 31, 0, _140_hex_ripe_d, no_hashes },
+ { "scr", 31, 0, _140_hex_scr_d, no_hashes },
+ { "secp", 6, 0, _140_hex_secp_d, no_hashes },
+ { "mimes", 31, 0, _140_hex_mimes_d, no_hashes },
+ { "json", 31, 0, _139_hex_json_d, no_hashes },
+ {}
+};
+
+static u3j_core _138_pen_d[] =
+{ { "hex", 7, 0, _138_hex_d, no_hashes },
+
+ { "cell", 7, _140_pen_cell_a, 0, no_hashes },
+ { "comb", 7, _140_pen_comb_a, 0, no_hashes },
+ { "cons", 7, _140_pen_cons_a, 0, no_hashes },
+ { "core", 7, _140_pen_core_a, 0, no_hashes },
+ { "face", 7, _140_pen_face_a, 0, no_hashes },
+ { "fitz", 7, _140_pen_fitz_a, 0, no_hashes },
+ // flan, flip, and flor removed
+ //
+ { "fork", 7, _140_pen_fork_a, 0, no_hashes },
+ { "look", 7, _140_pen_look_a, 0, no_hashes },
+ { "loot", 7, _140_pen_loot_a, 0, no_hashes },
+ { "ut", 15, 0, _140_pen__ut_d, no_hashes, _140_pen__ut_ho },
+ {}
+};
+
+static u3j_core _138_qua_d[] =
+{ { "pen", 3, 0, _138_pen_d, no_hashes, _140_pen_ho },
+
+ { "po", 7, 0, _140_qua__po_d, no_hashes },
+
+ { "trip", 7, _140_qua_trip_a, 0, no_hashes },
+
+ { "bend", 7, 0, _140_qua__bend_d, no_hashes },
+ { "cold", 7, 0, _140_qua__cold_d, no_hashes },
+ { "comp", 7, 0, _140_qua__comp_d, no_hashes },
+ { "cook", 7, 0, _140_qua__cook_d, no_hashes },
+ { "easy", 7, 0, _140_qua__easy_d, no_hashes },
+ { "glue", 7, 0, _140_qua__glue_d, no_hashes },
+ { "here", 7, 0, _140_qua__here_d, no_hashes },
+ { "just", 7, 0, _140_qua__just_d, no_hashes },
+ { "mask", 7, 0, _140_qua__mask_d, no_hashes },
+ { "shim", 7, 0, _140_qua__shim_d, no_hashes },
+ { "stag", 7, 0, _140_qua__stag_d, no_hashes },
+ { "stew", 7, 0, _140_qua__stew_d, no_hashes },
+ { "stir", 7, 0, _140_qua__stir_d, no_hashes },
+
+ { "pfix", 7, _140_qua_pfix_a, 0, no_hashes },
+ { "plug", 7, _140_qua_plug_a, 0, no_hashes },
+ { "pose", 7, _140_qua_pose_a, 0, no_hashes },
+ { "sfix", 7, _140_qua_sfix_a, 0, no_hashes },
+
+ { "mink", 7, _140_qua_mink_a, 0, no_hashes },
+ { "mole", 7, _140_qua_mole_a, 0, no_hashes },
+ { "mule", 7, _140_qua_mule_a, 0, no_hashes },
+
+ { "scot", 7, _140_qua_scot_a, 0, no_hashes },
+ { "scow", 7, _140_qua_scow_a, 0, no_hashes },
+ { "slaw", 7, _140_qua_slaw_a, 0, no_hashes },
+ {}
+};
+
+static u3j_core _138_tri_d[] =
+{ { "qua", 3, 0, _138_qua_d, no_hashes, _140_qua_ho },
+
+ { "cofl", 7, 0, _140_tri__cofl_d, no_hashes },
+ { "rd", 7, 0, _140_tri__rd_d, no_hashes },
+ { "rs", 7, 0, _140_tri__rs_d, no_hashes },
+ { "rq", 7, 0, _140_tri__rq_d, no_hashes },
+ { "rh", 7, 0, _140_tri__rh_d, no_hashes },
+ { "og", 7, 0, _140_tri__og_d, no_hashes },
+
+ { "sha", 7, 0, _140_tri__sha_d, no_hashes },
+ { "shax", 7, _140_tri_shax_a, 0, no_hashes },
+ { "shay", 7, _140_tri_shay_a, 0, no_hashes },
+ { "shas", 7, _140_tri_shas_a, 0, no_hashes },
+ { "shal", 7, _140_tri_shal_a, 0, no_hashes },
+
+ { "ob", 3, 0, _140_ob_d, no_hashes, _140_ob_ho },
+ {}
+};
+
+static u3j_harm _138_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}};
+
+static u3j_core _138_two__by_d[] =
+ { { "all", 7, _140_two__by_all_a, 0, _140_two__by_all_ha },
+ { "any", 7, _140_two__by_any_a, 0, _140_two__by_any_ha },
+ { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha },
+ { "bif", 7, _138_two__by_bif_a, 0, no_hashes },
+ { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha },
+ { "dif", 7, _140_two__by_dif_a, 0, _140_two__by_dif_ha },
+ { "gas", 7, _140_two__by_gas_a, 0, _140_two__by_gas_ha },
+ { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha },
+ { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha },
+ { "int", 7, _140_two__by_int_a, 0, _140_two__by_int_ha },
+ { "jab", 7, _140_two__by_jab_a, 0, _140_two__by_jab_ha },
+ { "key", 7, _140_two__by_key_a, 0, _140_two__by_key_ha },
+ { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha },
+ { "rep", 7, _140_two__by_rep_a, 0, _140_two__by_rep_ha },
+ { "run", 7, _140_two__by_run_a, 0, _140_two__by_run_ha },
+ { "tap", 7, _140_two__by_tap_a, 0, _140_two__by_tap_ha },
+ { "uni", 7, _140_two__by_uni_a, 0, _140_two__by_uni_ha },
+ { "urn", 7, _140_two__by_urn_a, 0, _140_two__by_urn_ha },
+ { "wyt", 3, _140_two__by_wyt_a, 0, _140_two__by_wyt_ha },
+ {}
+ };
+
+static u3j_harm _138_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}};
+
+static u3j_harm _138_two_aor_a[] = {{".2", u3wc_aor, c3y}, {}};
+
+static u3j_core _138_two_d[] =
+{ { "tri", 3, 0, _138_tri_d, no_hashes, _140_tri_ho },
+
+ { "find", 7, _140_two_find_a, 0, no_hashes },
+ { "flop", 7, _140_two_flop_a, 0, no_hashes },
+ { "lent", 7, _140_two_lent_a, 0, no_hashes },
+ { "levy", 7, _140_two_levy_a, 0, no_hashes },
+ { "lien", 7, _140_two_lien_a, 0, no_hashes },
+ { "murn", 7, _140_two_murn_a, 0, no_hashes },
+ { "need", 7, _140_two_need_a, 0, no_hashes },
+ { "mate", 7, _138_two_mate_a, 0, no_hashes },
+ { "reap", 7, _140_two_reap_a, 0, no_hashes },
+ { "reel", 7, _140_two_reel_a, 0, no_hashes },
+ { "roll", 7, _140_two_roll_a, 0, no_hashes },
+ { "skid", 7, _140_two_skid_a, 0, no_hashes },
+ { "skim", 7, _140_two_skim_a, 0, no_hashes },
+ { "skip", 7, _140_two_skip_a, 0, no_hashes },
+ { "scag", 7, _140_two_scag_a, 0, no_hashes },
+ { "slag", 7, _140_two_slag_a, 0, no_hashes },
+ { "snag", 7, _140_two_snag_a, 0, no_hashes },
+ { "sort", 7, _140_two_sort_a, 0, no_hashes },
+ { "turn", 7, _140_two_turn_a, 0, no_hashes },
+ { "weld", 7, _140_two_weld_a, 0, no_hashes },
+ { "welp", 7, _140_two_welp_a, 0, no_hashes },
+ { "zing", 7, _140_two_zing_a, 0, no_hashes },
+
+ { "aor", 7, _138_two_aor_a, 0, no_hashes },
+ { "bex", 7, _140_two_bex_a, 0, no_hashes },
+ { "cat", 7, _140_two_cat_a, 0, no_hashes },
+ { "can", 7, _140_two_can_a, 0, no_hashes },
+ { "con", 7, _140_two_con_a, 0, no_hashes },
+ { "cue", 7, _140_two_cue_a, 0, no_hashes },
+ { "cut", 7, _140_two_cut_a, 0, no_hashes },
+ { "dis", 7, _140_two_dis_a, 0, no_hashes },
+ { "dor", 7, _140_two_dor_a, 0, no_hashes },
+ { "end", 7, _140_two_end_a, 0, no_hashes },
+ { "gor", 7, _140_two_gor_a, 0, no_hashes },
+ { "jam", 7, _140_two_jam_a, 0, no_hashes },
+ { "lsh", 7, _140_two_lsh_a, 0, no_hashes },
+ { "mat", 7, _140_two_mat_a, 0, no_hashes },
+ { "met", 7, _140_two_met_a, 0, no_hashes },
+ { "mix", 7, _140_two_mix_a, 0, no_hashes },
+ { "mor", 7, _140_two_mor_a, 0, no_hashes },
+ { "mug", 7, _140_two_mug_a, 0, no_hashes },
+ { "muk", 59, _140_two_muk_a, 0, no_hashes },
+ { "rap", 7, _140_two_rap_a, 0, no_hashes },
+ { "rep", 7, _140_two_rep_a, 0, no_hashes },
+ { "rev", 7, _140_two_rev_a, 0, no_hashes },
+ { "rip", 7, _140_two_rip_a, 0, no_hashes },
+ { "rsh", 7, _140_two_rsh_a, 0, no_hashes },
+ { "swp", 7, _140_two_swp_a, 0, no_hashes },
+ { "rub", 7, _140_two_rub_a, 0, no_hashes },
+ { "pow", 7, _140_two_pow_a, 0, no_hashes },
+ { "sqt", 7, _140_two_sqt_a, 0, no_hashes },
+ { "xeb", 7, _140_two_xeb_a, 0, no_hashes },
+
+ { "by", 7, 0, _138_two__by_d, no_hashes },
+ { "in", 7, 0, _139_two__in_d, no_hashes },
+ {}
+};
+
+static u3j_core _138_one_d[] =
+{ { "two", 3, 0, _138_two_d, no_hashes },
+
+ { "add", 7, _140_one_add_a, 0, no_hashes },
+ { "dec", 7, _140_one_dec_a, 0, no_hashes },
+ { "div", 7, _140_one_div_a, 0, no_hashes },
+ { "dvr", 7, _140_one_dvr_a, 0, no_hashes },
+ { "gte", 7, _140_one_gte_a, 0, no_hashes },
+ { "gth", 7, _140_one_gth_a, 0, no_hashes },
+ { "lte", 7, _140_one_lte_a, 0, no_hashes },
+ { "lth", 7, _140_one_lth_a, 0, no_hashes },
+ { "max", 7, _140_one_max_a, 0, no_hashes },
+ { "min", 7, _140_one_min_a, 0, no_hashes },
+ { "mod", 7, _140_one_mod_a, 0, no_hashes },
+ { "mul", 7, _140_one_mul_a, 0, no_hashes },
+ { "sub", 7, _140_one_sub_a, 0, no_hashes },
+
+ { "cap", 7, _140_one_cap_a, 0, no_hashes },
+ { "mas", 7, _140_one_mas_a, 0, no_hashes },
+ { "peg", 7, _140_one_peg_a, 0, no_hashes },
+ {}
+};
+
+static u3j_core _k138_d[] =
+{ { "one", 3, 0, _138_one_d, no_hashes },
+ {}
+};
+
+
+static u3j_core _a50_two__by_d[] =
+ { { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha },
+ { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha },
+ { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha },
+ { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha },
+ { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha },
+ {}
+ };
+
+static u3j_core _a50_two__in_d[] =
+ { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha }, // NB: 140 jet
+ { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha },
+ { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha },
+ {}
+ };
+
+u3j_core _a50_d[] =
+{ { "add", 7, _140_one_add_a, 0, _140_one_add_ha },
+ { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha },
+ { "div", 7, _140_one_div_a, 0, _140_one_div_ha },
+ { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha },
+ { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha },
+ { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha },
+ { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha },
+ { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha },
+ { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha },
+ { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha },
+ { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha },
+
+ { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha },
+ { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha },
+ { "can", 7, _140_two_can_a, 0, _140_two_can_ha },
+ { "con", 7, _140_two_con_a, 0, _140_two_con_ha },
+ { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha },
+ { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha },
+ { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha },
+ { "end", 7, _140_two_end_a, 0, _140_two_end_ha },
+ { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha },
+ { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha },
+ { "met", 7, _140_two_met_a, 0, _140_two_met_ha },
+ { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha },
+ { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha },
+ { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha },
+ { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha },
+ { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha },
+ { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha },
+ { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha },
+
+ { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha },
+ { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha },
+ { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha },
+ { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha },
+ { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha },
+ { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha },
+ { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha },
+ { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha },
+
+ { "by", 7, 0, _a50_two__by_d, _140_two__by_ha },
+ { "in", 7, 0, _a50_two__in_d, _140_two__in_ha },
+ {}
+};
+
+extern u3j_core _k137_d[];
+extern u3j_core _k136_d[];
+
+static u3j_core _d[] =
+{ { "k140", 0, 0, _k140_d, _k140_ha, 0, (u3j_core*) 140, 0 },
+ { "k139", 0, 0, _k139_d, no_hashes, 0, (u3j_core*) 139, 0 },
+ { "k138", 0, 0, _k138_d, no_hashes, 0, (u3j_core*) 138, 0 },
+ { "k137", 0, 0, _k137_d, no_hashes, 0, (u3j_core*) 137, 0 },
+ { "k136", 0, 0, _k136_d, no_hashes, 0, (u3j_core*) 136, 0 },
+ { "a50", 0, 0, _a50_d, _k140_ha, 0, (u3j_core*) c3__a50, 0 },
+ {}
+};
+
+u3j_dash
+u3j_Dash = {
+ _d,
+ 0,
+ 0
+};
+
diff --git a/vere/pkg/noun/jets/w.h b/vere/pkg/noun/jets/w.h
new file mode 100644
index 0000000..57d9677
--- /dev/null
+++ b/vere/pkg/noun/jets/w.h
@@ -0,0 +1,433 @@
+/// @file
+
+#ifndef U3_JETS_W_H
+#define U3_JETS_W_H
+
+#include "types.h"
+
+ /** Tier 1.
+ **/
+ u3_noun u3wa_add(u3_noun);
+ u3_noun u3wa_dec(u3_noun);
+ u3_noun u3wa_div(u3_noun);
+ u3_noun u3wa_gte(u3_noun);
+ u3_noun u3wa_gth(u3_noun);
+ u3_noun u3wa_lte(u3_noun);
+ u3_noun u3wa_lth(u3_noun);
+ u3_noun u3wa_max(u3_noun);
+ u3_noun u3wa_min(u3_noun);
+ u3_noun u3wa_mod(u3_noun);
+ u3_noun u3wa_mul(u3_noun);
+ u3_noun u3wa_sub(u3_noun);
+
+ /** Tier 2.
+ **/
+ u3_noun u3wb_bind(u3_noun);
+ u3_noun u3wb_clap(u3_noun);
+ u3_noun u3wb_drop(u3_noun);
+ u3_noun u3wb_find(u3_noun);
+ u3_noun u3wb_flop(u3_noun);
+ u3_noun u3wb_lent(u3_noun);
+ u3_noun u3wb_levy(u3_noun);
+ u3_noun u3wb_lien(u3_noun);
+ u3_noun u3wb_murn(u3_noun);
+ u3_noun u3wb_need(u3_noun);
+ u3_noun u3wb_mate(u3_noun);
+ u3_noun u3wb_reap(u3_noun);
+ u3_noun u3wb_reel(u3_noun);
+ u3_noun u3wb_roll(u3_noun);
+ u3_noun u3wb_skid(u3_noun);
+ u3_noun u3wb_skim(u3_noun);
+ u3_noun u3wb_skip(u3_noun);
+ u3_noun u3wb_scag(u3_noun);
+ u3_noun u3wb_slag(u3_noun);
+ u3_noun u3wb_snag(u3_noun);
+ u3_noun u3wb_sort(u3_noun);
+ u3_noun u3wb_turn(u3_noun);
+ u3_noun u3wb_weld(u3_noun);
+# define u3wb_welp u3wb_weld
+ u3_noun u3wb_zing(u3_noun);
+
+ /** Tier 3.
+ **/
+ u3_noun u3wc_aor(u3_noun);
+ u3_noun u3wc_bex(u3_noun);
+ u3_noun u3wc_xeb(u3_noun);
+ u3_noun u3wc_can(u3_noun);
+ u3_noun u3wc_cap(u3_noun);
+ u3_noun u3wc_cat(u3_noun);
+ u3_noun u3wc_clz(u3_noun);
+ u3_noun u3wc_con(u3_noun);
+ u3_noun u3wc_ctz(u3_noun);
+ u3_noun u3wc_cut(u3_noun);
+ u3_noun u3wc_dis(u3_noun);
+ u3_noun u3wc_dor(u3_noun);
+ u3_noun u3wc_dvr(u3_noun);
+ u3_noun u3wc_end(u3_noun);
+ u3_noun u3wc_gor(u3_noun);
+ u3_noun u3wc_ham(u3_noun);
+ u3_noun u3wc_hew(u3_noun);
+ u3_noun u3wc_lsh(u3_noun);
+ u3_noun u3wc_mas(u3_noun);
+ u3_noun u3wc_met(u3_noun);
+ u3_noun u3wc_mix(u3_noun);
+ u3_noun u3wc_mor(u3_noun);
+ u3_noun u3wc_mug(u3_noun);
+ u3_noun u3wc_muk(u3_noun);
+ u3_noun u3wc_peg(u3_noun);
+ u3_noun u3wc_pow(u3_noun);
+ u3_noun u3wc_rap(u3_noun);
+ u3_noun u3wc_rep(u3_noun);
+ u3_noun u3wc_rev(u3_noun);
+ u3_noun u3wc_rig(u3_noun);
+ u3_noun u3wc_rip(u3_noun);
+ u3_noun u3wc_rsh(u3_noun);
+ u3_noun u3wc_sew(u3_noun);
+ u3_noun u3wc_swp(u3_noun);
+ u3_noun u3wc_sqt(u3_noun);
+
+ u3_noun u3wcp_ins(u3_noun);
+ u3_noun u3wcp_ind(u3_noun);
+ u3_noun u3wcp_tos(u3_noun);
+ u3_noun u3wcp_tod(u3_noun);
+
+ /** Tier 4.
+ **/
+ u3_noun u3wdb_all(u3_noun);
+ u3_noun u3wdb_any(u3_noun);
+ u3_noun u3wdb_apt(u3_noun);
+ u3_noun u3wdb_bif(u3_noun);
+ u3_noun u3wdb_del(u3_noun);
+ u3_noun u3wdb_dif(u3_noun);
+ u3_noun u3wdb_gas(u3_noun);
+ u3_noun u3wdb_get(u3_noun);
+ u3_noun u3wdb_has(u3_noun);
+ u3_noun u3wdb_int(u3_noun);
+ u3_noun u3wdb_jab(u3_noun);
+ u3_noun u3wdb_key(u3_noun);
+ u3_noun u3wdb_put(u3_noun);
+# define u3wdb_tap u3wdi_tap
+ u3_noun u3wdb_uni(u3_noun);
+ u3_noun u3wdb_urn(u3_noun);
+# define u3wdb_rep u3wdi_rep
+ u3_noun u3wdb_run(u3_noun);
+# define u3wdb_wyt u3wdi_wyt
+
+ u3_noun u3wdi_apt_140(u3_noun);
+ u3_noun u3wdi_apt(u3_noun);
+ u3_noun u3wdi_bif(u3_noun);
+ u3_noun u3wdi_del(u3_noun);
+ u3_noun u3wdi_dif(u3_noun);
+ u3_noun u3wdi_gas(u3_noun);
+ u3_noun u3wdi_has(u3_noun);
+ u3_noun u3wdi_int(u3_noun);
+ u3_noun u3wdi_put(u3_noun);
+ u3_noun u3wdi_rep(u3_noun);
+ u3_noun u3wdi_run(u3_noun);
+ u3_noun u3wdi_tap(u3_noun);
+ u3_noun u3wdi_uni(u3_noun);
+ u3_noun u3wdi_wyt(u3_noun);
+
+ /** Tier 5.
+ **/
+ u3_noun u3we_cue(u3_noun);
+ u3_noun u3we_jam(u3_noun);
+ u3_noun u3we_mat(u3_noun);
+ u3_noun u3we_rub(u3_noun);
+ u3_noun u3we_leer(u3_noun);
+ u3_noun u3we_lore(u3_noun);
+ u3_noun u3we_loss(u3_noun);
+ u3_noun u3we_lune(u3_noun);
+ u3_noun u3we_mice(u3_noun);
+ u3_noun u3we_mink(u3_noun);
+ u3_noun u3we_mole(u3_noun);
+ u3_noun u3we_mule(u3_noun);
+ u3_noun u3we_repg(u3_noun);
+ u3_noun u3we_rexp(u3_noun);
+ u3_noun u3we_trip(u3_noun);
+
+ u3_noun u3we_scow(u3_noun);
+ u3_noun u3we_scot(u3_noun);
+ u3_noun u3we_slaw(u3_noun);
+
+ u3_noun u3we_pfix(u3_noun);
+ u3_noun u3we_plug(u3_noun);
+ u3_noun u3we_pose(u3_noun);
+ u3_noun u3we_sfix(u3_noun);
+
+ u3_noun u3wea_ecba_en(u3_noun);
+ u3_noun u3wea_ecba_de(u3_noun);
+ u3_noun u3wea_ecbb_en(u3_noun);
+ u3_noun u3wea_ecbb_de(u3_noun);
+ u3_noun u3wea_ecbc_en(u3_noun);
+ u3_noun u3wea_ecbc_de(u3_noun);
+
+ u3_noun u3wea_cbca_en(u3_noun);
+ u3_noun u3wea_cbca_de(u3_noun);
+ u3_noun u3wea_cbcb_en(u3_noun);
+ u3_noun u3wea_cbcb_de(u3_noun);
+ u3_noun u3wea_cbcc_en(u3_noun);
+ u3_noun u3wea_cbcc_de(u3_noun);
+
+ u3_noun u3wea_siva_en(u3_noun);
+ u3_noun u3wea_siva_de(u3_noun);
+ u3_noun u3wea_sivb_en(u3_noun);
+ u3_noun u3wea_sivb_de(u3_noun);
+ u3_noun u3wea_sivc_en(u3_noun);
+ u3_noun u3wea_sivc_de(u3_noun);
+
+ u3_noun u3wea_de(u3_noun);
+ u3_noun u3wea_en(u3_noun);
+
+ u3_noun u3wes_hsh(u3_noun);
+ u3_noun u3wes_hsl(u3_noun);
+ u3_noun u3wes_pbk(u3_noun);
+ u3_noun u3wes_pbl(u3_noun);
+
+ u3_noun u3we_shax(u3_noun);
+ u3_noun u3we_shay(u3_noun);
+ u3_noun u3we_shas(u3_noun);
+ u3_noun u3we_shal(u3_noun);
+ u3_noun u3we_sha1(u3_noun);
+
+ u3_noun u3we_fein_ob(u3_noun);
+ u3_noun u3we_fynd_ob(u3_noun);
+
+ u3_noun u3weo_raw(u3_noun);
+
+ u3_noun u3wee_scad(u3_noun);
+ u3_noun u3wee_scas(u3_noun);
+ u3_noun u3wee_scap(u3_noun);
+
+ u3_noun u3wee_puck(u3_noun);
+ u3_noun u3wee_luck(u3_noun);
+ u3_noun u3wee_sign(u3_noun);
+ u3_noun u3wee_sign_raw(u3_noun);
+ u3_noun u3wee_veri(u3_noun);
+ u3_noun u3wee_sign_octs(u3_noun);
+ u3_noun u3wee_sign_octs_raw(u3_noun);
+ u3_noun u3wee_veri_octs(u3_noun);
+ u3_noun u3wee_shar(u3_noun);
+ u3_noun u3wee_slar(u3_noun);
+ u3_noun u3wee_recs(u3_noun);
+ u3_noun u3wee_smac(u3_noun);
+ u3_noun u3wee_point_neg(u3_noun);
+ u3_noun u3wee_point_add(u3_noun);
+ u3_noun u3wee_scalarmult(u3_noun);
+ u3_noun u3wee_scalarmult_base(u3_noun);
+ u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun);
+ u3_noun u3wee_add_double_scalarmult(u3_noun);
+
+ u3_noun u3we_hmac(u3_noun);
+
+ u3_noun u3we_kecc224(u3_noun);
+ u3_noun u3we_kecc256(u3_noun);
+ u3_noun u3we_kecc384(u3_noun);
+ u3_noun u3we_kecc512(u3_noun);
+
+ u3_noun u3we_argon2(u3_noun);
+
+ u3_noun u3we_blake2b(u3_noun);
+ u3_noun u3we_blake3_hash(u3_noun);
+ u3_noun u3we_blake3_chunk_output(u3_noun);
+ u3_noun u3we_blake3_compress(u3_noun);
+
+ u3_noun u3we_chacha_crypt(u3_noun);
+ u3_noun u3we_chacha_xchacha(u3_noun);
+
+ u3_noun u3we_adler32(u3_noun);
+ u3_noun u3we_crc32(u3_noun);
+
+ u3_noun u3we_ripe(u3_noun);
+
+ u3_noun u3we_make(u3_noun);
+ u3_noun u3we_sign(u3_noun);
+ u3_noun u3we_reco(u3_noun);
+
+ u3_noun u3we_sosi(u3_noun);
+ u3_noun u3we_sove(u3_noun);
+
+ u3_noun u3we_en_base16(u3_noun);
+ u3_noun u3we_de_base16(u3_noun);
+
+ u3_noun u3we_json_de(u3_noun);
+ u3_atom u3we_json_en(u3_noun);
+
+ u3_noun u3we_bend_fun(u3_noun);
+ u3_noun u3we_cold_fun(u3_noun);
+ u3_noun u3we_cook_fun(u3_noun);
+ u3_noun u3we_comp_fun(u3_noun);
+ u3_noun u3we_easy_fun(u3_noun);
+ u3_noun u3we_glue_fun(u3_noun);
+ u3_noun u3we_here_fun(u3_noun);
+ u3_noun u3we_just_fun(u3_noun);
+ u3_noun u3we_mask_fun(u3_noun);
+ u3_noun u3we_shim_fun(u3_noun);
+ u3_noun u3we_stag_fun(u3_noun);
+ u3_noun u3we_stew_fun(u3_noun);
+ u3_noun u3we_stir_fun(u3_noun);
+
+ u3_noun u3wef_drg(u3_noun);
+ u3_noun u3wef_lug(u3_noun);
+
+ u3_noun u3wer_add(u3_noun);
+ u3_noun u3wer_sub(u3_noun);
+ u3_noun u3wer_mul(u3_noun);
+ u3_noun u3wer_div(u3_noun);
+ u3_noun u3wer_sqt(u3_noun);
+ u3_noun u3wer_fma(u3_noun);
+ u3_noun u3wer_lth(u3_noun);
+ u3_noun u3wer_lte(u3_noun);
+ u3_noun u3wer_equ(u3_noun);
+ u3_noun u3wer_gte(u3_noun);
+ u3_noun u3wer_gth(u3_noun);
+
+ u3_noun u3wet_add(u3_noun);
+ u3_noun u3wet_sub(u3_noun);
+ u3_noun u3wet_mul(u3_noun);
+ u3_noun u3wet_div(u3_noun);
+ u3_noun u3wet_sqt(u3_noun);
+ u3_noun u3wet_fma(u3_noun);
+ u3_noun u3wet_lth(u3_noun);
+ u3_noun u3wet_lte(u3_noun);
+ u3_noun u3wet_equ(u3_noun);
+ u3_noun u3wet_gte(u3_noun);
+ u3_noun u3wet_gth(u3_noun);
+
+ u3_noun u3weq_add(u3_noun);
+ u3_noun u3weq_sub(u3_noun);
+ u3_noun u3weq_mul(u3_noun);
+ u3_noun u3weq_div(u3_noun);
+ u3_noun u3weq_sqt(u3_noun);
+ u3_noun u3weq_fma(u3_noun);
+ u3_noun u3weq_lth(u3_noun);
+ u3_noun u3weq_lte(u3_noun);
+ u3_noun u3weq_equ(u3_noun);
+ u3_noun u3weq_gte(u3_noun);
+ u3_noun u3weq_gth(u3_noun);
+
+ u3_noun u3wes_add(u3_noun);
+ u3_noun u3wes_sub(u3_noun);
+ u3_noun u3wes_mul(u3_noun);
+ u3_noun u3wes_div(u3_noun);
+ u3_noun u3wes_sqt(u3_noun);
+ u3_noun u3wes_fma(u3_noun);
+ u3_noun u3wes_lth(u3_noun);
+ u3_noun u3wes_lte(u3_noun);
+ u3_noun u3wes_equ(u3_noun);
+ u3_noun u3wes_gte(u3_noun);
+ u3_noun u3wes_gth(u3_noun);
+
+ u3_noun u3we_crc32(u3_noun);
+ u3_noun u3we_decompress_zlib(u3_noun);
+ u3_noun u3we_decompress_gzip(u3_noun);
+
+ u3_noun u3we_lia_run_v1(u3_noun);
+ u3_noun u3we_lia_run_once(u3_noun);
+
+ //+| %utilities
+ u3_noun u3we_bytestream_rip_octs(u3_noun);
+ u3_noun u3we_bytestream_cat_octs(u3_noun);
+ u3_noun u3we_bytestream_can_octs(u3_noun);
+ //+| %navigation
+ u3_noun u3we_bytestream_skip_line(u3_noun);
+ u3_noun u3we_bytestream_find_byte(u3_noun);
+ u3_noun u3we_bytestream_seek_byte(u3_noun);
+ //+| %read-byte
+ u3_noun u3we_bytestream_read_byte(u3_noun);
+ //+| %read-octs
+ u3_noun u3we_bytestream_read_octs(u3_noun);
+ //+| %transformation
+ u3_noun u3we_bytestream_chunk(u3_noun);
+ u3_noun u3we_bytestream_extract(u3_noun);
+ u3_noun u3we_bytestream_fuse_extract(u3_noun);
+ //+| %bitstream
+ u3_noun u3we_bytestream_need_bits(u3_noun);
+ u3_noun u3we_bytestream_drop_bits(u3_noun);
+ // u3_noun u3we_bytestream_skip_bits(u3_noun);
+ u3_noun u3we_bytestream_peek_bits(u3_noun);
+ u3_noun u3we_bytestream_read_bits(u3_noun);
+ // u3_noun u3we_bytestream_read_need_bits(u3_noun);
+ u3_noun u3we_bytestream_byte_bits(u3_noun);
+
+ /** Tier 6.
+ **/
+ u3_noun u3wf_bull(u3_noun);
+ u3_noun u3wf_cell(u3_noun);
+ u3_noun u3wf_comb(u3_noun);
+ u3_noun u3wf_cons(u3_noun);
+ u3_noun u3wf_core(u3_noun);
+ u3_noun u3wf_cube(u3_noun);
+ u3_noun u3wf_face(u3_noun);
+ u3_noun u3wf_fine(u3_noun);
+ u3_noun u3wf_fitz(u3_noun);
+ u3_noun u3wf_flan_139(u3_noun);
+ u3_noun u3wf_flay(u3_noun);
+ u3_noun u3wf_flip_139(u3_noun);
+ u3_noun u3wf_flor_139(u3_noun);
+ u3_noun u3wf_forq(u3_noun);
+ u3_noun u3wf_fork(u3_noun);
+ u3_noun u3wf_hint(u3_noun);
+ u3_noun u3wf_hike(u3_noun);
+ u3_noun u3wf_look(u3_noun);
+ u3_noun u3wf_loot(u3_noun);
+
+ u3_noun u3wfl_bunt(u3_noun);
+ u3_noun u3wfl_whip(u3_noun);
+
+ u3_noun u3wfp_hack(u3_noun);
+ u3_noun u3wfp_late(u3_noun);
+ u3_noun u3wfp_open(u3_noun);
+ u3_noun u3wfp_rake(u3_noun);
+
+ u3_noun u3wfu_busk(u3_noun);
+ u3_noun u3wfu_crop(u3_noun);
+ u3_noun u3wfu_find(u3_noun);
+ u3_noun u3wfu_fond(u3_noun);
+ u3_noun u3wfu_fish(u3_noun);
+ u3_noun u3wfu_fuse(u3_noun);
+ u3_noun u3wfu_redo(u3_noun);
+ u3_noun u3wfu_mint(u3_noun);
+ u3_noun u3wfu_mull(u3_noun);
+ u3_noun u3wfu_nest_dext(u3_noun);
+ u3_noun u3wfu_peek(u3_noun);
+ u3_noun u3wfu_play(u3_noun);
+ u3_noun u3wfu_repo(u3_noun);
+ u3_noun u3wfu_rest(u3_noun);
+
+ /** Tier 7.
+ **/
+ u3_noun u3wg_plot_fax(u3_noun);
+ u3_noun u3wg_plot_met(u3_noun);
+ u3_noun u3wi_la_add(u3_noun);
+ u3_noun u3wi_la_sub(u3_noun);
+ u3_noun u3wi_la_mul(u3_noun);
+ u3_noun u3wi_la_div(u3_noun);
+ u3_noun u3wi_la_mod(u3_noun);
+ u3_noun u3wi_la_adds(u3_noun);
+ u3_noun u3wi_la_subs(u3_noun);
+ u3_noun u3wi_la_muls(u3_noun);
+ u3_noun u3wi_la_divs(u3_noun);
+ u3_noun u3wi_la_mods(u3_noun);
+ u3_noun u3wi_la_dot(u3_noun);
+ u3_noun u3wi_la_diag(u3_noun);
+ u3_noun u3wi_la_transpose(u3_noun);
+ u3_noun u3wi_la_cumsum(u3_noun);
+ u3_noun u3wi_la_argmin(u3_noun);
+ u3_noun u3wi_la_argmax(u3_noun);
+ u3_noun u3wi_la_ravel(u3_noun);
+ u3_noun u3wi_la_min(u3_noun);
+ u3_noun u3wi_la_max(u3_noun);
+ u3_noun u3wi_la_linspace(u3_noun);
+ u3_noun u3wi_la_range(u3_noun);
+ u3_noun u3wi_la_abs(u3_noun);
+ u3_noun u3wi_la_gth(u3_noun);
+ u3_noun u3wi_la_gte(u3_noun);
+ u3_noun u3wi_la_lth(u3_noun);
+ u3_noun u3wi_la_lte(u3_noun);
+
+ u3_noun u3wi_la_trace(u3_noun);
+ u3_noun u3wi_la_mmul(u3_noun);
+
+#endif /* ifndef U3_JETS_W_H */
+
diff --git a/vere/pkg/noun/jets_tests.c b/vere/pkg/noun/jets_tests.c
new file mode 100644
index 0000000..222b31a
--- /dev/null
+++ b/vere/pkg/noun/jets_tests.c
@@ -0,0 +1,994 @@
+/// @file
+
+#include "noun.h"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_init(1 << 20);
+ u3m_pave(c3y);
+}
+
+static inline c3_i
+_ud_etch(c3_d num_d, const c3_c* num_c)
+{
+ u3_atom num = u3i_chub(num_d);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_ud_c(num, &out_c);
+ c3_i ret_i = 1;
+
+ if ( 0 != strcmp(num_c, out_c) ) {
+ fprintf(stderr, "etch_ud: %" PRIu64 " fail; expected %s, got '%s'\r\n",
+ num_d, num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_ud(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_ud: %" PRIu64 " mismatch; expected %s\r\n", num_d, num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+
+ return ret_i;
+}
+
+static c3_i
+_test_etch_ud(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _ud_etch(0, "0");
+ ret_i &= _ud_etch(1, "1");
+ ret_i &= _ud_etch(12, "12");
+ ret_i &= _ud_etch(123, "123");
+ ret_i &= _ud_etch(1234, "1.234");
+ ret_i &= _ud_etch(12345, "12.345");
+ ret_i &= _ud_etch(123456, "123.456");
+ ret_i &= _ud_etch(1234567, "1.234.567");
+ ret_i &= _ud_etch(12345678, "12.345.678");
+ ret_i &= _ud_etch(123456789, "123.456.789");
+ ret_i &= _ud_etch(100000000, "100.000.000");
+ ret_i &= _ud_etch(101101101, "101.101.101");
+ ret_i &= _ud_etch(201201201, "201.201.201");
+ ret_i &= _ud_etch(302201100, "302.201.100");
+
+ ret_i &= _ud_etch(8589934592ULL, "8.589.934.592");
+ ret_i &= _ud_etch(2305843009213693952ULL, "2.305.843.009.213.693.952");
+ ret_i &= _ud_etch(18446744073709551615ULL, "18.446.744.073.709.551.615");
+
+ {
+ c3_c* num_c = "340.282.366.920.938.463.463.374.607.431.768.211.456";
+ u3_atom num = u3qc_bex(128);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_ud_c(num, &out_c);
+
+ if ( 0 != strncmp(num_c, out_c, len_i) ) {
+ fprintf(stderr, "etch_ud: (bex 128) fail; expected %s, got '%s'\r\n",
+ num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_ud(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_ud: (bex 128) mismatch; expected %s\r\n", num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+ }
+
+ return ret_i;
+}
+
+static inline c3_i
+_ux_etch(c3_d num_d, const c3_c* num_c)
+{
+ u3_atom num = u3i_chub(num_d);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_ux_c(num, &out_c);
+ c3_i ret_i = 1;
+
+ if ( 0 != strcmp(num_c, out_c) ) {
+ fprintf(stderr, "etch_ux: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n",
+ num_d, num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_ux(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_ux: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+
+ return ret_i;
+}
+
+static c3_i
+_test_etch_ux(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _ux_etch(0x0, "0x0");
+ ret_i &= _ux_etch(0x1, "0x1");
+ ret_i &= _ux_etch(0x12, "0x12");
+ ret_i &= _ux_etch(0x123, "0x123");
+ ret_i &= _ux_etch(0x1234, "0x1234");
+ ret_i &= _ux_etch(0x12345, "0x1.2345");
+ ret_i &= _ux_etch(0x123456, "0x12.3456");
+ ret_i &= _ux_etch(0x1234567, "0x123.4567");
+ ret_i &= _ux_etch(0x12345678, "0x1234.5678");
+ ret_i &= _ux_etch(0x123456789, "0x1.2345.6789");
+ ret_i &= _ux_etch(0x100000000, "0x1.0000.0000");
+ ret_i &= _ux_etch(0x101101101, "0x1.0110.1101");
+ ret_i &= _ux_etch(0x201201201, "0x2.0120.1201");
+ ret_i &= _ux_etch(0x302201100, "0x3.0220.1100");
+
+ ret_i &= _ux_etch(0x123456789abcdefULL, "0x123.4567.89ab.cdef");
+ ret_i &= _ux_etch(0x8589934592ULL, "0x85.8993.4592");
+ ret_i &= _ux_etch(0x5843009213693952ULL, "0x5843.0092.1369.3952");
+ ret_i &= _ux_etch(0x6744073709551615ULL, "0x6744.0737.0955.1615");
+
+ {
+ c3_c* num_c = "0x1.0000.0000.0000.0000.0000.0000.0000.0000";
+ u3_atom num = u3qc_bex(128);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_ux_c(num, &out_c);
+
+ if ( 0 != strncmp(num_c, out_c, len_i) ) {
+ fprintf(stderr, "etch_ux: (bex 128) fail; expected %s, got '%s'\r\n",
+ num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_ux(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_ux: (bex 128) mismatch; expected %s\r\n", num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+ }
+
+ return ret_i;
+}
+
+static inline c3_i
+_uv_etch(c3_d num_d, const c3_c* num_c)
+{
+ u3_atom num = u3i_chub(num_d);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_uv_c(num, &out_c);
+ c3_i ret_i = 1;
+
+ if ( 0 != strcmp(num_c, out_c) ) {
+ fprintf(stderr, "etch_uv: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n",
+ num_d, num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_uv(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_uv: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+
+ return ret_i;
+}
+
+static c3_i
+_test_etch_uv(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _uv_etch(0x0, "0v0");
+ ret_i &= _uv_etch(0x1, "0v1");
+ ret_i &= _uv_etch(0x10, "0vg");
+ ret_i &= _uv_etch(0x12, "0vi");
+ ret_i &= _uv_etch(0x123, "0v93");
+ ret_i &= _uv_etch(0x1234, "0v4hk");
+ ret_i &= _uv_etch(0x12345, "0v28q5");
+ ret_i &= _uv_etch(0x123456, "0v14d2m");
+ ret_i &= _uv_etch(0x1234567, "0vi6hb7");
+ ret_i &= _uv_etch(0x12345678, "0v9.38ljo");
+ ret_i &= _uv_etch(0x123456789, "0v4h.kaps9");
+ ret_i &= _uv_etch(0x100000000, "0v40.00000");
+ ret_i &= _uv_etch(0x101101101, "0v40.h0481");
+ ret_i &= _uv_etch(0x201201201, "0v80.i04g1");
+ ret_i &= _uv_etch(0x302201100, "0vc1.20480");
+
+ ret_i &= _uv_etch(0x123456789abcdefULL, "0v28.q5cu4.qnjff");
+ ret_i &= _uv_etch(0x8589934592ULL, "0vgm4.p6hci");
+ ret_i &= _uv_etch(0x5843009213693952ULL, "0v5gg.o0i89.mieai");
+ ret_i &= _uv_etch(0x6744073709551615ULL, "0v6eh.076s4.la5gl");
+
+ {
+ c3_c* num_c = "0v8.00000.00000.00000.00000.00000";
+ u3_atom num = u3qc_bex(128);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_uv_c(num, &out_c);
+
+ if ( 0 != strncmp(num_c, out_c, len_i) ) {
+ fprintf(stderr, "etch_uv: (bex 128) fail; expected %s, got '%s'\r\n",
+ num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_uv(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ // fprintf(stderr, "etch_uv: (bex 128) mismatch; expected %s\r\n", num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+ }
+
+ return ret_i;
+}
+
+static inline c3_i
+_uw_etch(c3_d num_d, const c3_c* num_c)
+{
+ u3_atom num = u3i_chub(num_d);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_uw_c(num, &out_c);
+ c3_i ret_i = 1;
+
+ if ( 0 != strcmp(num_c, out_c) ) {
+ fprintf(stderr, "etch_uw: 0x%" PRIx64 " fail; expected %s, got '%s'\r\n",
+ num_d, num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_uw(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_uw: 0x%" PRIx64 " mismatch; expected %s\r\n", num_d, num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+
+ return ret_i;
+}
+
+static c3_i
+_test_etch_uw(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _uw_etch(0x0, "0w0");
+ ret_i &= _uw_etch(0x1, "0w1");
+ ret_i &= _uw_etch(0x10, "0wg");
+ ret_i &= _uw_etch(0x12, "0wi");
+ ret_i &= _uw_etch(0x123, "0w4z");
+ ret_i &= _uw_etch(0x1234, "0w18Q");
+ ret_i &= _uw_etch(0x12345, "0wid5");
+ ret_i &= _uw_etch(0x123456, "0w4zhm");
+ ret_i &= _uw_etch(0x1234567, "0w18QlD");
+ ret_i &= _uw_etch(0x12345678, "0wid5pU");
+ ret_i &= _uw_etch(0x123456789, "0w4.zhmu9");
+ ret_i &= _uw_etch(0x100000000, "0w4.00000");
+ ret_i &= _uw_etch(0x101101101, "0w4.14141");
+ ret_i &= _uw_etch(0x201201201, "0w8.18181");
+ ret_i &= _uw_etch(0x302201100, "0wc.28140");
+
+ ret_i &= _uw_etch(0x123456789abcdefULL, "0w4zhmu.9GYTL");
+ ret_i &= _uw_etch(0x8589934592ULL, "0w8m.9AQmi");
+ ret_i &= _uw_etch(0x5843009213693952ULL, "0w5.x3098.jqjBi");
+ ret_i &= _uw_etch(0x6744073709551615ULL, "0w6.t41Ps.9lhol");
+
+ {
+ c3_c* num_c = "0w40.00000.00000.00000.00000";
+ u3_atom num = u3qc_bex(128);
+ c3_c* out_c;
+ size_t len_i = u3s_etch_uw_c(num, &out_c);
+
+ if ( 0 != strncmp(num_c, out_c, len_i) ) {
+ fprintf(stderr, "etch_uw: (bex 128) fail; expected %s, got '%s'\r\n",
+ num_c, out_c);
+ ret_i = 0;
+ }
+ else {
+ u3_noun out = u3s_etch_uw(num);
+ u3_noun tou = u3i_bytes(len_i, (c3_y*)out_c);
+
+ if ( c3n == u3r_sing(tou, out) ) {
+ fprintf(stderr, "etch_uw: (bex 128) mismatch; expected %s\r\n", num_c);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ u3z(tou);
+ }
+
+ c3_free(out_c);
+ u3z(num);
+ }
+
+ return ret_i;
+}
+
+static inline c3_i
+_ud_good(c3_w num_w, const c3_c* num_c)
+{
+ u3_weak out;
+ if ( num_w != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) {
+ if ( u3_none == out ) {
+ fprintf(stderr, "sift_ud: %s fail; expected %u\r\n", num_c, num_w);
+ }
+ else {
+ fprintf(stderr, "sift_ud: %s wrong; expected %u: actual %u\r\n", num_c, num_w, out);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline c3_i
+_ud_fail(const c3_c* num_c)
+{
+ u3_weak out;
+ if ( u3_none != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) {
+ u3m_p("out", out);
+ fprintf(stderr, "sift_ud: %s expected fail\r\n", num_c);
+ return 0;
+ }
+
+ return 1;
+}
+
+static c3_i
+_test_sift_ud(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _ud_good(0, "0");
+ ret_i &= _ud_good(1, "1");
+ ret_i &= _ud_good(12, "12");
+ ret_i &= _ud_good(123, "123");
+ ret_i &= _ud_good(1234, "1.234");
+ ret_i &= _ud_good(12345, "12.345");
+ ret_i &= _ud_good(123456, "123.456");
+ ret_i &= _ud_good(1234567, "1.234.567");
+ ret_i &= _ud_good(12345678, "12.345.678");
+ ret_i &= _ud_good(123456789, "123.456.789");
+ ret_i &= _ud_good(100000000, "100.000.000");
+ ret_i &= _ud_good(101101101, "101.101.101");
+ ret_i &= _ud_good(201201201, "201.201.201");
+ ret_i &= _ud_good(302201100, "302.201.100");
+
+ ret_i &= _ud_fail("01");
+ ret_i &= _ud_fail("02");
+ ret_i &= _ud_fail("003");
+ ret_i &= _ud_fail("1234");
+ ret_i &= _ud_fail("1234.5");
+ ret_i &= _ud_fail("1234.567.8");
+ ret_i &= _ud_fail("1234.56..78.");
+ ret_i &= _ud_fail("123.45a");
+ ret_i &= _ud_fail(".123.456");
+
+ {
+ c3_c* num_c = "4.294.967.296";
+ u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c);
+ u3_atom pro = u3qc_bex(32);
+
+ if ( u3_none == out ) {
+ fprintf(stderr, "sift_ud: (bex 32) fail\r\n");
+ ret_i = 0;
+ }
+
+ if ( c3n == u3r_sing(pro, out) ) {
+ u3m_p("out", out);
+ fprintf(stderr, "sift_ud: (bex 32) wrong\r\n");
+ ret_i = 0;
+ }
+
+ u3z(out); u3z(pro);
+ }
+
+
+ {
+ c3_c* num_c = "340.282.366.920.938.463.463.374.607.431.768.211.456";
+ u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c);
+ u3_atom pro = u3qc_bex(128);
+
+ if ( u3_none == out ) {
+ fprintf(stderr, "sift_ud: (bex 128) fail\r\n");
+ ret_i = 0;
+ }
+
+ if ( c3n == u3r_sing(pro, out) ) {
+ u3m_p("out", out);
+ fprintf(stderr, "sift_ud: (bex 128) wrong\r\n");
+ ret_i = 0;
+ }
+
+ u3z(out); u3z(pro);
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_en_base16(void)
+{
+ c3_i ret_i = 1;
+
+ {
+ u3_atom dat = 0xaa;
+ u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat);
+
+ if ( c3n == u3r_sing_c("aa", pro) ) {
+ fprintf(stderr, "en_base16: fail (a)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_atom dat = 0x1234;
+ u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat);
+
+ if ( c3n == u3r_sing_c("1234", pro) ) {
+ fprintf(stderr, "en_base16: fail (b)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_atom dat = 0xf012;
+ u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat);
+
+ if ( c3n == u3r_sing_c("f012", pro) ) {
+ fprintf(stderr, "en_base16: fail (c)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_atom dat = 0x10b;
+ u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat);
+
+ if ( c3n == u3r_sing_c("010b", pro) ) {
+ fprintf(stderr, "en_base16: fail (d)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_atom pro = u3qe_en_base16(3, 0x1234);
+
+ if ( c3n == u3r_sing_c("001234", pro) ) {
+ fprintf(stderr, "en_base16: fail (e)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_atom pro = u3qe_en_base16(1, 0x1234);
+
+ if ( c3n == u3r_sing_c("34", pro) ) {
+ fprintf(stderr, "en_base16: fail (f)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ return ret_i;
+}
+
+
+static c3_i
+_test_de_base16(void)
+{
+ c3_i ret_i = 1;
+
+ {
+ u3_noun inp = u3i_string("aa");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (a)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 1 != len ) {
+ fprintf(stderr, "de_base16: fail len (a)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0xaa != dat ) {
+ fprintf(stderr, "de_base16: fail dat (a)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ {
+ u3_noun inp = u3i_string("1234");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (b)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 2 != len ) {
+ fprintf(stderr, "de_base16: fail len (b)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x1234 != dat ) {
+ fprintf(stderr, "de_base16: fail dat (b)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ {
+ u3_noun inp = u3i_string("f012");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (c)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 2 != len ) {
+ fprintf(stderr, "de_base16: fail len (c)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0xf012 != dat ) {
+ fprintf(stderr, "de_base16: fail dat (c)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ {
+ u3_noun inp = u3i_string("010b");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (d)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 2 != len ) {
+ fprintf(stderr, "de_base16: fail len (d)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x10b != dat ) {
+ fprintf(stderr, "de_base16: fail dat (d)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ {
+ u3_noun inp = u3i_string("10b");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (e)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 2 != len ) {
+ fprintf(stderr, "de_base16: fail len (e)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x10b != dat ) {
+ fprintf(stderr, "de_base16: fail dat (e)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ {
+ u3_noun inp = u3i_string("001234");
+ u3_noun pro = u3qe_de_base16(inp);
+ u3_atom len, dat;
+
+ if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) {
+ fprintf(stderr, "de_base16: fail cell (f)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 3 != len ) {
+ fprintf(stderr, "de_base16: fail len (f)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x1234 != dat ) {
+ fprintf(stderr, "de_base16: fail dat (f)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(inp); u3z(pro);
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_base16(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _test_en_base16();
+ ret_i &= _test_de_base16();
+
+ return ret_i;
+}
+
+static c3_w
+_fein_ob_w(c3_w inp_w)
+{
+ u3_atom inp = u3i_word(inp_w);
+ u3_atom act = u3qe_fein_ob(inp);
+ c3_w act_w = u3r_word(0, act);
+ u3z(inp); u3z(act);
+ return act_w;
+}
+
+static c3_i
+_expect_fein_ob_w(c3_w inp_w, c3_w exp_w)
+{
+ c3_w act_w = _fein_ob_w(inp_w);
+
+ if ( act_w != exp_w ) {
+ fprintf(stderr, "fein: inp=0x%08x exp=0x%08x act=0x%08x\n",
+ inp_w, exp_w, act_w);
+ return 0;
+ }
+
+ return 1;
+}
+
+static c3_i
+_test_fein_ob(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _expect_fein_ob_w(0, 0);
+ ret_i &= _expect_fein_ob_w(0xffff, 0xffff);
+ ret_i &= _expect_fein_ob_w(0x1b08f, 0x76b920e5);
+ ret_i &= _expect_fein_ob_w(0x10000, 0x423e60bf);
+ ret_i &= _expect_fein_ob_w(0x10001, 0xd4400acb);
+ ret_i &= _expect_fein_ob_w(0x10002, 0xf429043);
+ ret_i &= _expect_fein_ob_w(0x10000000, 0xa04bc7fa);
+ ret_i &= _expect_fein_ob_w(0x1234abcd, 0x686f6c25);
+ ret_i &= _expect_fein_ob_w(0xabcd1234, 0x4a220c8);
+ ret_i &= _expect_fein_ob_w(0xdeadbeef, 0x909bc4a9);
+ ret_i &= _expect_fein_ob_w(0xfffff, 0x6746b96b);
+ ret_i &= _expect_fein_ob_w(0xffffffff, 0xbba4dcce);
+
+ return ret_i;
+}
+
+static c3_w
+_fynd_ob_w(c3_w inp_w)
+{
+ u3_atom inp = u3i_word(inp_w);
+ u3_atom act = u3qe_fynd_ob(inp);
+ c3_w act_w = u3r_word(0, act);
+ u3z(inp); u3z(act);
+ return act_w;
+}
+
+static c3_i
+_expect_fynd_ob_w(c3_w exp_w, c3_w inp_w)
+{
+ c3_w act_w = _fynd_ob_w(inp_w);
+
+ if ( act_w != exp_w ) {
+ fprintf(stderr, "fynd: inp=0x%08x exp=0x%08x act=0x%08x\n",
+ inp_w, exp_w, act_w);
+ return 0;
+ }
+
+ return 1;
+}
+
+static c3_i
+_test_fynd_ob(void)
+{
+ c3_i ret_i = 1;
+
+ ret_i &= _expect_fynd_ob_w(0, 0);
+ ret_i &= _expect_fynd_ob_w(0xffff, 0xffff);
+ ret_i &= _expect_fynd_ob_w(0x10000, 0x423e60bf);
+ ret_i &= _expect_fynd_ob_w(0x10001, 0xd4400acb);
+ ret_i &= _expect_fynd_ob_w(0x10002, 0xf429043);
+ ret_i &= _expect_fynd_ob_w(0x10000000, 0xa04bc7fa);
+ ret_i &= _expect_fynd_ob_w(0x1234abcd, 0x686f6c25);
+ ret_i &= _expect_fynd_ob_w(0xabcd1234, 0x4a220c8);
+ ret_i &= _expect_fynd_ob_w(0xdeadbeef, 0x909bc4a9);
+ ret_i &= _expect_fynd_ob_w(0xfffff, 0x6746b96b);
+ ret_i &= _expect_fynd_ob_w(0xffffffff, 0xbba4dcce);
+
+ return ret_i;
+}
+
+static c3_i
+_exhaust_roundtrip_fein_fynd_ob(void)
+{
+ c3_i ret_i = 1;
+ c3_w fyn_w, i_w;
+
+ {
+ u3_atom fen, fyn;
+
+ for ( i_w = 0x10000; i_w < 0x80000000; i_w++ ) {
+ fen = u3qe_fein_ob(i_w);
+ fyn = u3qe_fynd_ob(fen);
+ fyn_w = u3r_word(0, fyn);
+
+ if ( i_w != fyn_w ) {
+ fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n",
+ i_w, u3r_word(0, fen), fyn_w);
+ ret_i = 0;
+ }
+ u3z(fen); u3z(fyn);
+
+ if ( !(i_w % 0x1000000) ) {
+ fprintf(stderr, "fein/fynd: 0x%x done\n", i_w);
+ }
+ }
+ }
+
+ {
+ c3_w fen_w;
+
+ do {
+ fen_w = _fein_ob_w(i_w);
+ fyn_w = _fynd_ob_w(fen_w);
+ if ( i_w != fyn_w ) {
+ fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n",
+ i_w, fen_w, fyn_w);
+ ret_i = 0;
+ }
+
+ if ( !(i_w % 0x1000000) ) {
+ fprintf(stderr, "fein/fynd: 0x%x done\n", i_w);
+ }
+ }
+ while ( ++i_w );
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_ob(void)
+{
+ c3_i ret_i = 1;
+ ret_i &= _test_fein_ob();
+ ret_i &= _test_fynd_ob();
+ // disabled, takes almost ~m15
+ //
+ // ret_i &= _exhaust_roundtrip_fein_fynd_ob();
+ return ret_i;
+}
+
+static c3_i
+_test_mas(void)
+{
+ c3_i ret_i = 1;
+ u3_atom res;
+
+ if ( 0x4000 != (res = u3qc_mas(0x8000)) ) {
+ fprintf(stderr, "test mas fail: (mas 0x8000) != 0x4000: 0x'%x'\r\n", res);
+ ret_i = 0;
+ }
+
+ if ( 0x20000000 != (res = u3qc_mas(0x40000000)) ) {
+ fprintf(stderr, "test mas fail: (mas 0x4000.0000) != 0x2000.0000: 0x%x\r\n", res);
+ ret_i = 0;
+ }
+
+ {
+ u3_atom sam, pro;
+
+ sam = u3qc_bex(36);
+ pro = u3qc_bex(35);
+ res = u3qc_mas(sam);
+
+ if ( c3n == u3r_sing(pro, res) ) {
+ c3_c* out_c;
+ u3s_etch_ux_c(res, &out_c);
+ fprintf(stderr, "test mas fail: (mas (bex 36)) != (bex 35): %s\r\n", out_c);
+ c3_free(out_c);
+ ret_i = 0;
+ }
+
+ u3z(res); u3z(sam); u3z(pro);
+
+ sam = u3qc_bex(64);
+ pro = u3qc_bex(63);
+ res = u3qc_mas(sam);
+
+ if ( c3n == u3r_sing(pro, res) ) {
+ c3_c* out_c;
+ u3s_etch_ux_c(res, &out_c);
+ fprintf(stderr, "test mas fail: (mas (bex 64)) != (bex 63): %s\r\n", out_c);
+ c3_free(out_c);
+ ret_i = 0;
+ }
+
+ u3z(res); u3z(sam); u3z(pro);
+
+ sam = u3qc_bex(65);
+ pro = u3qc_bex(64);
+ res = u3qc_mas(sam);
+
+ if ( c3n == u3r_sing(pro, res) ) {
+ c3_c* out_c;
+ u3s_etch_ux_c(res, &out_c);
+ fprintf(stderr, "test mas fail: (mas (bex 65)) != (bex 64): %s\r\n", out_c);
+ c3_free(out_c);
+ ret_i = 0;
+ }
+
+ u3z(res); u3z(sam); u3z(pro);
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_jets(void)
+{
+ c3_i ret_i = 1;
+
+ if ( !_test_etch_ud() ) {
+ fprintf(stderr, "test jets: etch_ud: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_etch_ux() ) {
+ fprintf(stderr, "test jets: etch_ux: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_etch_uv() ) {
+ fprintf(stderr, "test jets: etch_uv: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_etch_uw() ) {
+ fprintf(stderr, "test jets: etch_uw: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_sift_ud() ) {
+ fprintf(stderr, "test jets: sift_ud: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_base16() ) {
+ fprintf(stderr, "test jets: base16: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_ob() ) {
+ fprintf(stderr, "test jets: ob: failed\r\n");
+ ret_i = 0;
+ }
+
+ if ( !_test_mas() ) {
+ fprintf(stderr, "test jets: mas: failed\r\n");
+ ret_i = 0;
+ }
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_jets() ) {
+ fprintf(stderr, "test jets: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test jets: ok\r\n");
+ return 0;
+}
diff --git a/vere/pkg/noun/log.c b/vere/pkg/noun/log.c
new file mode 100644
index 0000000..ee1888e
--- /dev/null
+++ b/vere/pkg/noun/log.c
@@ -0,0 +1,40 @@
+/// @file
+
+#include "log.h"
+
+#include <stdarg.h>
+
+#include "options.h"
+
+void
+u3l_log(const char* format, ...)
+{
+ va_list myargs;
+ va_start(myargs, format);
+
+ if (u3C.stderr_log_f) {
+ // the user set their own logging function. render the line and redirect
+ // to them.
+ //
+ char msg[4096];
+ vsnprintf(msg, 4096, format, myargs);
+ u3C.stderr_log_f(msg);
+ } else {
+ // this process did not set a logging function, fallback to stderr
+ //
+ vfprintf(stderr, format, myargs);
+ fprintf(stderr, "\r\n");
+ fflush(stderr);
+ }
+
+ va_end(myargs);
+}
+
+u3_weak
+u3l_punt(const char* name, u3_weak pro)
+{
+ if ( u3_none == pro ) {
+ u3l_log("%s-punt", name);
+ }
+ return pro;
+}
diff --git a/vere/pkg/noun/log.h b/vere/pkg/noun/log.h
new file mode 100644
index 0000000..4e94147
--- /dev/null
+++ b/vere/pkg/noun/log.h
@@ -0,0 +1,24 @@
+/// @file
+
+#ifndef U3_LOG_H
+#define U3_LOG_H
+
+#include "types.h"
+
+/* u3l_log(): logs to stderr or redirects to configured function.
+*/
+ void
+ u3l_log(const char* format, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+/* u3l_punt(): condtionally logs a named punt
+ * (e.g. "mint-punt" for the `name` "mint")
+ * when `pro` is u3_none, and returns pro.
+ * For use when a jet driver declines to handle
+ * a core, when the user should be somehow notified
+ * (e.g. in a cryptographic jet).
+ */
+ u3_weak
+ u3l_punt(const char* name, u3_weak pro);
+
+#endif /* ifndef U3_LOG_H */
diff --git a/vere/pkg/noun/manage.c b/vere/pkg/noun/manage.c
new file mode 100644
index 0000000..92e36dc
--- /dev/null
+++ b/vere/pkg/noun/manage.c
@@ -0,0 +1,2615 @@
+/// @file
+
+#include "manage.h"
+
+#include <ctype.h>
+#ifndef U3_OS_windows
+#include <dlfcn.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#if defined(U3_OS_osx)
+#include <execinfo.h>
+#endif
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(U3_OS_linux)
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#endif
+
+#include "allocate.h"
+#include "backtrace.h"
+#include "events.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "jets.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "log.h"
+#include "nock.h"
+#include "openssl/crypto.h"
+#include "options.h"
+#include "rsignal.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "urcrypt.h"
+#include "vortex.h"
+#include "whereami.h"
+#include "xtract.h"
+
+// XX stack-overflow recovery should be gated by -a
+//
+#undef NO_OVERFLOW
+
+ /* (u3_noun)setjmp(u3R->esc.buf): setjmp within road.
+ */
+#if 0
+ c3_o
+ u3m_trap(void);
+#else
+# define u3m_trap() (u3_noun)(setjmp(u3R->esc.buf))
+#endif
+
+ /* u3m_signal(): treat a nock-level exception as a signal interrupt.
+ */
+ void
+ u3m_signal(u3_noun sig_l);
+
+ /* u3m_dump(): dump the current road to stderr.
+ */
+ void
+ u3m_dump(void);
+
+ /* u3m_fall(): return to parent road.
+ */
+ void
+ u3m_fall(void);
+
+ /* u3m_leap(): in u3R, create a new road within the existing one.
+ */
+ void
+ u3m_leap(c3_w pad_w);
+
+ /* u3m_golf(): record cap length for u3m_flog().
+ */
+ c3_w
+ u3m_golf(void);
+
+ /* u3m_flog(): pop the cap.
+ **
+ ** A common sequence for inner allocation is:
+ **
+ ** c3_w gof_w = u3m_golf();
+ ** u3m_leap();
+ ** // allocate some inner stuff...
+ ** u3m_fall();
+ ** // inner stuff is still valid, but on cap
+ ** u3m_flog(gof_w);
+ **
+ ** u3m_flog(0) simply clears the cap.
+ */
+ void
+ u3m_flog(c3_w gof_w);
+
+ /* u3m_soft_top(): top-level safety wrapper.
+ */
+ u3_noun
+ u3m_soft_top(c3_w mil_w, // timer ms
+ c3_w pad_w, // base memory pad
+ u3_funk fun_f,
+ u3_noun arg);
+
+
+// u3m_signal uses restricted functionality signals for compatibility reasons:
+// some platforms may not provide true POSIX asynchronous signals and their
+// compat layer will then implement this restricted functionality subset.
+// u3m_signal never needs to interrupt I/O operations, its signal handlers
+// do not manipulate signals, do not modify shared state, and always either
+// return or longjmp.
+//
+static jmp_buf u3_Signal;
+
+#ifndef U3_OS_windows
+#include "sigsegv.h"
+
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 16384
+#endif
+#ifndef NO_OVERFLOW
+static uint8_t Sigstk[SIGSTKSZ];
+#endif
+#endif
+
+#ifdef U3_OS_windows
+#include "veh_handler.h"
+#endif
+
+#if 0
+/* _cm_punt(): crudely print trace.
+*/
+static void
+_cm_punt(u3_noun tax)
+{
+ u3_noun xat;
+
+ for ( xat = tax; xat; xat = u3t(xat) ) {
+ u3m_p("&", u3h(xat));
+ }
+}
+#endif
+
+/* _cm_emergency(): write emergency text to stderr, never failing.
+*/
+static void
+_cm_emergency(c3_c* cap_c, c3_l sig_l)
+{
+ write(2, "\r\n", 2);
+ write(2, cap_c, strlen(cap_c));
+
+ if ( sig_l ) {
+ write(2, ": ", 2);
+ write(2, &sig_l, 4);
+ }
+
+ write(2, "\r\n", 2);
+}
+
+static void _cm_overflow(void *arg1, void *arg2, void *arg3)
+{
+ (void)(arg1);
+ (void)(arg2);
+ (void)(arg3);
+ u3m_signal(c3__over);
+}
+
+/* _cm_signal_handle(): handle a signal in general.
+*/
+static void
+_cm_signal_handle(c3_l sig_l)
+{
+#ifndef U3_OS_windows
+ if ( c3__over == sig_l ) {
+#ifndef NO_OVERFLOW
+ sigsegv_leave_handler(_cm_overflow, NULL, NULL, NULL);
+#endif
+ } else
+#endif
+ {
+ u3m_signal(sig_l);
+ }
+}
+
+#ifndef NO_OVERFLOW
+static void
+#ifndef U3_OS_windows
+_cm_signal_handle_over(int emergency, stackoverflow_context_t scp)
+#else
+_cm_signal_handle_over(int x)
+#endif
+{
+ _cm_signal_handle(c3__over);
+}
+#endif
+
+static void
+_cm_signal_handle_term(int x)
+{
+ // Ignore if we are using base memory from work memory, very rare.
+ //
+ if ( (0 != u3H->rod_u.kid_p) && (&(u3H->rod_u) == u3R) ) {
+ _cm_emergency("ignored", c3__term);
+ }
+ else {
+ _cm_signal_handle(c3__term);
+ }
+}
+
+static void
+_cm_signal_handle_intr(int x)
+{
+ // Interrupt: stop work. Ignore if not working, or (rarely) using base.
+ //
+ if ( &(u3H->rod_u) == u3R ) {
+ _cm_emergency("ignored", c3__intr);
+ }
+ else {
+ _cm_signal_handle(c3__intr);
+ }
+}
+
+static void
+_cm_signal_handle_alrm(int x)
+{
+ _cm_signal_handle(c3__alrm);
+}
+
+/* _cm_signal_reset(): reset top road after signal longjmp.
+*/
+static void
+_cm_signal_reset(void)
+{
+ u3R = &u3H->rod_u;
+ u3R->cap_p = u3R->mat_p;
+ u3R->ear_p = 0;
+ u3R->kid_p = 0;
+}
+
+#if 0
+/* _cm_stack_recover(): recover stack trace, with lacunae.
+*/
+static u3_noun
+_cm_stack_recover(u3a_road* rod_u)
+{
+ c3_w len_w;
+
+ len_w = 0;
+ {
+ u3_noun tax = rod_u->bug.tax;
+
+ while ( tax ) {
+ len_w++;
+ tax = u3t(tax);
+ }
+
+ if ( len_w < 4096 ) {
+ return u3a_take(rod_u->bug.tax);
+ }
+ else {
+ u3_noun beg, fin;
+ c3_w i_w;
+
+ tax = rod_u->bug.tax;
+ beg = u3_nul;
+ for ( i_w = 0; i_w < 2048; i_w++ ) {
+ beg = u3nc(u3a_take(u3h(tax)), beg);
+ tax = u3t(tax);
+ }
+ beg = u3kb_flop(beg);
+
+ for ( i_w = 0; i_w < (len_w - 4096); i_w++ ) {
+ tax = u3t(tax);
+ }
+ fin = u3nc(u3nc(c3__lose, c3__over), u3a_take(tax));
+
+ return u3kb_weld(beg, fin);
+ }
+ }
+}
+#endif
+
+/* _cm_stack_unwind(): unwind to the top level, preserving all frames.
+*/
+static u3_noun
+_cm_stack_unwind(void)
+{
+ u3_noun tax;
+
+ while ( u3R != &(u3H->rod_u) ) {
+ u3_noun yat = u3m_love(u3R->bug.tax);
+
+ u3R->bug.tax = u3kb_weld(yat, u3R->bug.tax);
+ }
+ tax = u3R->bug.tax;
+
+ u3R->bug.tax = 0;
+ return tax;
+}
+
+/* _cm_signal_recover(): recover from a deep signal, after longjmp. Free arg.
+*/
+static u3_noun
+_cm_signal_recover(c3_l sig_l, u3_noun arg)
+{
+ u3_noun tax;
+
+ // Unlikely to be set, but it can be made to happen.
+ //
+ tax = u3H->rod_u.bug.tax;
+ u3H->rod_u.bug.tax = 0;
+
+ if ( NULL != stk_u ) {
+ stk_u->off_w = u3H->rod_u.off_w;
+ stk_u->fow_w = u3H->rod_u.fow_w;
+ }
+
+ if ( &(u3H->rod_u) == u3R ) {
+ // A top-level crash - rather odd. We should GC.
+ //
+ _cm_emergency("recover: top", sig_l);
+ u3C.wag_w |= u3o_check_corrupt;
+
+ // Reset the top road - the problem could be a fat cap.
+ //
+ _cm_signal_reset();
+
+ if ( (c3__meme == sig_l) && (u3a_open(u3R) <= 256) ) {
+ // Out of memory at the top level. Error becomes c3__full,
+ // and we release the emergency buffer. To continue work,
+ // we need to readjust the image, eg, migrate to 64 bit.
+ //
+ u3z(u3R->bug.mer);
+ u3R->bug.mer = 0;
+ sig_l = c3__full;
+ }
+ return u3nt(3, sig_l, tax);
+ }
+ else {
+ u3_noun pro;
+
+ // A signal was generated while we were within Nock.
+ //
+ _cm_emergency("recover: dig", sig_l);
+
+#if 0
+ // Descend to the innermost trace, collecting stack.
+ //
+ {
+ u3a_road* rod_u;
+
+ u3R = &(u3H->rod_u);
+ rod_u = u3R;
+
+ while ( rod_u->kid_p ) {
+#if 0
+ u3l_log("collecting %d frames",
+ u3kb_lent((u3to(u3_road, rod_u->kid_p)->bug.tax));
+#endif
+ tax = u3kb_weld(_cm_stack_recover(u3to(u3_road, rod_u->kid_p)), tax);
+ rod_u = u3to(u3_road, rod_u->kid_p);
+ }
+ }
+#else
+ tax = _cm_stack_unwind();
+#endif
+ pro = u3nt(3, sig_l, tax);
+ _cm_signal_reset();
+
+ u3z(arg);
+ return pro;
+ }
+}
+
+/* _cm_signal_deep(): start deep processing; set timer for [mil_w] or 0.
+*/
+static void
+_cm_signal_deep(c3_w mil_w)
+{
+ // disable outer system signal handling
+ //
+ if ( 0 != u3C.sign_hold_f ) {
+ u3C.sign_hold_f();
+ }
+
+#ifndef NO_OVERFLOW
+#ifndef U3_OS_windows
+ if ( 0 != stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ)) {
+ u3l_log("unable to install stack overflow handler");
+ abort();
+ }
+#else
+ rsignal_install_handler(SIGSTK, _cm_signal_handle_over);
+#endif
+#endif
+ rsignal_install_handler(SIGINT, _cm_signal_handle_intr);
+ rsignal_install_handler(SIGTERM, _cm_signal_handle_term);
+
+ // Provide a little emergency memory, for use in case things
+ // go utterly haywire.
+ //
+ if ( 0 == u3H->rod_u.bug.mer ) {
+ u3H->rod_u.bug.mer = u3i_string(
+ "emergency buffer with sufficient space to cons the trace and bail"
+ );
+ }
+
+ if ( mil_w ) {
+ struct itimerval itm_u;
+
+ timerclear(&itm_u.it_interval);
+ itm_u.it_value.tv_sec = (mil_w / 1000);
+ itm_u.it_value.tv_usec = 1000 * (mil_w % 1000);
+
+ if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) {
+ u3l_log("loom: set timer failed %s", strerror(errno));
+ }
+ else {
+ rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm);
+ }
+ }
+
+ u3t_boot();
+}
+
+/* _cm_signal_done():
+*/
+static void
+_cm_signal_done(void)
+{
+ rsignal_deinstall_handler(SIGINT);
+ rsignal_deinstall_handler(SIGTERM);
+ rsignal_deinstall_handler(SIGVTALRM);
+
+#ifndef NO_OVERFLOW
+#ifndef U3_OS_windows
+ stackoverflow_deinstall_handler();
+#else
+ rsignal_install_handler(SIGSTK, _cm_signal_handle_over);
+#endif
+#endif
+ {
+ struct itimerval itm_u;
+
+ timerclear(&itm_u.it_interval);
+ timerclear(&itm_u.it_value);
+
+ if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) {
+ u3l_log("loom: clear timer failed %s", strerror(errno));
+ }
+ }
+
+ // restore outer system signal handling
+ //
+ if ( 0 != u3C.sign_move_f ) {
+ u3C.sign_move_f();
+ }
+
+ u3t_boff();
+}
+
+/* u3m_signal(): treat a nock-level exception as a signal interrupt.
+*/
+void
+u3m_signal(u3_noun sig_l)
+{
+ rsignal_longjmp(u3_Signal, sig_l);
+}
+
+/* u3m_file(): load file, as atom, or bail.
+*/
+u3_noun
+u3m_file(c3_c* pas_c)
+{
+ struct stat buf_b;
+ c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644);
+ c3_w fln_w, red_w;
+ c3_y* pad_y;
+
+ if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
+ u3l_log("%s: %s", pas_c, strerror(errno));
+ return u3m_bail(c3__fail);
+ }
+ fln_w = buf_b.st_size;
+ pad_y = c3_malloc(buf_b.st_size);
+
+ red_w = read(fid_i, pad_y, fln_w);
+ close(fid_i);
+
+ if ( fln_w != red_w ) {
+ c3_free(pad_y);
+ return u3m_bail(c3__fail);
+ }
+ else {
+ u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y);
+ c3_free(pad_y);
+
+ return pad;
+ }
+}
+
+/* u3m_mark(): mark all nouns in the road.
+*/
+u3m_quac**
+u3m_mark(void)
+{
+ u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 5);
+ qua_u[0] = u3v_mark();
+ qua_u[1] = u3j_mark();
+ qua_u[2] = u3n_mark();
+ qua_u[3] = u3a_mark_road(); // NB: must be the last thing marked
+ qua_u[4] = NULL;
+
+ return qua_u;
+}
+
+/* _pave_parts(): build internal tables.
+*/
+static void
+_pave_parts(void)
+{
+ u3a_init_heap();
+
+ if ( &(u3H->rod_u) != u3R ) {
+ u3R->cel.cel_p = u3of(u3_post, u3a_walloc(1U << u3a_page));
+ }
+
+ u3R->cax.har_p = u3h_new_cache(u3C.hap_w); // transient
+ u3R->cax.per_p = u3h_new_cache(u3C.per_w); // persistent
+ u3R->jed.war_p = u3h_new();
+ u3R->jed.cod_p = u3h_new();
+ u3R->jed.han_p = u3h_new();
+ u3R->jed.bas_p = u3h_new();
+ u3R->byc.har_p = u3h_new();
+}
+
+static c3_d
+_pave_params(void)
+{
+ // pam_d bits:
+ // { word-size[1], virtual-bits[2], page-size[3], bytecode[5], ... }
+ //
+ // word-size: 0==32, 1==64
+ // page-size: relative binary-log in bytes
+ //
+ //
+ return 0
+ ^ (u3a_vits << 1)
+ ^ ((u3a_page + 2 - 12) << 3)
+ ^ (U3N_VERLAT << 6);
+}
+
+/* _pave_home(): initialize pristine home road.
+*/
+static void
+_pave_home(void)
+{
+ u3_post top_p = u3C.wor_i - u3a_walign;
+ u3_post bot_p = 1U << u3a_page;
+
+ u3H = u3to(u3v_home, 0);
+ memset(u3H, 0, sizeof(u3v_home));
+ u3H->ver_d = U3V_VERLAT;
+ u3H->pam_d = _pave_params();
+
+ u3R = &u3H->rod_u;
+
+ u3R->rut_p = u3R->hat_p = bot_p;
+ u3R->mat_p = u3R->cap_p = top_p;
+
+ _pave_parts();
+}
+
+STATIC_ASSERT( (c3_wiseof(u3v_home) <= (1U << u3a_page)),
+ "home road size" );
+
+STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)),
+ "home road alignment" );
+
+STATIC_ASSERT( U3N_VERLAT < (1U << 5), "5-bit bytecode version" );
+
+/* _find_home(): in restored image, point to home road.
+*/
+static void
+_find_home(void)
+{
+ c3_d ver_d = *((c3_d*)u3_Loom);
+
+ if ( ver_d != U3V_VERLAT ) {
+ fprintf(stderr, "loom: checkpoint version mismatch: "
+ "have %" PRIu64 ", need %" PRIu64 "\r\n",
+ ver_d, U3V_VERLAT);
+ abort();
+ }
+
+ c3_d pam_d = *((c3_d*)u3_Loom + 1);
+
+ if ( pam_d & 1 ) {
+ fprintf(stderr, "word-size mismatch: 64-bit snapshot in 32-bit binary\r\n");
+ abort();
+ }
+ if ( ((pam_d >> 1) & 3) != u3a_vits ) {
+ fprintf(stderr, "virtual-bits mismatch: %u in snapshot; %u in binary\r\n",
+ (c3_w)((pam_d >> 1) & 3), u3a_vits);
+ abort();
+ }
+ if ( (12 + ((pam_d >> 3) & 7)) != (u3a_page + 2) ) {
+ fprintf(stderr, "page-size mismatch: %u in snapshot; %u in binary\r\n",
+ 1U << (12 + ((pam_d >> 3) & 7)), (c3_w)u3a_page + 2);
+ abort();
+ }
+
+ // NB: the home road is always north
+ //
+ {
+ u3_post top_p = u3C.wor_i - u3a_walign;
+
+ u3H = u3to(u3v_home, 0);
+ u3R = &u3H->rod_u;
+
+ // this looks risky, but there are no legitimate scenarios
+ // where it's wrong
+ //
+ u3R->mat_p = u3R->cap_p = top_p;
+ }
+
+ // check for obvious corruption
+ //
+ {
+ c3_w nor_w;
+ u3_post low_p, hig_p;
+ u3m_water(&low_p, &hig_p);
+
+ nor_w = (low_p + ((1 << u3a_page) - 1)) >> u3a_page;
+
+ if ( nor_w > u3P.img_u.pgs_w ) {
+ fprintf(stderr, "loom: corrupt size (%u, %u)\r\n",
+ nor_w, u3P.img_u.pgs_w);
+ u3_assert(!"loom: corrupt size");
+ }
+
+ // the north segment is in-order on disk; it being oversized
+ // doesn't necessarily indicate corruption.
+ //
+ if ( nor_w < u3P.img_u.pgs_w ) {
+ fprintf(stderr, "loom: strange size north (%u, %u)\r\n",
+ nor_w, u3P.img_u.pgs_w);
+ }
+
+ // XX move me
+ //
+ u3a_ream();
+ }
+
+ /* As a further guard against any sneaky loom corruption */
+ u3a_loom_sane();
+
+ _rod_vaal(u3R);
+
+ if ( ((pam_d >> 6) & 31) != U3N_VERLAT ) {
+ fprintf(stderr, "loom: discarding stale bytecode programs\r\n");
+ u3j_ream();
+ u3n_ream();
+ u3n_reclaim();
+ u3j_reclaim();
+ u3H->pam_d = _pave_params();
+ }
+}
+
+/* u3m_pave(): instantiate or activate image.
+*/
+void
+u3m_pave(c3_o nuu_o)
+{
+ if ( c3y == nuu_o ) {
+ _pave_home();
+ }
+ else {
+ _find_home();
+ }
+}
+
+#if 0
+/* u3m_clear(): clear all allocated data in road.
+*/
+void
+u3m_clear(void)
+{
+ u3h_free(u3R->cax.har_p);
+ u3j_free();
+ u3n_free();
+}
+
+void
+u3m_dump(void)
+{
+ c3_w hat_w;
+ c3_w fre_w = 0;
+ c3_w i_w;
+
+ hat_w = _(u3a_is_north(u3R)) ? u3R->hat_w - u3R->rut_w
+ : u3R->rut_w - u3R->hat_w;
+
+ for ( i_w = 0; i_w < u3_cc_fbox_no; i_w++ ) {
+ u3a_fbox* fre_u = u3R->all.fre_u[i_w];
+
+ while ( fre_u ) {
+ fre_w += fre_u->box_u.siz_w;
+ fre_u = fre_u->nex_u;
+ }
+ }
+ u3l_log("dump: hat_w %x, fre_w %x, allocated %x",
+ hat_w, fre_w, (hat_w - fre_w));
+
+ if ( 0 != (hat_w - fre_w) ) {
+ c3_w* box_w = _(u3a_is_north(u3R)) ? u3R->rut_w : u3R->hat_w;
+ c3_w mem_w = 0;
+
+ while ( box_w < (_(u3a_is_north(u3R)) ? u3R->hat_w : u3R->rut_w) ) {
+ u3a_box* box_u = (void *)box_w;
+
+ if ( 0 != box_u->use_w ) {
+#ifdef U3_MEMORY_DEBUG
+ // u3l_log("live %d words, code %x", box_u->siz_w, box_u->cod_w);
+#endif
+ mem_w += box_u->siz_w;
+ }
+ box_w += box_u->siz_w;
+ }
+
+ u3l_log("second count: %x", mem_w);
+ }
+}
+#endif
+
+struct bt_cb_data {
+ c3_y count;
+ c3_y fail;
+ c3_c* pn_c;
+};
+
+static void
+err_cb(void* data, const char* msg, int errnum)
+{
+ struct bt_cb_data* bdata = (struct bt_cb_data *)data;
+ bdata->count++;
+
+ if ( bdata->count <= 1 ) {
+ /* u3l_log("Backtrace error %d: %s", errnum, msg); */
+ bdata->fail = 1;
+ }
+}
+
+static int
+bt_cb(void* data,
+ uintptr_t pc,
+ const char* filename,
+ int lineno,
+ const char* function)
+{
+ #ifndef U3_OS_windows
+ struct bt_cb_data* bdata = (struct bt_cb_data *)data;
+ bdata->count++;
+
+ Dl_info info = {};
+ c3_c* fname_c = {0};
+
+ if ( dladdr((void *)pc, &info) ) {
+ for ( c3_w i_w = 0; info.dli_fname[i_w] != 0; i_w++ )
+ if ( info.dli_fname[i_w] == '/' ) {
+ fname_c = (c3_c*)&info.dli_fname[i_w + 1];
+ }
+ }
+
+ if ( bdata->count <= 100 ) {
+ c3_c* loc[128];
+ if (filename != 0) {
+ snprintf((c3_c*)loc, 128, "%s:%d", filename, lineno);
+ }
+ else {
+ snprintf((c3_c*)loc, 128, "%s", fname_c != 0 ? fname_c : "-");
+ }
+
+ c3_c* fn_c;
+ if (function != 0 || bdata->pn_c != 0) {
+ fn_c = (c3_c*)(function != 0 ? function : bdata->pn_c);
+ }
+ else {
+ fn_c = (c3_c*)(info.dli_sname != 0 ? info.dli_sname : "-");
+ }
+
+ fprintf(stderr, "%-3d %-35s %s\r\n", bdata->count - 1, fn_c, (c3_c *)loc);
+
+ bdata->pn_c = 0;
+ return 0;
+ }
+ else {
+ bdata->pn_c = 0;
+ return 1;
+ }
+ #endif
+ return 0;
+}
+
+/* _self_path(): get binary self-path.
+ */
+static c3_y
+_self_path(c3_c *pat_c)
+{
+ c3_i len_i = 0;
+ c3_i pat_i;
+
+ if ( 0 < (len_i = wai_getExecutablePath(NULL, 0, &pat_i)) ) {
+ wai_getExecutablePath(pat_c, len_i, &pat_i);
+ pat_c[len_i] = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+u3m_stacktrace()
+{
+#ifndef U3_OS_windows
+ void* bt_state;
+ struct bt_cb_data data = { 0, 0, 0 };
+ c3_c* self_path_c[4096] = {0};
+
+#if defined(U3_OS_osx)
+ fprintf(stderr, "Stacktrace:\r\n");
+
+ if ( _self_path((c3_c*)self_path_c) == 0 ) {
+ bt_state = backtrace_create_state((const c3_c*)self_path_c, 0, err_cb, 0);
+ backtrace_full(bt_state, 0, bt_cb, err_cb, &data);
+ if (data.fail == 0) {
+ fprintf(stderr, "\r\n");
+ }
+ }
+ else {
+ data.fail = 1;
+ }
+
+ if ( data.fail == 1 ) {
+ void* array[100];
+ c3_c** strings;
+ size_t size = backtrace(array, 100);
+
+ strings = backtrace_symbols(array, size);
+
+ if ( strings[0] == NULL ) {
+ fprintf(stderr, "Backtrace failed\r\n");
+ }
+ else {
+ for ( c3_i i = 0; i < size; i++ ) {
+ fprintf(stderr, "%s\r\n", strings[i]);
+ }
+ fprintf(stderr, "\r\n");
+ }
+
+ free(strings);
+ }
+#elif defined(U3_OS_linux)
+ /* TODO: Fix unwind not getting past signal trampoline on linux aarch64
+ */
+ fprintf(stderr, "Stacktrace:\r\n");
+
+ if ( _self_path((c3_c*)self_path_c) == 0 ) {
+ bt_state = backtrace_create_state((const c3_c*)self_path_c, 0, err_cb, 0);
+
+ unw_context_t context;
+ unw_cursor_t cursor;
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+ unw_word_t pc, sp;
+
+ c3_c* pn_c[1024] = {0};
+ c3_w offp_w = 0;
+
+ do {
+ unw_get_reg(&cursor, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+ if ( 0 == unw_get_proc_name(&cursor, (c3_c*)pn_c, 1024, (unw_word_t *)&offp_w) )
+ data.pn_c = (c3_c*)pn_c;
+ backtrace_pcinfo(bt_state, pc - 1, bt_cb, err_cb, &data);
+ } while (unw_step(&cursor) > 0);
+
+ if ( (data.count > 0) ) {
+ fprintf(stderr, "\r\n");
+ }
+ }
+ else {
+ data.fail = 1;
+ fprintf(stderr, "Backtrace failed\r\n");
+ }
+#endif
+#endif
+}
+
+/* u3m_bail(): bail out. Does not return.
+**
+** Bail motes:
+**
+** %evil :: erroneous cryptography
+** %exit :: semantic failure
+** %oops :: assertion failure
+** %intr :: interrupt
+** %fail :: computability failure
+** %over :: stack overflow (a kind of %fail)
+** %meme :: out of memory
+**
+** These are equivalents of the full exception noun, the error ball:
+**
+** $% [%0 success]
+** [%1 paths]
+** [%2 trace]
+** [%3 code trace]
+** ==
+**
+** XX several of these abort() calls should be gated by -a
+*/
+c3_i
+u3m_bail(u3_noun how)
+{
+ // printf some metadata
+ //
+ switch ( how ) {
+ case c3__evil:
+ case c3__exit: break;
+
+ default: {
+ if ( _(u3ud(how)) ) {
+ c3_c str_c[5];
+
+ str_c[0] = ((how >> 0) & 0xff);
+ str_c[1] = ((how >> 8) & 0xff);
+ str_c[2] = ((how >> 16) & 0xff);
+ str_c[3] = ((how >> 24) & 0xff);
+ str_c[4] = 0;
+ fprintf(stderr, "\r\nbail: %s\r\n", str_c);
+ }
+ else if ( 1 != u3h(how) ) {
+ u3_assert(_(u3ud(u3h(how))));
+ fprintf(stderr, "\r\nbail: %d\r\n", u3h(how));
+ }
+ }
+ }
+
+ if ( &(u3H->rod_u) == u3R ) {
+ // XX set exit code
+ //
+ fprintf(stderr, "home: bailing out\r\n\r\n");
+ u3m_stacktrace();
+ abort();
+ }
+
+ // intercept fatal errors
+ //
+ switch ( how ) {
+ case c3__foul:
+ case c3__oops: {
+ // XX set exit code
+ //
+ fprintf(stderr, "bailing out\r\n\r\n");
+ u3m_stacktrace();
+ abort();
+ }
+ }
+
+ if ( &(u3H->rod_u) == u3R ) {
+ // For top-level errors, which shouldn't happen often, we have no
+ // choice but to use the signal process; and we require the flat
+ // form of how.
+ //
+ // XX JB: these seem unrecoverable, at least wrt memory management,
+ // so they've been disabled above for now
+ //
+ u3_assert(_(u3a_is_cat(how)));
+ u3m_signal(how);
+ }
+
+ // release the emergency buffer, ensuring space for cells
+ //
+ u3z(u3R->bug.mer);
+ u3R->bug.mer = 0;
+
+ /* Reconstruct a correct error ball.
+ */
+ if ( _(u3ud(how)) ) {
+ switch ( how ) {
+ case c3__exit: {
+ how = u3nc(2, u3R->bug.tax);
+ } break;
+
+ default: {
+ how = u3nt(3, how, u3R->bug.tax);
+ } break;
+ }
+ }
+
+ // Reset the spin stack pointer
+ if ( NULL != stk_u ) {
+ stk_u->off_w = u3R->off_w;
+ stk_u->fow_w = u3R->fow_w;
+ }
+
+ /* Longjmp, with an underscore.
+ */
+ _longjmp(u3R->esc.buf, how);
+}
+
+int c3_cooked(void) { return u3m_bail(c3__oops); }
+
+/* u3m_error(): bail out with %exit, ct_pushing error.
+*/
+c3_i
+u3m_error(c3_c* str_c)
+{
+ u3t_mean(u3i_string(str_c));
+ return u3m_bail(c3__exit);
+}
+
+/* u3m_leap(): in u3R, create a new road within the existing one.
+*/
+void
+u3m_leap(c3_w pad_w)
+{
+ u3_road* rod_u;
+
+ _rod_vaal(u3R);
+
+ // push a new road struct onto the stack
+ //
+ {
+ u3a_pile pil_u;
+ c3_p ptr_p;
+ u3a_pile_prep(&pil_u, sizeof(u3a_road) + 15); // XX refactor to wiseof
+ ptr_p = (c3_p)u3a_push(&pil_u);
+
+ // XX add push_once, push_once_aligned
+ //
+ if ( ptr_p & 15 ) {
+ ptr_p &= ~15;
+ if ( c3n == u3a_is_north(u3R) ) {
+ ptr_p += 16;
+ }
+ }
+
+ rod_u = (void*)ptr_p;
+ memset(rod_u, 0, sizeof(u3a_road));
+ }
+
+ /* Allocate a region on the cap.
+ */
+ {
+ u3p(c3_w) bot_p, top_p; /* S: bot_p = new mat. N: bot_p = new rut */
+
+ if ( c3y == u3a_is_north(u3R) ) {
+ // pad and page-align the hat
+ //
+ bot_p = u3R->hat_p + pad_w;
+ bot_p += (1U << u3a_page) - 1;
+ bot_p &= ~((1U << u3a_page) - 1);
+ top_p = u3R->cap_p;
+ top_p &= ~((1U << u3a_page) - 1);
+
+ if ( bot_p >= top_p ) {
+ u3m_bail(c3__meme);
+ }
+
+ u3e_ward(bot_p - 1, top_p);
+ rod_u->mat_p = rod_u->cap_p = bot_p;
+ rod_u->rut_p = rod_u->hat_p = top_p;
+
+ // in a south road, the heap is high and the stack is low
+ //
+ // the heap starts at the end of the memory segment;
+ // the stack starts at the base memory pointer [mem_w],
+ // and ends after the space for the road structure [siz_w]
+ //
+ // 00~~~|M|+++|C|######|H|---|R|~~~FFF
+ // ^---u3R which _pave_road returns
+ //
+ // XX obsolete?
+
+ _rod_vaal(rod_u);
+#if 0
+ fprintf(stderr, "NPAR.hat_p: 0x%x %p, SKID.hat_p: 0x%x %p\r\n",
+ u3R->hat_p, u3a_into(u3R->hat_p),
+ rod_u->hat_p, u3a_into(rod_u->hat_p));
+#endif
+ }
+ else {
+ bot_p = u3R->cap_p;
+ bot_p += (1U << u3a_page) - 1;
+ bot_p &= ~((1U << u3a_page) - 1);
+ top_p = u3R->hat_p - pad_w;
+ top_p &= ~((1U << u3a_page) - 1);
+
+ // XX moar
+ if ( (u3R->hat_p < pad_w) || (bot_p >= top_p) ) {
+ u3m_bail(c3__meme);
+ }
+
+ u3e_ward(bot_p - 1, top_p);
+ rod_u->rut_p = rod_u->hat_p = bot_p;
+ rod_u->mat_p = rod_u->cap_p = top_p;
+
+ // in a north road, the heap is low and the stack is high
+ //
+ // the heap starts at the base memory pointer [mem_w];
+ // the stack starts at the end of the memory segment,
+ // minus space for the road structure [siz_w]
+ //
+ // 00~~~|R|---|H|######|C|+++|M|~~~FF
+ // ^--u3R which _pave_road returns (u3H for home road)
+ //
+ // XX obsolete?
+
+ _rod_vaal(rod_u);
+
+#if 0
+ fprintf(stderr, "SPAR.hat_p: 0x%x %p, NKID.hat_p: 0x%x %p\r\n",
+ u3R->hat_p, u3a_into(u3R->hat_p),
+ rod_u->hat_p, u3a_into(rod_u->hat_p));
+
+#endif
+ }
+ }
+
+ /* Attach the new road to its parents.
+ */
+ {
+ u3_assert(0 == u3R->kid_p);
+ rod_u->par_p = u3of(u3_road, u3R);
+ u3R->kid_p = u3of(u3_road, rod_u);
+ }
+
+ // Add slow stack pointer to rod_u
+ if ( NULL != stk_u ) {
+ rod_u->off_w = stk_u->off_w;
+ rod_u->fow_w = stk_u->fow_w;
+ }
+
+ /* Set up the new road.
+ */
+ {
+ u3R = rod_u;
+ _pave_parts();
+ }
+#ifdef U3_MEMORY_DEBUG
+ rod_u->all.fre_w = 0;
+#endif
+
+ _rod_vaal(u3R);
+}
+
+void
+_print_diff(c3_c* cap_c, c3_w a, c3_w b)
+{
+ c3_w diff = a<b ? b-a : a-b;
+ u3a_print_memory(stderr, cap_c, diff);
+}
+
+/* u3m_fall(): in u3R, return an inner road to its parent.
+*/
+void
+u3m_fall(void)
+{
+ u3_assert(0 != u3R->par_p);
+
+#if 0
+ /* If you're printing a lot of these you need to change
+ * u3a_print_memory from fprintf to u3l_log
+ */
+ fprintf(stderr, "fall: from %s %p, to %s %p (cap 0x%x, was 0x%x)\r\n",
+ _(u3a_is_north(u3R)) ? "north" : "south",
+ (void*)u3R,
+ _(u3a_is_north(u3to(u3_road, u3R->par_p))) ? "north" : "south",
+ u3to(void, u3R->par_p),
+ u3R->hat_p,
+ u3R->rut_p);
+ _print_diff("unused free", u3R->hat_p, u3R->cap_p);
+ _print_diff("freeing", u3R->rut_p, u3R->hat_p);
+ _print_diff("stack", u3R->cap_p, u3R->mat_p);
+ static c3_w wat_w = 500000000;
+ if (u3to(u3_road, u3R->par_p) == &u3H->rod_u) {
+ wat_w = 500000000;
+ }
+ else {
+ wat_w = c3_min(wat_w,
+ u3R->hat_p < u3R->cap_p ?
+ u3R->cap_p - u3R->hat_p :
+ u3R->hat_p - u3R->cap_p);
+ }
+ u3a_print_memory(stderr, "low water mark", wat_w);
+
+#endif
+
+ u3to(u3_road, u3R->par_p)->pro.nox_d += u3R->pro.nox_d;
+ u3to(u3_road, u3R->par_p)->pro.cel_d += u3R->pro.cel_d;
+
+ /* The new cap is the old hat - it's as simple as that.
+ */
+ u3to(u3_road, u3R->par_p)->cap_p = u3R->hat_p;
+
+ /* And, we're back home.
+ */
+ u3R = u3to(u3_road, u3R->par_p);
+ u3R->kid_p = 0;
+}
+
+/* u3m_hate(): new, integrated leap mechanism (enter).
+*/
+void
+u3m_hate(c3_w pad_w)
+{
+ u3_assert(0 == u3R->ear_p);
+
+ u3R->ear_p = u3R->cap_p;
+ u3m_leap(pad_w);
+
+ u3R->bug.mer = u3i_string(
+ "emergency buffer with sufficient space to cons the trace and bail"
+ );
+}
+
+/* u3m_love(): return product from leap.
+*/
+u3_noun
+u3m_love(u3_noun pro)
+{
+ // save cache pointers from current road
+ //
+ u3p(u3h_root) byc_p = u3R->byc.har_p;
+ u3a_jets jed_u = u3R->jed;
+ u3p(u3h_root) per_p = u3R->cax.per_p;
+
+ // fallback to parent road (child heap on parent's stack)
+ //
+ u3m_fall();
+
+ // copy product and caches off our stack
+ //
+ pro = u3a_take(pro);
+ jed_u = u3j_take(jed_u);
+ byc_p = u3n_take(byc_p);
+ per_p = u3h_take(per_p);
+
+ // pop the stack
+ //
+ u3a_drop_heap(u3R->cap_p, u3R->ear_p);
+ u3R->cap_p = u3R->ear_p;
+ u3R->ear_p = 0;
+
+ // integrate junior caches
+ //
+ u3j_reap(jed_u);
+ u3n_reap(byc_p);
+ u3z_reap(u3z_memo_keep, per_p);
+
+ return pro;
+}
+
+/* u3m_golf(): record cap_p length for u3m_flog().
+*/
+c3_w
+u3m_golf(void)
+{
+ if ( c3y == u3a_is_north(u3R) ) {
+ return u3R->mat_p - u3R->cap_p;
+ }
+ else {
+ return u3R->cap_p - u3R->mat_p;
+ }
+}
+
+/* u3m_flog(): reset cap_p.
+*/
+void
+u3m_flog(c3_w gof_w)
+{
+ // Enable memsets in case of memory corruption.
+ //
+ if ( c3y == u3a_is_north(u3R) ) {
+ u3_post bot_p = (u3R->mat_p - gof_w);
+ // c3_w len_w = (bot_w - u3R->cap_w);
+
+ // memset(u3R->cap_w, 0, 4 * len_w);
+ u3R->cap_p = bot_p;
+ }
+ else {
+ u3_post bot_p = u3R->mat_p + gof_w;
+ // c3_w len_w = (u3R->cap_w - bot_w);
+
+ // memset(bot_w, 0, 4 * len_w); //
+ u3R->cap_p = bot_p;
+ }
+}
+
+/* u3m_water(): produce watermarks.
+*/
+void
+u3m_water(u3_post* low_p, u3_post* hig_p)
+{
+ // allow the segfault handler to fire before the road is set
+ //
+ // while not explicitly possible in the codebase,
+ // compiler optimizations can reorder stores
+ //
+ if ( !u3R ) {
+ *low_p = 0;
+ *hig_p = u3C.wor_i - 1;
+ }
+ // in a north road, hat points to the end of the heap + 1 word,
+ // while cap points to the top of the stack
+ //
+ else if ( c3y == u3a_is_north(u3R) ) {
+ *low_p = u3R->hat_p - 1;
+ *hig_p = u3R->cap_p;
+ }
+ // in a south road, hat points to the end of the heap,
+ // while cap points to the top of the stack + 1 word
+ //
+ else {
+ *low_p = u3R->cap_p - 1;
+ *hig_p = u3R->hat_p;
+ }
+}
+
+/* u3m_soft_top(): top-level safety wrapper.
+*/
+u3_noun
+u3m_soft_top(c3_w mil_w, // timer ms
+ c3_w pad_w, // base memory pad
+ u3_funk fun_f,
+ u3_noun arg)
+{
+ u3_noun why, pro;
+ volatile c3_l sig_l = 0;
+
+ /* Enter internal signal regime.
+ */
+ _cm_signal_deep(mil_w);
+
+ if ( 0 != (sig_l = rsignal_setjmp(u3_Signal)) ) {
+ // reinitialize trace state
+ //
+ u3t_init();
+
+ // return to blank state
+ //
+ _cm_signal_done();
+
+ // recover memory state from the top down
+ //
+ return _cm_signal_recover(sig_l, arg);
+ }
+
+ /* Record the cap, and leap.
+ */
+ u3m_hate(pad_w);
+
+ /* Trap for ordinary nock exceptions.
+ */
+ if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) {
+ pro = fun_f(arg);
+
+ /* Make sure the inner routine did not create garbage.
+ */
+ if ( u3C.wag_w & u3o_debug_ram ) {
+#ifdef U3_CPU_DEBUG
+ if ( u3R->all.max_w > 1000000 ) {
+ u3a_print_memory(stderr, "execute: top", u3R->all.max_w);
+ }
+#endif
+ u3m_grab(pro, u3_none);
+ }
+
+ /* Revert to external signal regime.
+ */
+ _cm_signal_done();
+
+ /* Produce success, on the old road.
+ */
+ pro = u3nc(0, u3m_love(pro));
+ }
+ else {
+ /* Overload the error result.
+ */
+ pro = u3m_love(why);
+ }
+
+ /* Revert to external signal regime.
+ */
+ _cm_signal_done();
+
+ /* Free the argument.
+ */
+ u3z(arg);
+
+ /* Return the product.
+ */
+ return pro;
+}
+
+/* u3m_soft_sure(): top-level call assumed correct.
+*/
+u3_noun
+u3m_soft_sure(u3_funk fun_f, u3_noun arg)
+{
+ u3_noun pro, pru = u3m_soft_top(0, (1 << 18), fun_f, arg);
+
+ u3_assert(_(u3du(pru)));
+ pro = u3k(u3t(pru));
+ u3z(pru);
+
+ return pro;
+}
+
+/* u3m_soft_slam: top-level call.
+*/
+u3_noun _cm_slam(u3_noun arg) { return u3n_slam_on(u3h(arg), u3t(arg)); }
+u3_noun
+u3m_soft_slam(u3_noun gat, u3_noun sam)
+{
+ return u3m_soft_sure(_cm_slam, u3nc(gat, sam));
+}
+
+/* u3m_soft_nock: top-level nock.
+*/
+u3_noun _cm_nock(u3_noun arg) { return u3n_nock_on(u3h(arg), u3t(arg)); }
+u3_noun
+u3m_soft_nock(u3_noun bus, u3_noun fol)
+{
+ return u3m_soft_sure(_cm_nock, u3nc(bus, fol));
+}
+
+static void
+_hamt_map(u3_noun kev, void* cax_p)
+{
+ u3_noun* old = cax_p;
+ u3_noun key, val, new;
+ u3x_cell(kev, &key, &val);
+ new = u3qdb_put(*old, u3t(key), val);
+ u3z(*old);
+ *old = new;
+}
+
+/* u3m_soft_cax(): descend into virtualization context, with cache.
+*/
+u3_noun
+u3m_soft_cax(u3_funq fun_f,
+ u3_noun aga,
+ u3_noun agb)
+{
+ u3_noun why = 0, pro;
+ u3_noun cax = u3_nul;
+
+ /* Save and set memo cache harvesting flag.
+ */
+ c3_w wag_w = u3C.wag_w;
+ u3C.wag_w |= u3o_cash;
+
+ /* Record the cap, and leap.
+ */
+ u3m_hate(1 << 18);
+
+ /* Configure the new road.
+ */
+ {
+ u3R->ski.gul = u3_nul;
+ u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don;
+ u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace;
+ u3R->bug.tax = 0;
+ }
+ u3t_on(coy_o);
+
+ /* Trap for exceptions.
+ */
+ if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) {
+ u3t_off(coy_o);
+ pro = fun_f(aga, agb);
+ u3C.wag_w = wag_w;
+
+#ifdef U3_CPU_DEBUG
+ if ( u3R->all.max_w > 1000000 ) {
+ u3a_print_memory(stderr, "execute: run", u3R->all.max_w);
+ }
+#endif
+
+ /* Today you can't run -g without memory debug, but you should be
+ * able to.
+ */
+#ifdef U3_MEMORY_DEBUG
+ if ( u3C.wag_w & u3o_debug_ram ) {
+ u3m_grab(pro, u3_none);
+ }
+#endif
+
+ /* Produce success, on the old road.
+ */
+ u3h_walk_with(u3R->cax.per_p, _hamt_map, &cax);
+ pro = u3nc(u3nc(0, pro), cax);
+ pro = u3m_love(pro);
+ }
+ else {
+ u3t_init();
+ u3C.wag_w = wag_w;
+
+ /* Produce - or fall again.
+ */
+ {
+ u3_assert(_(u3du(why)));
+ switch ( u3h(why) ) {
+ default: u3_assert(0); return 0;
+
+ case 1: { // blocking request
+ pro = u3nc(u3nc(2, u3m_love(u3R->bug.tax)), u3_nul);
+ } break;
+
+ case 2: { // true exit
+ pro = u3nc(u3m_love(why), u3_nul);
+ } break;
+
+ case 3: { // failure; rebail w/trace
+ u3_noun yod = u3m_love(u3t(why));
+
+ u3m_bail
+ (u3nt(3,
+ u3a_take(u3h(yod)),
+ u3kb_weld(u3t(yod), u3k(u3R->bug.tax))));
+ } break;
+ }
+ }
+ }
+ /* Release the arguments.
+ */
+ {
+ u3z(aga);
+ u3z(agb);
+ }
+
+ /* Return the product.
+ */
+ return pro;
+}
+
+/* u3m_soft_run(): descend into virtualization context.
+*/
+u3_noun
+u3m_soft_run(u3_noun gul,
+ u3_funq fun_f,
+ u3_noun aga,
+ u3_noun agb)
+{
+ u3_noun why = 0, pro;
+
+ /* Record the cap, and leap.
+ */
+ u3m_hate(1 << 18);
+
+ /* Configure the new road.
+ */
+
+ {
+ // XX review
+ if ( (u3_nul == gul) || (u3C.wag_w & u3o_cash) ) {
+ u3R->ski.gul = u3_nul;
+ }
+ else {
+ u3R->ski.gul = u3nc(gul, u3to(u3_road, u3R->par_p)->ski.gul);
+ }
+ u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don;
+ u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace;
+ u3R->bug.tax = 0;
+ }
+ u3t_on(coy_o);
+
+ /* Trap for exceptions.
+ */
+ if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) {
+ u3t_off(coy_o);
+ pro = fun_f(aga, agb);
+
+#ifdef U3_CPU_DEBUG
+ if ( u3R->all.max_w > 1000000 ) {
+ u3a_print_memory(stderr, "execute: run", u3R->all.max_w);
+ }
+#endif
+
+ /* Today you can't run -g without memory debug, but you should be
+ * able to.
+ */
+#ifdef U3_MEMORY_DEBUG
+ if ( u3C.wag_w & u3o_debug_ram ) {
+ u3m_grab(pro, u3_none);
+ }
+#endif
+
+ /* Produce success, on the old road.
+ */
+ pro = u3nc(0, u3m_love(pro));
+ }
+ else {
+ u3t_init();
+
+ /* Produce - or fall again.
+ */
+ {
+ u3_assert(_(u3du(why)));
+ switch ( u3h(why) ) {
+ default: u3_assert(0); return 0;
+
+ case 0: { // unusual: bail with success.
+ pro = u3m_love(why);
+ } break;
+
+ case 1: { // blocking request
+ pro = u3m_love(why);
+ } break;
+
+ case 2: { // true exit
+ pro = u3m_love(why);
+ } break;
+
+ case 3: { // failure; rebail w/trace
+ u3_noun yod = u3m_love(u3t(why));
+
+ u3m_bail
+ (u3nt(3,
+ u3a_take(u3h(yod)),
+ u3kb_weld(u3t(yod), u3k(u3R->bug.tax))));
+ } break;
+
+ case 4: { // meta-bail
+ u3m_bail(u3m_love(u3t(why)));
+ } break;
+ }
+ }
+ }
+
+ /* Release the arguments.
+ */
+ {
+ u3z(gul);
+ u3z(aga);
+ u3z(agb);
+ }
+
+ /* Return the product.
+ */
+ return pro;
+}
+
+/* u3m_soft_esc(): namespace lookup. Produces direct result.
+*/
+u3_noun
+u3m_soft_esc(u3_noun ref, u3_noun sam)
+{
+ u3_noun why, gul, pro;
+
+ /* Assert preconditions.
+ */
+ {
+ gul = u3h(u3R->ski.gul);
+ }
+
+ /* Record the cap, and leap.
+ */
+ u3m_hate(1 << 18);
+
+ /* Configure the new road.
+ */
+ {
+ u3R->ski.gul = u3t(u3to(u3_road, u3R->par_p)->ski.gul);
+ u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don;
+ u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace;
+ u3R->bug.tax = 0;
+ }
+
+ /* Trap for exceptions.
+ */
+ if ( 0 == (why = (u3_noun)setjmp(u3R->esc.buf)) ) {
+ pro = u3n_slam_on(gul, u3nc(ref, sam));
+
+ /* Fall back to the old road, leaving temporary memory intact.
+ */
+ pro = u3m_love(pro);
+ }
+ else {
+ u3t_init();
+
+ /* Push the error back up to the calling context - not the run we
+ ** are in, but the caller of the run, matching pure nock semantics.
+ */
+ u3m_bail(u3nc(4, u3m_love(why)));
+ }
+
+ /* Release the sample. Note that we used it above, but in a junior
+ ** road, so its refcount is intact.
+ */
+ u3z(ref);
+ u3z(sam);
+
+ /* Return the product.
+ */
+ return pro;
+}
+
+/* u3m_grab(): garbage-collect the world, plus extra roots.
+*/
+void
+u3m_grab(u3_noun som, ...) // terminate with u3_none
+{
+ // u3h_free(u3R->cax.har_p);
+ // u3R->cax.har_p = u3h_new();
+
+ u3a_mark_init();
+ {
+ va_list vap;
+ u3_noun tur;
+
+ va_start(vap, som);
+
+ if ( som != u3_none ) {
+ u3a_mark_noun(som);
+
+ while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
+ u3a_mark_noun(tur);
+ }
+ }
+ va_end(vap);
+ }
+ u3m_mark(); // XX leaks
+ u3a_sweep();
+}
+
+/* u3m_soft(): top-level wrapper.
+**
+** Produces [0 product] or [%error (list tank)], top last.
+*/
+u3_noun
+u3m_soft(c3_w mil_w,
+ u3_funk fun_f,
+ u3_noun arg)
+{
+ u3_noun why;
+
+ why = u3m_soft_top(mil_w, (1 << 20), fun_f, arg); // 4M pad
+
+ if ( 0 == u3h(why) ) {
+ return why;
+ }
+ else {
+ u3_noun tax, cod, pro;
+
+ switch ( u3h(why) ) {
+ case 2: {
+ cod = c3__exit;
+ tax = u3t(why);
+ } break;
+
+ case 3: {
+ cod = u3h(u3t(why));
+ tax = u3t(u3t(why));
+ } break;
+
+ // don't use .^ at the top level!
+ //
+ default: {
+ u3m_p("invalid mot", u3h(why));
+ u3_assert(0);
+ }
+ }
+
+ // don't call +mook if we have no kernel
+ //
+ // This is required to soft the boot sequence.
+ //
+ if ( 0 == u3A->roc ) {
+ while ( u3_nul != tax ) {
+ u3_noun dat, mot, val;
+ u3x_cell(tax, &dat, &tax);
+
+ if ( c3y == u3r_cell(dat, &mot, &val) ) {
+ if ( c3__spot == mot ) {
+ u3m_p("tax", val);
+ }
+ else if ( (c3__mean == mot)
+ && (c3y == u3a_is_atom(val)) )
+ {
+ u3m_p("men", val);
+ }
+ else {
+ u3m_p("mot", mot);
+ }
+ }
+ }
+
+ pro = u3nc(u3k(cod), u3_nul);
+ }
+ // %evil leaves no trace
+ //
+ else if ( c3__evil == cod ) {
+ pro = u3nc(u3k(cod), u3_nul);
+ }
+ else {
+ u3_noun mok = u3dc("mook", 2, u3k(tax));
+ pro = u3nc(u3k(cod), u3k(u3t(mok)));
+ u3z(mok);
+ }
+
+ u3z(why);
+ return pro;
+ }
+}
+
+/* _cm_is_tas(): yes iff som (RETAIN) is @tas.
+*/
+static c3_o
+_cm_is_tas(u3_atom som, c3_w len_w)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_c c_c = u3r_byte(i_w, som);
+
+ if ( islower(c_c) ||
+ (isdigit(c_c) && (0 != i_w) && ((len_w - 1) != i_w))
+ || '-' == c_c )
+ {
+ continue;
+ }
+ return c3n;
+ }
+ return c3y;
+}
+
+/* _cm_is_ta(): yes iff som (RETAIN) is @ta.
+*/
+static c3_o
+_cm_is_ta(u3_noun som, c3_w len_w)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_c c_c = u3r_byte(i_w, som);
+
+ if ( (c_c < 32) || (c_c > 127) ) {
+ return c3n;
+ }
+ }
+ return c3y;
+}
+
+/* _cm_hex(): hex byte.
+*/
+c3_y _cm_hex(c3_y c_y)
+{
+ if ( c_y < 10 )
+ return '0' + c_y;
+ else return 'a' + (c_y - 10);
+}
+
+/* _cm_in_pretty: measure/cut prettyprint.
+*/
+static c3_w
+_cm_in_pretty(u3_noun som, c3_o sel_o, c3_c* str_c)
+{
+ if ( _(u3du(som)) ) {
+ c3_w sel_w, one_w, two_w;
+
+ sel_w = 0;
+ if ( _(sel_o) ) {
+ if ( str_c ) { *(str_c++) = '['; }
+ sel_w += 1;
+ }
+
+ one_w = _cm_in_pretty(u3h(som), c3y, str_c);
+ if ( str_c ) {
+ str_c += one_w;
+ *(str_c++) = ' ';
+ }
+ two_w = _cm_in_pretty(u3t(som), c3n, str_c);
+ if ( str_c ) { str_c += two_w; }
+
+ if ( _(sel_o) ) {
+ if ( str_c ) { *(str_c++) = ']'; }
+ sel_w += 1;
+ }
+ return one_w + two_w + 1 + sel_w;
+ }
+ else {
+ if ( som < 65536 ) {
+ c3_c buf_c[6];
+ c3_w len_w;
+
+ snprintf(buf_c, 6, "%d", som);
+ len_w = strlen(buf_c);
+
+ if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; }
+ return len_w;
+ }
+ else {
+ c3_w len_w = u3r_met(3, som);
+
+ if ( _(_cm_is_tas(som, len_w)) ) {
+ if ( str_c ) {
+ *(str_c++) = '%';
+ u3r_bytes(0, len_w, (c3_y *)str_c, som);
+ str_c += len_w;
+ }
+ return len_w + 1;
+ }
+ else if ( _(_cm_is_ta(som, len_w)) ) {
+ if ( str_c ) {
+ *(str_c++) = '\'';
+ u3r_bytes(0, len_w, (c3_y *)str_c, som);
+ str_c += len_w;
+ *(str_c++) = '\'';
+ }
+ return len_w + 2;
+ }
+ else {
+ c3_c *buf_c = c3_malloc(2 + (2 * len_w) + 1);
+ c3_w i_w = 0;
+ c3_w a_w = 0;
+
+ buf_c[a_w++] = '0';
+ buf_c[a_w++] = 'x';
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_y c_y = u3r_byte(len_w - (i_w + 1), som);
+
+ if ( (i_w == 0) && (c_y <= 0xf) ) {
+ buf_c[a_w++] = _cm_hex(c_y);
+ } else {
+ buf_c[a_w++] = _cm_hex(c_y >> 4);
+ buf_c[a_w++] = _cm_hex(c_y & 0xf);
+ }
+ }
+ buf_c[a_w] = 0;
+ len_w = a_w;
+
+ if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; }
+
+ c3_free(buf_c);
+ return len_w;
+ }
+ }
+ }
+}
+
+/* u3m_pretty(): dumb prettyprint to string.
+*/
+c3_c*
+u3m_pretty(u3_noun som)
+{
+ c3_w len_w = _cm_in_pretty(som, c3y, 0);
+ c3_c* pre_c = c3_malloc(len_w + 1);
+
+ _cm_in_pretty(som, c3y, pre_c);
+ pre_c[len_w] = 0;
+ return pre_c;
+}
+
+/* _cm_in_pretty_path: measure/cut prettyprint.
+ *
+ * Modeled after _cm_in_pretty(), the backend to u3m_p(), but with the
+ * assumption that we're always displaying a path.
+ */
+static c3_w
+_cm_in_pretty_path(u3_noun som, c3_c* str_c)
+{
+ if ( _(u3du(som)) ) {
+ c3_w sel_w, one_w, two_w;
+ if ( str_c ) {
+ *(str_c++) = '/';
+ }
+ sel_w = 1;
+
+ one_w = _cm_in_pretty_path(u3h(som), str_c);
+ if ( str_c ) {
+ str_c += one_w;
+ }
+
+ two_w = _cm_in_pretty_path(u3t(som), str_c);
+ if ( str_c ) {
+ str_c += two_w;
+ }
+
+ return sel_w + one_w + two_w;
+ }
+ else {
+ c3_w len_w = u3r_met(3, som);
+ if ( str_c && len_w ) {
+ u3r_bytes(0, len_w, (c3_y *)str_c, som);
+ str_c += len_w;
+ }
+ return len_w;
+ }
+}
+
+/* u3m_pretty_path(): prettyprint a path to string.
+*/
+c3_c*
+u3m_pretty_path(u3_noun som)
+{
+ c3_w len_w = _cm_in_pretty_path(som, NULL);
+ c3_c* pre_c = c3_malloc(len_w + 1);
+
+ _cm_in_pretty_path(som, pre_c);
+ pre_c[len_w] = 0;
+ return pre_c;
+}
+
+/* u3m_p(): dumb print with caption.
+*/
+void
+u3m_p(const c3_c* cap_c, u3_noun som)
+{
+ c3_c* pre_c = u3m_pretty(som);
+
+ u3l_log("%s: %s", cap_c, pre_c);
+ c3_free(pre_c);
+}
+
+/* u3m_tape(): dump a tape to stdout.
+*/
+void
+u3m_tape(u3_noun tep)
+{
+ u3_noun tap = tep;
+
+ while ( u3_nul != tap ) {
+ c3_c car_c;
+
+ if ( u3h(tap) >= 127 ) {
+ car_c = '?';
+ } else car_c = u3h(tap);
+
+ putc(car_c, stdout);
+ tap = u3t(tap);
+ }
+ u3z(tep);
+}
+
+/* u3m_wall(): dump a wall to stdout.
+*/
+void
+u3m_wall(u3_noun wol)
+{
+ u3_noun wal = wol;
+
+ while ( u3_nul != wal ) {
+ u3m_tape(u3k(u3h(wal)));
+
+ putc(13, stdout);
+ putc(10, stdout);
+
+ wal = u3t(wal);
+ }
+ u3z(wol);
+}
+
+/* _cm_limits(): set up global modes and limits.
+*/
+static void
+_cm_limits(void)
+{
+#ifndef U3_OS_windows
+ struct rlimit rlm;
+
+ // Moar stack.
+ //
+ {
+ u3_assert( 0 == getrlimit(RLIMIT_STACK, &rlm) );
+
+ rlm.rlim_cur = c3_min(rlm.rlim_max, (65536 << 10));
+
+ if ( 0 != setrlimit(RLIMIT_STACK, &rlm) ) {
+ u3l_log("boot: stack size: %s", strerror(errno));
+ exit(1);
+ }
+ }
+
+ // Moar filez.
+ //
+ {
+ getrlimit(RLIMIT_NOFILE, &rlm);
+
+ #ifdef U3_OS_osx
+ rlm.rlim_cur = c3_min(OPEN_MAX, rlm.rlim_max);
+ #else
+ rlm.rlim_cur = rlm.rlim_max;
+ #endif
+
+ // no exit, not a critical limit
+ //
+ if ( 0 != setrlimit(RLIMIT_NOFILE, &rlm) ) {
+ u3l_log("boot: open file limit: %s", strerror(errno));
+ }
+ }
+
+ // Moar core.
+ //
+# ifndef ASAN_ENABLED
+ {
+ getrlimit(RLIMIT_CORE, &rlm);
+ rlm.rlim_cur = RLIM_INFINITY;
+
+ // no exit, not a critical limit
+ //
+ if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) {
+ u3l_log("boot: core limit: %s", strerror(errno));
+ }
+ }
+# endif
+#endif
+}
+
+/* u3m_fault(): handle a memory event with libsigsegv protocol.
+ */
+c3_i
+u3m_fault(void* adr_v, c3_i ser_i)
+{
+ c3_w* adr_w = (c3_w*)adr_v;
+ u3_post low_p, hig_p;
+
+ // let the stack overflow handler run.
+ //
+ if ( 0 == ser_i ) {
+ return 0;
+ }
+ // this could be avoided by registering the loom bounds in libsigsegv
+ //
+ else if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3C.wor_i)) ) {
+ fprintf(stderr, "loom: external fault: %p (%p : %p)\r\n\r\n",
+ (void *)adr_w, (void *)u3_Loom, (void *)(u3_Loom + u3C.wor_i));
+ u3m_stacktrace();
+ u3_assert(0);
+ return 0;
+ }
+
+ u3m_water(&low_p, &hig_p);
+
+ switch ( u3e_fault(low_p, hig_p, u3a_outa(adr_w)) ) {
+ // page tracking invariants violated, fatal
+ //
+ case u3e_flaw_sham: {
+ u3_assert(0);
+ return 0;
+ }
+
+ // virtual memory failure (protections)
+ //
+ // XX s/b recoverable, need to u3m_signal() a new mote
+ //
+ case u3e_flaw_base: {
+ u3_assert(0);
+ return 0;
+ }
+
+ // loom limits exceeded, recoverable
+ //
+ case u3e_flaw_meme: {
+ u3m_signal(c3__meme); // doesn't return
+ return 1;
+ }
+
+ case u3e_flaw_good: return 1;
+ }
+
+ u3_assert(!"unpossible");
+}
+
+/* u3m_foul(): dirty all pages and disable tracking.
+*/
+void
+u3m_foul(void)
+{
+ if ( c3n == u3e_yolo() ) {
+ return;
+ }
+
+ u3e_foul();
+}
+
+/* u3m_save(): update the checkpoint.
+*/
+void
+u3m_save(void)
+{
+ u3_post low_p, hig_p;
+ u3m_water(&low_p, &hig_p);
+
+ u3a_wait();
+
+ u3_assert(u3R == &u3H->rod_u);
+
+ u3e_save(low_p, hig_p);
+
+ u3a_dash();
+}
+
+/* u3m_toss(): discard ephemeral memory.
+*/
+void
+u3m_toss(void)
+{
+ u3_post low_p, hig_p;
+ u3m_water(&low_p, &hig_p);
+
+ if ( ((low_p + u3C.tos_w) < u3C.wor_i)
+ && (hig_p > u3C.tos_w) )
+ {
+ low_p += u3C.tos_w;
+ hig_p -= u3C.tos_w;
+
+ if ( low_p < hig_p ) {
+ u3e_toss(low_p, hig_p);
+ }
+ }
+}
+
+/* u3m_ward(): tend the guardpage.
+*/
+void
+u3m_ward(void)
+{
+ u3_post low_p, hig_p;
+ u3m_water(&low_p, &hig_p);
+
+#if 1 // XX redundant
+ {
+ c3_w low_w, hig_w;
+
+ if ( c3y == u3a_is_north(u3R) ) {
+ low_w = u3R->hat_p;
+ hig_w = u3R->cap_p;
+ }
+ else {
+ low_w = u3R->cap_p;
+ hig_w = u3R->hat_p;
+ }
+
+ if ( (low_w > (u3P.gar_w << u3a_page))
+ || (hig_w < (u3P.gar_w << u3a_page)) )
+ {
+ u3_assert( ((low_p >> u3a_page) >= u3P.gar_w)
+ || ((hig_p >> u3a_page) <= u3P.gar_w) );
+ }
+ }
+#endif
+
+ u3e_ward(low_p, hig_p);
+}
+
+/* _cm_signals(): set up interrupts, etc.
+*/
+static void
+_cm_signals(void)
+{
+#ifndef U3_OS_windows
+ if ( 0 != sigsegv_install_handler(u3m_fault) ) {
+ u3l_log("boot: sigsegv install failed");
+ exit(1);
+ }
+
+# if defined(U3_OS_PROF)
+ // Block SIGPROF, so that if/when we reactivate it on the
+ // main thread for profiling, we won't get hits in parallel
+ // on other threads.
+ if ( u3C.wag_w & u3o_debug_cpu ) {
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGPROF);
+
+ if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) {
+ u3l_log("boot: thread mask SIGPROF: %s", strerror(errno));
+ exit(1);
+ }
+ }
+#endif
+#else
+ if (0 == AddVectoredExceptionHandler(1, _windows_exception_filter)) {
+ u3l_log("boot: vectored exception handler install failed");
+ exit(1);
+ }
+#endif
+}
+
+/* _cm_malloc_ssl(): openssl-shaped malloc
+*/
+static void*
+_cm_malloc_ssl(size_t len_i
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ , const char* file, int line
+#endif
+ )
+{
+ return u3a_malloc(len_i);
+}
+
+/* _cm_realloc_ssl(): openssl-shaped realloc.
+*/
+static void*
+_cm_realloc_ssl(void* lag_v, size_t len_i
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ , const char* file, int line
+#endif
+ )
+{
+ return u3a_realloc(lag_v, len_i);
+}
+
+/* _cm_free_ssl(): openssl-shaped free.
+*/
+static void
+_cm_free_ssl(void* tox_v
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ , const char* file, int line
+#endif
+ )
+{
+ u3a_free(tox_v);
+}
+
+extern void u3je_secp_init(void);
+
+/* _cm_crypto(): initialize openssl and crypto jets.
+*/
+static void
+_cm_crypto(void)
+{
+ /* Initialize OpenSSL with loom allocation functions. */
+ if ( 0 == CRYPTO_set_mem_functions(&_cm_malloc_ssl,
+ &_cm_realloc_ssl,
+ &_cm_free_ssl) ) {
+ u3l_log("%s", "openssl initialization failed");
+ abort();
+ }
+
+ u3je_secp_init();
+}
+
+/* _cm_realloc2(): gmp-shaped realloc.
+*/
+static void*
+_cm_realloc2(void* lag_v, size_t old_i, size_t new_i)
+{
+ return u3a_realloc(lag_v, new_i);
+}
+
+/* _cm_free2(): gmp-shaped free.
+*/
+static void
+_cm_free2(void* tox_v, size_t siz_i)
+{
+ u3a_free(tox_v);
+}
+
+/* u3m_init(): start the environment.
+*/
+void
+u3m_init(size_t len_i)
+{
+ _cm_limits();
+ _cm_signals();
+ _cm_crypto();
+
+ u3a_init_once();
+
+ // make sure GMP uses our malloc.
+ //
+ mp_set_memory_functions(u3a_malloc, _cm_realloc2, _cm_free2);
+
+ // make sure that [len_i] is a fully-addressible non-zero power of two.
+ //
+ if ( !len_i
+ || (len_i & (len_i - 1))
+ || (len_i < (1 << (u3a_page + 2)))
+ || (len_i > u3a_bytes) )
+ {
+ u3l_log("loom: bad size: %zu", len_i);
+ exit(1);
+ }
+
+ // map at fixed address.
+ //
+ {
+ void* map_v = mmap((void *)u3_Loom,
+ len_i,
+ (PROT_READ | PROT_WRITE),
+ (MAP_ANON | MAP_FIXED | MAP_PRIVATE),
+ -1, 0);
+
+ if ( -1 == (c3_ps)map_v ) {
+ map_v = mmap((void *)0,
+ len_i,
+ (PROT_READ | PROT_WRITE),
+ (MAP_ANON | MAP_PRIVATE),
+ -1, 0);
+
+ u3l_log("boot: mapping %zuMB failed", len_i >> 20);
+ u3l_log("see https://docs.urbit.org/user-manual/running/cloud-hosting"
+ " for adding swap space");
+ if ( -1 != (c3_ps)map_v ) {
+ u3l_log("if porting to a new platform, try U3_OS_LoomBase %p",
+ map_v);
+ }
+ exit(1);
+ }
+
+ u3C.wor_i = len_i >> 2;
+ u3l_log("loom: mapped %zuMB", len_i >> 20);
+ }
+}
+
+extern void u3je_secp_stop(void);
+
+/* u3m_stop(): graceful shutdown cleanup.
+*/
+void
+u3m_stop(void)
+{
+ u3t_sstack_exit();
+
+ u3e_stop();
+ u3je_secp_stop();
+}
+
+/* u3m_pier(): make a pier.
+*/
+c3_c*
+u3m_pier(c3_c* dir_c)
+{
+ c3_c ful_c[8193];
+
+ u3C.dir_c = dir_c;
+
+ snprintf(ful_c, 8192, "%s", dir_c);
+ if ( c3_mkdir(ful_c, 0700) ) {
+ if ( EEXIST != errno ) {
+ fprintf(stderr, "loom: pier create: %s\r\n", strerror(errno));
+ exit(1);
+ }
+ }
+
+ snprintf(ful_c, 8192, "%s/.urb", dir_c);
+ if ( c3_mkdir(ful_c, 0700) ) {
+ if ( EEXIST != errno ) {
+ fprintf(stderr, "loom: .urb create: %s\r\n", strerror(errno));
+ exit(1);
+ }
+ }
+
+ snprintf(ful_c, 8192, "%s/.urb/chk", dir_c);
+ if ( c3_mkdir(ful_c, 0700) ) {
+ if ( EEXIST != errno ) {
+ fprintf(stderr, "loom: .urb/chk create: %s\r\n", strerror(errno));
+ exit(1);
+ }
+ }
+
+ return strdup(dir_c);
+}
+
+/* u3m_boot(): start the u3 system. return next event, starting from 1.
+*/
+c3_d
+u3m_boot(c3_c* dir_c, size_t len_i)
+{
+ c3_o nuu_o;
+
+ u3C.dir_c = dir_c;
+
+ /* Activate the loom.
+ */
+ u3m_init(len_i);
+
+ /* Activate the storage system.
+ */
+ nuu_o = u3e_live(c3n, u3m_pier(dir_c));
+
+ /* Activate tracing.
+ */
+ u3C.slog_f = 0;
+ u3C.sign_hold_f = 0;
+ u3C.sign_move_f = 0;
+ u3t_init();
+
+ /* Construct or activate the allocator.
+ */
+ u3m_pave(nuu_o);
+
+ /* GC immediately if requested
+ */
+ if ( (c3n == nuu_o) && (u3C.wag_w & u3o_check_corrupt) ) {
+ u3l_log("boot: gc requested");
+ u3m_grab(u3_none);
+ u3C.wag_w &= ~u3o_check_corrupt;
+ u3l_log("boot: gc complete");
+ }
+
+ /* Initialize the jet system.
+ */
+ {
+ c3_w len_w = u3j_boot(nuu_o);
+ u3l_log("boot: installed %d jets", len_w);
+ }
+
+ /* Reactivate jets on old kernel.
+ */
+ if ( c3n == nuu_o ) {
+ u3j_ream();
+ u3n_ream();
+ return u3A->eve_d;
+ }
+ else {
+ /* Basic initialization.
+ */
+ memset(u3A, 0, sizeof(*u3A));
+ return 0;
+ }
+}
+
+/* u3m_boot_lite(): start without checkpointing.
+*/
+c3_d
+u3m_boot_lite(size_t len_i)
+{
+ /* Activate the loom.
+ */
+ u3m_init(len_i);
+
+ /* Activate tracing.
+ */
+ u3C.slog_f = 0;
+ u3C.sign_hold_f = 0;
+ u3C.sign_move_f = 0;
+ u3t_init();
+
+ /* Construct or activate the allocator.
+ */
+ u3m_pave(c3y);
+
+ /* Place the guard page.
+ */
+ u3e_init();
+
+ /* Initialize the jet system.
+ */
+ u3j_boot(c3y);
+
+ /* Basic initialization.
+ */
+ memset(u3A, 0, sizeof(*u3A));
+ return 0;
+}
+
+/* u3m_reclaim: clear persistent caches to reclaim memory.
+*/
+void
+u3m_reclaim(void)
+{
+ u3v_reclaim();
+ u3j_reclaim();
+ u3n_reclaim();
+ u3a_reclaim();
+}
+
+/* _cm_pack_rewrite(): trace through arena, rewriting pointers.
+*/
+static void
+_cm_pack_rewrite(void)
+{
+ // XX fix u3a_rewrite* to support south roads
+ //
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ // NB: these implementations must be kept in sync with u3m_reclaim();
+ // anything not reclaimed must be rewritable
+ //
+ u3v_rewrite_compact();
+ u3j_rewrite_compact();
+ u3n_rewrite_compact();
+ u3a_rewrite_compact();
+}
+
+/* u3m_pack: compact (defragment) memory, returns u3a_open delta.
+*/
+c3_w
+u3m_pack(void)
+{
+ c3_w pre_w = u3a_open(u3R);
+
+ // reclaim first, to free space, and discard anything we can't/don't rewrite
+ //
+ u3m_reclaim();
+
+ // sweep the heap, finding and saving new locations
+ //
+ u3a_pack_seek(u3R);
+
+ // trace roots, rewriting inner pointers
+ //
+ _cm_pack_rewrite();
+
+ // sweep the heap, relocating objects to their new locations
+ //
+ u3a_pack_move(u3R);
+
+ return (u3a_open(u3R) - pre_w);
+}
diff --git a/vere/pkg/noun/manage.h b/vere/pkg/noun/manage.h
new file mode 100644
index 0000000..f0779e9
--- /dev/null
+++ b/vere/pkg/noun/manage.h
@@ -0,0 +1,215 @@
+/// @file
+
+#ifndef U3_MANAGE_H
+#define U3_MANAGE_H
+
+// #include "v1/manage.h"
+// #include "v2/manage.h"
+
+#include "c3/c3.h"
+#include "types.h"
+#include "version.h"
+
+ /** System management.
+ **/
+ /* u3m_boot(): start the u3 system. return next event, starting from 1.
+ */
+ c3_d
+ u3m_boot(c3_c* dir_c, size_t len_i);
+
+ /* u3m_pier(): make a pier.
+ */
+ c3_c*
+ u3m_pier(c3_c* dir_c);
+
+ /* u3m_boot_lite(): start without checkpointing.
+ */
+ c3_d
+ u3m_boot_lite(size_t len_i);
+
+ /* u3m_stop(): graceful shutdown cleanup. */
+ void
+ u3m_stop(void);
+
+ /* u3m_bail(): bail out. Does not return.
+ **
+ ** Bail motes:
+ **
+ ** %exit :: semantic failure
+ ** %evil :: bad crypto
+ ** %intr :: interrupt
+ ** %fail :: execution failure
+ ** %foul :: assert failure
+ ** %need :: network block
+ ** %meme :: out of memory
+ ** %time :: timed out
+ ** %oops :: assertion failure
+ */
+ c3_i
+ u3m_bail(c3_m how_m) __attribute__((noreturn));
+
+ /* u3m_fault(): handle a memory event with libsigsegv protocol.
+ */
+ c3_i
+ u3m_fault(void* adr_v, c3_i ser_i);
+
+ /* u3m_foul(): dirty all pages and disable tracking.
+ */
+ void
+ u3m_foul(void);
+
+ /* u3m_backup(): copy snapshot to .urb/bhk (if it doesn't exist yet).
+ */
+ c3_o
+ u3m_backup(c3_o);
+
+ /* u3m_save(): update the checkpoint.
+ */
+ void
+ u3m_save(void);
+
+ /* u3m_toss(): discard ephemeral memory.
+ */
+ void
+ u3m_toss(void);
+
+ /* u3m_ward(): tend the guardpage.
+ */
+ void
+ u3m_ward(void);
+
+ /* u3m_init(): start the environment.
+ */
+ void
+ u3m_init(size_t len_i);
+
+ /* u3m_pave(): instantiate or activate image.
+ */
+ void
+ u3m_pave(c3_o nuu_o);
+
+ /* u3m_signal(): treat a nock-level exception as a signal interrupt.
+ */
+ void
+ u3m_signal(u3_noun sig_l);
+
+ /* u3m_file(): load file, as atom, or bail.
+ */
+ u3_noun
+ u3m_file(c3_c* pas_c);
+
+ /* u3m_error(): bail out with %exit, ct_pushing error.
+ */
+ c3_i
+ u3m_error(c3_c* str_c);
+
+ /* u3m_hate(): new, integrated leap mechanism (enter).
+ */
+ void
+ u3m_hate(c3_w pad_w);
+
+ /* u3m_love(): return product from leap.
+ */
+ u3_noun
+ u3m_love(u3_noun pro);
+
+ /* u3m_soft(): system soft wrapper. unifies unix and nock errors.
+ **
+ ** Produces [%$ result] or [%error (list tank)].
+ */
+ u3_noun
+ u3m_soft(c3_w mil_w, u3_funk fun_f, u3_noun arg);
+
+ /* u3m_soft_cax(): descend into virtualization context, with cache.
+ */
+ u3_noun
+ u3m_soft_cax(u3_funq fun_f, u3_noun aga, u3_noun agb);
+
+ /* u3m_soft_slam: top-level call.
+ */
+ u3_noun
+ u3m_soft_slam(u3_noun gat, u3_noun sam);
+
+ /* u3m_soft_nock: top-level nock.
+ */
+ u3_noun
+ u3m_soft_nock(u3_noun bus, u3_noun fol);
+
+ /* u3m_soft_sure(): top-level call assumed correct.
+ */
+ u3_noun
+ u3m_soft_sure(u3_funk fun_f, u3_noun arg);
+
+ /* u3m_soft_run(): descend into virtualization context.
+ */
+ u3_noun
+ u3m_soft_run(u3_noun gul,
+ u3_funq fun_f,
+ u3_noun aga,
+ u3_noun agb);
+
+ /* u3m_soft_esc(): namespace lookup to (unit ,*).
+ */
+ u3_noun
+ u3m_soft_esc(u3_noun ref, u3_noun sam);
+
+
+ /* u3m_quac: memory report.
+ */
+ typedef struct _u3m_quac {
+ c3_c* nam_c;
+ c3_w siz_w;
+ struct _u3m_quac** qua_u;
+ } u3m_quac;
+
+ /* u3m_mark(): mark all nouns in the road.
+ */
+ u3m_quac**
+ u3m_mark();
+
+ /* u3m_grab(): garbage-collect the world, plus extra roots.
+ */
+ void
+ u3m_grab(u3_noun som, ...); // terminate with u3_none
+
+ /* u3m_water(): produce high and low watermarks. Asserts u3R == u3H.
+ */
+ void
+ u3m_water(u3_post* low_p, u3_post* hig_p);
+
+ /* u3m_pretty(): dumb prettyprint to string. RETAIN.
+ */
+ c3_c*
+ u3m_pretty(u3_noun som);
+
+ /* u3m_pretty_path(): prettyprint a path to string. RETAIN.
+ */
+ c3_c*
+ u3m_pretty_path(u3_noun som);
+
+ /* u3m_p(): dumb print with caption. RETAIN.
+ */
+ void
+ u3m_p(const c3_c* cap_c, u3_noun som);
+
+ /* u3m_tape(): dump a tape to stdout.
+ */
+ void
+ u3m_tape(u3_noun tep);
+
+ /* u3m_wall(): dump a wall to stdout.
+ */
+ void
+ u3m_wall(u3_noun wol);
+
+ /* u3m_reclaim: clear persistent caches to reclaim memory.
+ */
+ void
+ u3m_reclaim(void);
+
+ /* u3m_pack: compact (defragment) memory, returns u3a_open delta.
+ */
+ c3_w
+ u3m_pack(void);
+
+#endif /* ifndef U3_MANAGE_H */
diff --git a/vere/pkg/noun/nock.c b/vere/pkg/noun/nock.c
new file mode 100644
index 0000000..8218efa
--- /dev/null
+++ b/vere/pkg/noun/nock.c
@@ -0,0 +1,3268 @@
+/// @file
+
+#include "nock.h"
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "jets.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "manage.h"
+#include "options.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "vortex.h"
+#include "xtract.h"
+#include "zave.h"
+
+
+// define to have each opcode printed as it executes,
+// along with some other debugging info
+# undef VERBOSE_BYTECODE
+
+#if 0
+// Retained for debugging purposes.
+static u3_noun _n_nock_on(u3_noun bus, u3_noun fol);
+
+/* _n_hint(): process hint.
+*/
+static u3_noun
+_n_hint(u3_noun zep,
+ u3_noun hod,
+ u3_noun bus,
+ u3_noun nex)
+{
+ switch ( zep ) {
+ default: {
+ // u3m_p("weird zep", zep);
+ u3a_lose(zep);
+ u3a_lose(hod);
+
+ return _n_nock_on(bus, nex);
+ }
+
+ case c3__hunk:
+ case c3__lose:
+ case c3__mean:
+ case c3__spot: {
+ u3_noun tac = u3nc(zep, hod);
+ u3_noun pro;
+
+ u3t_push(tac);
+#if 0
+ {
+ static int low_i;
+
+ if ( !low_i ) {
+ low_i = 1;
+ if ( 0 == (u3R->pro.nox_d % 65536ULL) ) {
+ if ( c3__spot == zep ) {
+ u3l_log("spot %d/%d : %d/%d",
+ u3h(u3h(u3t(hod))),
+ u3t(u3h(u3t(hod))),
+ u3h(u3t(u3t(hod))),
+ u3t(u3t(u3t(hod))));
+ }
+ }
+ low_i = 0;
+ }
+ }
+#endif
+ pro = _n_nock_on(bus, nex);
+ u3t_drop();
+
+ return pro;
+ }
+
+ case c3__live: {
+ if ( c3y == u3ud(hod) ) {
+ u3t_off(noc_o);
+ u3t_heck(hod);
+ u3t_on(noc_o);
+ } else {
+ u3z(hod);
+ }
+ return _n_nock_on(bus, nex);
+ }
+
+ case c3__slog: {
+ if ( !(u3C.wag_w & u3o_quiet) ) {
+ u3t_off(noc_o);
+ u3t_slog(hod);
+ u3t_on(noc_o);
+ }
+ return _n_nock_on(bus, nex);
+ }
+
+ case c3__germ: {
+ u3_noun pro = _n_nock_on(bus, nex);
+
+ if ( c3y == u3r_sing(pro, hod) ) {
+ u3z(pro); return hod;
+ } else {
+ u3z(hod); return pro;
+ }
+ }
+
+ case c3__fast: {
+ u3_noun pro = _n_nock_on(bus, nex);
+
+ u3t_off(noc_o);
+ u3j_mine(hod, u3k(pro));
+ u3t_on(noc_o);
+
+ return pro;
+ }
+
+ case c3__memo: {
+ u3z(hod);
+#if 0
+ return _n_nock_on(bus, nex);
+#else
+ {
+ u3_noun pro = u3z_find_2(144 + c3__nock, bus, nex);
+
+ if ( pro != u3_none ) {
+ u3z(bus); u3z(nex);
+ return pro;
+ }
+ pro = _n_nock_on(u3k(bus), u3k(nex));
+
+ if ( &(u3H->rod_u) != u3R ) {
+ u3z_save_2(144 + c3__nock, bus, nex, pro);
+ }
+
+ u3z(bus); u3z(nex);
+
+ return pro;
+ }
+#endif
+ }
+
+ case c3__sole: {
+ u3z(hod);
+ {
+ u3_noun pro = _n_nock_on(bus, nex);
+
+ // return u3z_uniq(pro);
+ return pro;
+ }
+ }
+ }
+}
+
+/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
+*/
+static u3_noun
+_n_nock_on(u3_noun bus, u3_noun fol)
+{
+ u3_noun hib, gal;
+
+ while ( 1 ) {
+ hib = u3h(fol);
+ gal = u3t(fol);
+
+#ifdef U3_CPU_DEBUG
+ u3R->pro.nox_d += 1;
+#endif
+
+ if ( c3y == u3du(hib) ) {
+ u3_noun poz, riv;
+
+ poz = _n_nock_on(u3k(bus), u3k(hib));
+ riv = _n_nock_on(bus, u3k(gal));
+
+ u3a_lose(fol);
+ return u3i_cell(poz, riv);
+ }
+ else switch ( hib ) {
+ default: return u3m_bail(c3__exit);
+
+ case 0: {
+ if ( c3n == u3ud(gal) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun pro = u3k(u3at(gal, bus));
+
+ u3a_lose(bus); u3a_lose(fol);
+ return pro;
+ }
+ }
+ u3_assert(!"not reached");
+
+ case 1: {
+ u3_noun pro = u3k(gal);
+
+ u3a_lose(bus); u3a_lose(fol);
+ return pro;
+ }
+ u3_assert(!"not reached");
+
+ case 2: {
+ u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
+ u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
+
+ u3a_lose(fol);
+ bus = seb;
+ fol = nex;
+ continue;
+ }
+ u3_assert(!"not reached");
+
+ case 3: {
+ u3_noun gof, pro;
+
+ gof = _n_nock_on(bus, u3k(gal));
+ pro = u3du(gof);
+
+ u3a_lose(gof); u3a_lose(fol);
+ return pro;
+ }
+ u3_assert(!"not reached");
+
+ case 4: {
+ u3_noun gof, pro;
+
+ gof = _n_nock_on(bus, u3k(gal));
+ pro = u3i_vint(gof);
+
+ u3a_lose(fol);
+ return pro;
+ }
+ u3_assert(!"not reached");
+
+ case 5: {
+ u3_noun wim = _n_nock_on(bus, u3k(gal));
+ u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
+
+ u3a_lose(wim); u3a_lose(fol);
+ return pro;
+ }
+ u3_assert(!"not reached");
+
+ case 6: {
+ u3_noun b_gal, c_gal, d_gal;
+
+ u3x_trel(gal, &b_gal, &c_gal, &d_gal);
+ {
+ u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
+ u3_noun nex;
+
+ if ( 0 == tys ) {
+ nex = u3k(c_gal);
+ } else if ( 1 == tys ) {
+ nex = u3k(d_gal);
+ } else return u3m_bail(c3__exit);
+
+ u3a_lose(fol);
+ fol = nex;
+ continue;
+ }
+ }
+ u3_assert(!"not reached");
+
+ case 7: {
+ u3_noun b_gal, c_gal;
+
+ u3x_cell(gal, &b_gal, &c_gal);
+ {
+ u3_noun bod = _n_nock_on(bus, u3k(b_gal));
+ u3_noun nex = u3k(c_gal);
+
+ u3a_lose(fol);
+ bus = bod;
+ fol = nex;
+ continue;
+ }
+ }
+ u3_assert(!"not reached");
+
+ case 8: {
+ u3_noun b_gal, c_gal;
+
+ u3x_cell(gal, &b_gal, &c_gal);
+ {
+ u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
+ u3_noun bod = u3nc(heb, bus);
+ u3_noun nex = u3k(c_gal);
+
+ u3a_lose(fol);
+ bus = bod;
+ fol = nex;
+ continue;
+ }
+ }
+ u3_assert(!"not reached");
+
+ case 9: {
+ u3_noun b_gal, c_gal;
+
+ u3x_cell(gal, &b_gal, &c_gal);
+ {
+ u3_noun seb = _n_nock_on(bus, u3k(c_gal));
+ u3_noun pro;
+
+ u3t_off(noc_o);
+ pro = u3j_kick(seb, b_gal);
+ u3t_on(noc_o);
+
+ if ( u3_none != pro ) {
+ u3a_lose(fol);
+ return pro;
+ }
+ else {
+ if ( c3n == u3ud(b_gal) ) {
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun nex = u3k(u3at(b_gal, seb));
+
+ u3a_lose(fol);
+ bus = seb;
+ fol = nex;
+ continue;
+ }
+ }
+ }
+ }
+ u3_assert(!"not reached");
+
+ case 10: {
+ u3_noun p_gal, q_gal;
+
+ u3x_cell(gal, &p_gal, &q_gal);
+ {
+ u3_noun zep, hod, nex;
+
+ if ( c3y == u3du(p_gal) ) {
+ u3_noun b_gal = u3h(p_gal);
+ u3_noun c_gal = u3t(p_gal);
+ u3_noun d_gal = q_gal;
+
+ zep = u3k(b_gal);
+ hod = _n_nock_on(u3k(bus), u3k(c_gal));
+ nex = u3k(d_gal);
+ }
+ else {
+ u3_noun b_gal = p_gal;
+ u3_noun c_gal = q_gal;
+
+ zep = u3k(b_gal);
+ hod = u3_nul;
+ nex = u3k(c_gal);
+ }
+
+ u3a_lose(fol);
+ return _n_hint(zep, hod, bus, nex);
+ }
+ }
+
+ case 11: {
+ u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
+ u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
+ u3_noun val;
+
+ u3t_off(noc_o);
+ val = u3m_soft_esc(u3k(ref), u3k(gof));
+ u3t_on(noc_o);
+
+ if ( !_(u3du(val)) ) {
+ u3m_bail(u3nt(1, gof, 0));
+ }
+ if ( !_(u3du(u3t(val))) ) {
+ //
+ // replace with proper error stack push
+ //
+ u3t_push(u3nt(c3__hunk, ref, gof));
+ return u3m_bail(c3__exit);
+ }
+ else {
+ u3_noun pro;
+
+ u3z(ref);
+ u3z(gof);
+ u3z(fol);
+ pro = u3k(u3t(u3t(val)));
+ u3z(val);
+
+ return pro;
+ }
+ }
+ u3_assert(!"not reached");
+ }
+ }
+}
+#endif
+
+// Several opcodes "overflow" (from byte to short index) to their successor, so
+// order can matter here.
+// Note that we use an X macro (https://en.wikipedia.org/wiki/X_Macro) to unify
+// the opcode's enum name, string representation, and computed goto into a
+// single structure.
+#define OPCODES \
+ /* non-nock bytecodes */ \
+ X(HALT, "halt", &&do_halt), /* 0: terminator, end of bytcode program */ \
+ X(BAIL, "bail", &&do_bail), /* 1: deterministic crash */ \
+ /* stack manipulation */ \
+ X(COPY, "copy", &&do_copy), /* 2 */ \
+ X(SWAP, "swap", &&do_swap), /* 3 */ \
+ X(TOSS, "toss", &&do_toss), /* 4 */ \
+ /* auto-cons */ \
+ X(AUTO, "auto", &&do_auto), /* 5: kept */ \
+ X(AULT, "ault", &&do_ault), /* 6: lost */ \
+ /* general purposes */ \
+ X(SNOC, "snoc", &&do_snoc), /* 7: keep */ \
+ X(SNOL, "snol", &&do_snol), /* 8: lose */ \
+ /* nock 0: head */ \
+ X(HEAD, "head", &&do_head), /* 9: keep */ \
+ X(HELD, "held", &&do_held), /* 10: lose */ \
+ /* nock 0: tail */ \
+ X(TAIL, "tail", &&do_tail), /* 11: keep */ \
+ X(TALL, "tall", &&do_tall), /* 12: lose */ \
+ /* nock 0: fragment (keep) */ \
+ X(FABK, "fabk", &&do_fabk), /* 13: c3_y */ \
+ X(FASK, "fask", &&do_fask), /* 14: c3_s */ \
+ X(FIBK, "fibk", &&do_fibk), /* 15: c3_y */ \
+ X(FISK, "fisk", &&do_fisk), /* 16: c3_s */ \
+ /* nock 0: fragment (lose) */ \
+ X(FABL, "fabl", &&do_fabl), /* 17: c3_y */ \
+ X(FASL, "fasl", &&do_fasl), /* 18: c3_s */ \
+ X(FIBL, "fibl", &&do_fibl), /* 19: c3_y */ \
+ X(FISL, "fisl", &&do_fisl), /* 20: c3_s */ \
+ /* nock 1: literal (keep) */ \
+ X(LIT0, "lit0", &&do_lit0), /* 21: a literal 0 */ \
+ X(LIT1, "lit1", &&do_lit1), /* 22: a literal 1 */ \
+ X(LITB, "litb", &&do_litb), /* 23: c3_y */ \
+ X(LITS, "lits", &&do_lits), /* 24: c3_s */ \
+ X(LIBK, "libk", &&do_libk), /* 25: c3_y */ \
+ X(LISK, "lisk", &&do_lisk), /* 26: c3_s */ \
+ /* nock 1: literal (lose) */ \
+ X(LIL0, "lil0", &&do_lil0), /* 27: a literal 0 */ \
+ X(LIL1, "lil1", &&do_lil1), /* 28: a literal 1 */ \
+ X(LILB, "lilb", &&do_lilb), /* 29: c3_y */ \
+ X(LILS, "lils", &&do_lils), /* 30: c3_s */ \
+ X(LIBL, "libl", &&do_libl), /* 31: c3_y */ \
+ X(LISL, "lisl", &&do_lisl), /* 32: c3_s */ \
+ /* nock 2: nock */ \
+ X(NOLK, "nolk", &&do_nolk), /* 33, lost */ \
+ X(NOCT, "noct", &&do_noct), /* 34, tail */ \
+ X(NOCK, "nock", &&do_nock), /* 35, kept */ \
+ /* nock 3 & 4 */ \
+ X(DEEP, "deep", &&do_deep), /* 36 */ \
+ X(BUMP, "bump", &&do_bump), /* 37 */ \
+ /* nock 5: equality */ \
+ X(SAM0, "sam0", &&do_sam0), /* 38: test that it is equal to 0 */ \
+ X(SAM1, "sam1", &&do_sam1), /* 39: test that it is equal to 1 */ \
+ X(SAMB, "samb", &&do_samb), /* 40: test equality for vars size c3_b */ \
+ X(SAMS, "sams", &&do_sams), /* 41: test equality for vars size c3_s */ \
+ X(SANB, "sanb", &&do_sanb), /* 42: test equality for vars size c3_b */ \
+ X(SANS, "sans", &&do_sans), /* 43: test equality for vars size c3_s */ \
+ X(SAME, "same", &&do_same), /* 44 */ \
+ X(SALM, "salm", &&do_salm), /* 45 */ \
+ X(SAMC, "samc", &&do_samc), /* 46 */ \
+ /* related to nock 6: unconditional skips */ \
+ X(SBIP, "sbip", &&do_sbip), /* 47: c3_b */ \
+ X(SIPS, "sips", &&do_sips), /* 48: c3_s */ \
+ X(SWIP, "swip", &&do_swip), /* 49: c3_l */ \
+ /* related to nock 6: conditional skips */ \
+ X(SBIN, "sbin", &&do_sbin), /* 50: c3_b */ \
+ X(SINS, "sins", &&do_sins), /* 51: c3_s */ \
+ X(SWIN, "swin", &&do_swin), /* 52: c3_l */ \
+ /* nock 9 */ \
+ X(KICB, "kicb", &&do_kicb), /* 53: c3_b */ \
+ X(KICS, "kics", &&do_kics), /* 54: c3_s */ \
+ X(TICB, "ticb", &&do_ticb), /* 55: c3_b */ \
+ X(TICS, "tics", &&do_tics), /* 56: c3_s */ \
+ /* nock 12: scry (only defined in arvo, not in base nock spec) */ \
+ X(WILS, "wils", &&do_wils), /* 57 */ \
+ X(WISH, "wish", &&do_wish), /* 58 */ \
+ /* nock 11: hint processing */ \
+ X(BUSH, "bush", &&do_bush), /* 59: c3_b */ \
+ X(SUSH, "sush", &&do_sush), /* 60: c3_s */ \
+ X(DROP, "drop", &&do_drop), /* 61 */ \
+ X(HECK, "heck", &&do_heck), /* 62 */ \
+ X(SLOG, "slog", &&do_slog), /* 63 */ \
+ /* nock 11: fast (keep) */ \
+ X(BAST, "bast", &&do_bast), /* 64: c3_b */ \
+ X(SAST, "sast", &&do_sast), /* 65: c3_s */ \
+ /* nock 11: fast (lost) */ \
+ X(BALT, "balt", &&do_balt), /* 66: c3_b */ \
+ X(SALT, "salt", &&do_salt), /* 67: c3_s */ \
+ /* nock 11: memo (keep) */ \
+ X(SKIB, "skib", &&do_skib), /* 68: c3_b */ \
+ X(SKIS, "skis", &&do_skis), /* 69: c3_s */ \
+ /* nock 11: memo (lose) */ \
+ X(SLIB, "slib", &&do_slib), /* 70: c3_b */ \
+ X(SLIS, "slis", &&do_slis), /* 71: c3_s */ \
+ X(SAVE, "save", &&do_save), /* 72 */ \
+ /* nock 11: before formula */ \
+ X(HILB, "hilb", &&do_hilb), /* 73: atomic, byte */ \
+ X(HILS, "hils", &&do_hils), /* 74: atomic, short */ \
+ X(HINB, "hinb", &&do_hinb), /* 75: arbitrary, byte */ \
+ X(HINS, "hins", &&do_hins), /* 76: arbitrary, short */ \
+ /* nock 11: after formula */ \
+ X(HILK, "hilk", &&do_hilk), /* 77: atomic, keep */ \
+ X(HILL, "hill", &&do_hill), /* 78: atomic, lose */ \
+ X(HINK, "hink", &&do_hink), /* 79: arbitrary, keep */ \
+ X(HINL, "hinl", &&do_hinl), /* 80: arbitrary, lose */ \
+ /* nock 10 */ \
+ X(MUTH, "muth", &&do_muth), /* 81 */ \
+ X(KUTH, "kuth", &&do_kuth), /* 82 */ \
+ X(MUTT, "mutt", &&do_mutt), /* 83 */ \
+ X(KUTT, "kutt", &&do_kutt), /* 84 */ \
+ X(MUSM, "musm", &&do_musm), /* 85 */ \
+ X(KUSM, "kusm", &&do_kusm), /* 86 */ \
+ X(MUTB, "mutb", &&do_mutb), /* 87: c3_b */ \
+ X(MUTS, "muts", &&do_muts), /* 88: c3_s */ \
+ X(MITB, "mitb", &&do_mitb), /* 89: c3_b */ \
+ X(MITS, "mits", &&do_mits), /* 90: c3_s */ \
+ X(KUTB, "kutb", &&do_kutb), /* 91: c3_b */ \
+ X(KUTS, "kuts", &&do_kuts), /* 92: c3_s */ \
+ X(KITB, "kitb", &&do_kitb), /* 93: c3_b */ \
+ X(KITS, "kits", &&do_kits), /* 94: c3_s */ \
+ X(LAST, NULL, NULL), /* 95 */
+
+// Opcodes. Define X to select the enum name from OPCODES.
+#define X(opcode, name, indirect_jump) opcode
+enum { OPCODES };
+#undef X
+
+/* _n_arg(): return the size (in bytes) of an opcode's argument
+ */
+static inline c3_y
+_n_arg(c3_y cod_y)
+{
+ switch ( cod_y ) {
+ case FABK: case FABL: case FIBL: case FIBK:
+ case LILB: case LITB: case LIBL: case LIBK:
+ case SAMB: case SANB: case SBIP: case SBIN:
+ case SLIB: case SKIB: case KICB: case TICB:
+ case BUSH: case BAST: case BALT:
+ case MUTB: case KUTB: case MITB: case KITB:
+ case HILB: case HINB:
+ return sizeof(c3_y);
+
+ case FASK: case FASL: case FISL: case FISK:
+ case LILS: case LITS: case LISL: case LISK:
+ case SAMS: case SANS: case SIPS: case SINS:
+ case SLIS: case SKIS: case KICS: case TICS:
+ case SUSH: case SAST: case SALT:
+ case MUTS: case KUTS: case MITS: case KITS:
+ case HILS: case HINS:
+ return sizeof(c3_s);
+
+ case SWIP: case SWIN:
+ return sizeof(c3_l);
+
+ default:
+ u3_assert( cod_y < LAST );
+ return 0;
+ }
+}
+
+
+/* _n_melt(): measure space for list of ops (from _n_comp) */
+static u3_noun
+_n_melt(u3_noun ops, c3_w* byc_w, c3_w* cal_w,
+ c3_w* reg_w, c3_w* lit_w, c3_w* mem_w)
+{
+ c3_w len_w = u3qb_lent(ops),
+ i_w = len_w - 1,
+ a_w;
+ c3_y cod_y;
+ c3_y* siz_y = u3a_malloc(len_w);
+ u3_noun op, sip = u3_nul;
+
+ while ( u3_nul != ops ) {
+ op = u3h(ops);
+ if ( c3n == u3du(op) ) {
+ switch ( op ) {
+ default:
+ siz_y[i_w] = 1;
+ break;
+
+ case BAST: case BALT:
+ a_w = (*reg_w)++;
+ if ( a_w <= 0xFF ) {
+ siz_y[i_w] = 2;
+ }
+ else if ( a_w <= 0xFFFF ) {
+ siz_y[i_w] = 3;
+ }
+ else {
+ fprintf(stderr, "_n_melt(): over 2^16 registration sites.\r\n");
+ u3_assert(0);
+ }
+ break;
+ }
+ }
+ else {
+ cod_y = u3h(op);
+
+ switch ( cod_y ) {
+ default:
+ siz_y[i_w] = 1 + _n_arg(cod_y);
+ break;
+
+ case SBIP: case SBIN: {
+ c3_l tot_l = 0,
+ sip_l = u3t(op);
+ c3_w j_w, k_w = i_w;
+ for ( j_w = 0; j_w < sip_l; ++j_w ) {
+ tot_l += siz_y[++k_w];
+ }
+ sip = u3nc(tot_l, sip);
+ siz_y[i_w] = tot_l <= 0xFF ? 2 : tot_l <= 0xFFFF ? 3 : 5;
+ break;
+ }
+
+ case SKIB: case SLIB: {
+ c3_l tot_l = 0,
+ sip_l = u3h(u3t(u3t(op)));
+ c3_w j_w, k_w = i_w;
+ for ( j_w = 0; j_w < sip_l; ++j_w ) {
+ tot_l += siz_y[++k_w];
+ }
+ sip = u3nc(tot_l, sip);
+ a_w = (*mem_w)++;
+ if ( a_w <= 0xFF ) {
+ siz_y[i_w] = 2;
+ }
+ else if ( a_w <= 0xFFFF ) {
+ siz_y[i_w] = 3;
+ }
+ else {
+ fprintf(stderr, "_n_melt(): over 2^16 memos.\r\n");
+ u3_assert(0);
+ }
+ break;
+ }
+
+ case SIPS: case SINS: case SWIP: case SWIN:
+ case SAST: case SALT: case KICS: case TICS:
+ case FISK: case FISL: case SUSH: case SANS:
+ case LISL: case LISK: case SKIS: case SLIS:
+ case HILS: case HINS:
+ u3_assert(0); //overflows
+ break;
+
+ case KICB: case TICB:
+ a_w = (*cal_w)++;
+ if ( a_w <= 0xFF ) {
+ siz_y[i_w] = 2;
+ }
+ else if ( a_w <= 0xFFFF ) {
+ siz_y[i_w] = 3;
+ }
+ else {
+ fprintf(stderr, "_n_melt(): over 2^16 call sites.\r\n");
+ u3_assert(0);
+ }
+ break;
+
+ case BUSH: case FIBK: case FIBL:
+ case SANB: case LIBL: case LIBK:
+ case KITB: case MITB:
+ case HILB: case HINB:
+ a_w = (*lit_w)++;
+ if ( a_w <= 0xFF ) {
+ siz_y[i_w] = 2;
+ }
+ else if ( a_w <= 0xFFFF ) {
+ siz_y[i_w] = 3;
+ }
+ else {
+ fprintf(stderr, "_n_melt(): over 2^16 literals.\r\n");
+ u3_assert(0);
+ }
+ break;
+ }
+ }
+
+ *(byc_w) += siz_y[i_w--];
+ ops = u3t(ops);
+ }
+
+ u3a_free(siz_y);
+ return u3kb_flop(sip);
+}
+
+/* _n_prog_dat(): return pointer to program's data segment
+ */
+static void*
+_n_prog_dat(u3n_prog* pog_u)
+{
+ return ((void*) pog_u) + sizeof(u3n_prog);
+}
+
+/* _n_prog_new(): allocate and set up pointers for u3n_prog
+ */
+static u3n_prog*
+_n_prog_new(c3_w byc_w, c3_w cal_w,
+ c3_w reg_w, c3_w lit_w, c3_w mem_w)
+{
+ c3_w cab_w = (sizeof(u3j_site) * cal_w),
+ reb_w = (sizeof(u3j_rite) * reg_w),
+ lib_w = (sizeof(u3_noun) * lit_w),
+ meb_w = (sizeof(u3n_memo) * mem_w),
+ pad_w = (8 - byc_w % 8) % 8,
+ pod_w = lit_w % 2,
+ ped_w = mem_w % 2,
+ dat_w = byc_w + cab_w + reb_w + lib_w + meb_w + pad_w +
+ (pod_w * sizeof(u3_noun)) + (ped_w * sizeof(u3n_memo));
+
+ u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w);
+ pog_u->byc_u.own_o = c3y;
+ pog_u->byc_u.len_w = byc_w;
+ pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u);
+
+ pog_u->lit_u.len_w = lit_w;
+ pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w + pad_w);
+
+ pog_u->mem_u.len_w = mem_w;
+ pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w);
+
+ pog_u->cal_u.len_w = cal_w;
+ pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w);
+
+ pog_u->reg_u.len_w = reg_w;
+ pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w);
+
+ return pog_u;
+}
+
+/* _n_prog_old(): as _n_prog_new(),
+ * but leech off senior program's data segment
+ */
+static u3n_prog*
+_n_prog_old(u3n_prog* sep_u)
+{
+ c3_w cab_w = sizeof(u3j_site) * sep_u->cal_u.len_w,
+ reb_w = sizeof(u3j_rite) * sep_u->reg_u.len_w,
+ lib_w = sizeof(u3_noun) * sep_u->lit_u.len_w,
+ meb_w = sizeof(u3n_memo) * sep_u->mem_u.len_w,
+ pod_w = sep_u->lit_u.len_w % 2,
+ ped_w = sep_u->mem_u.len_w % 2,
+ dat_w = cab_w + reb_w + lib_w + meb_w +
+ (pod_w * sizeof(u3_noun)) + (ped_w * sizeof(u3n_memo));
+
+ u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w);
+ pog_u->byc_u.own_o = c3n;
+ pog_u->byc_u.len_w = sep_u->byc_u.len_w;
+ pog_u->byc_u.ops_y = sep_u->byc_u.ops_y;
+
+ pog_u->lit_u.len_w = sep_u->lit_u.len_w;
+ pog_u->lit_u.non = (u3_noun*) _n_prog_dat(pog_u);
+
+ pog_u->mem_u.len_w = sep_u->mem_u.len_w;
+ pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w);
+
+ pog_u->cal_u.len_w = sep_u->cal_u.len_w;
+ pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w);
+
+ pog_u->reg_u.len_w = sep_u->reg_u.len_w;
+ pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w);
+
+ memcpy(pog_u->lit_u.non, sep_u->lit_u.non, dat_w);
+ return pog_u;
+}
+
+/* _n_prog_asm_inx(): write an index to the bytestream with overflow
+ */
+static void
+_n_prog_asm_inx(c3_y* buf_y, c3_w* i_w, c3_s inx_s, c3_y cod)
+{
+ if ( inx_s <= 0xFF ) {
+ buf_y[(*i_w)--] = (c3_y) (inx_s);
+ buf_y[*i_w] = (c3_y) cod;
+ }
+ else {
+ buf_y[(*i_w)--] = (c3_y) (inx_s >> 8);
+ buf_y[(*i_w)--] = (c3_y) (inx_s);
+ // the short-index versions of these opcodes must immediately
+ // follow the byte-index versions because of this convention
+ buf_y[(*i_w)] = cod + 1;
+ }
+}
+
+/* _n_prog_asm(): assemble list of ops (from _n_comp) into u3n_prog
+ */
+static void
+_n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip)
+{
+ u3_noun top = ops;
+ c3_y* buf_y = pog_u->byc_u.ops_y;
+ c3_s lit_s = 0,
+ cal_s = 0,
+ mem_s = 0,
+ reg_s = 0;
+ c3_w i_w = pog_u->byc_u.len_w-1;
+
+ buf_y[i_w] = HALT;
+
+ while ( i_w-- > 0 ) {
+ u3_noun op = u3h(ops);
+ if ( c3y == u3ud(op) ) {
+ switch ( op ) {
+ default:
+ buf_y[i_w] = (c3_y) op;
+ break;
+
+ /* registration site index args */
+ case BAST: case BALT: {
+ _n_prog_asm_inx(buf_y, &i_w, reg_s, op);
+ u3j_rite* rit_u = &(pog_u->reg_u.rit_u[reg_s++]);
+ rit_u->own_o = c3n;
+ rit_u->clu = u3_none;
+ rit_u->fin_p = 0;
+ break;
+ }
+ }
+ }
+ else {
+ u3_noun cod = u3h(op);
+ switch ( cod ) {
+ default:
+ u3_assert(0);
+ return;
+
+ /* memo index args */
+ case SKIB: case SLIB: {
+ u3n_memo* mem_u;
+ c3_l sip_l = u3h(sip);
+ u3_noun tmp = sip;
+ sip = u3k(u3t(sip));
+ u3z(tmp);
+ _n_prog_asm_inx(buf_y, &i_w, mem_s, cod);
+ mem_u = &(pog_u->mem_u.sot_u[mem_s++]);
+ mem_u->sip_l = sip_l;
+ // [op_y, cid, mem_w, nef]
+ mem_u->key = u3k(u3t(u3t(u3t(op))));
+ mem_u->cid = u3h(u3t(op));
+ break;
+ }
+
+ /* skips */
+ case SBIP: case SBIN: {
+ c3_l sip_l = u3h(sip);
+ u3_noun tmp = sip;
+ sip = u3k(u3t(sip));
+ u3z(tmp);
+ if ( sip_l <= 0xFF ) {
+ buf_y[i_w--] = (c3_y) sip_l;
+ buf_y[i_w] = (c3_y) cod;
+ }
+ else if ( sip_l <= 0xFFFF ) {
+ buf_y[i_w--] = (c3_y) (sip_l >> 8);
+ buf_y[i_w--] = (c3_y) sip_l;
+ buf_y[i_w] = (c3_y) cod + 1;
+ }
+ else {
+ buf_y[i_w--] = (c3_y) (sip_l >> 24);
+ buf_y[i_w--] = (c3_y) (sip_l >> 16);
+ buf_y[i_w--] = (c3_y) (sip_l >> 8);
+ buf_y[i_w--] = (c3_y) sip_l;
+ buf_y[i_w] = (c3_y) cod + 2;
+ }
+ break;
+ }
+
+ /* 8-bit direct args */
+ case FABK: case FABL:
+ case LITB: case LILB:
+ case MUTB: case KUTB:
+ case SAMB:
+ buf_y[i_w--] = (c3_y) u3t(op);
+ buf_y[i_w] = (c3_y) cod;
+ break;
+
+ /* 16-bit direct args */
+ case FASK: case FASL:
+ case LILS: case LITS:
+ case MUTS: case KUTS:
+ case SAMS: case SIPS: case SINS: {
+ c3_s off_s = u3t(op);
+ buf_y[i_w--] = (c3_y) (off_s >> 8);
+ buf_y[i_w--] = (c3_y) off_s;
+ buf_y[i_w] = (c3_y) cod;
+ break;
+ }
+
+ /* 31-bit direct args */
+ case SWIP: case SWIN: {
+ c3_w off_l = u3t(op);
+ buf_y[i_w--] = (c3_y) (off_l >> 24);
+ buf_y[i_w--] = (c3_y) (off_l >> 16);
+ buf_y[i_w--] = (c3_y) (off_l >> 8);
+ buf_y[i_w--] = (c3_y) off_l;
+ buf_y[i_w] = (c3_y) cod;
+ break;
+ }
+
+ /* literal index args */
+ case FIBK: case FIBL:
+ case LIBK: case LIBL:
+ case BUSH: case SANB:
+ case KITB: case MITB:
+ case HILB: case HINB:
+ _n_prog_asm_inx(buf_y, &i_w, lit_s, cod);
+ pog_u->lit_u.non[lit_s++] = u3k(u3t(op));
+ break;
+
+ /* call site index args */
+ case TICB: case KICB: {
+ _n_prog_asm_inx(buf_y, &i_w, cal_s, cod);
+ u3j_site* sit_u = &(pog_u->cal_u.sit_u[cal_s++]);
+ sit_u->axe = u3k(u3t(op));
+ sit_u->pog_p = 0;
+ sit_u->bat = u3_none;
+ sit_u->bas = u3_none;
+ sit_u->loc = u3_none;
+ sit_u->lab = u3_none;
+ sit_u->jet_o = c3n;
+ sit_u->fon_o = c3n;
+ sit_u->cop_u = NULL;
+ sit_u->ham_u = NULL;
+ sit_u->fin_p = 0;
+ break;
+ }
+ }
+ }
+ ops = u3t(ops);
+ }
+ u3z(top);
+ // this assert will fail if we overflow a c3_w worth of instructions
+ u3_assert(u3_nul == ops);
+ // this is just a sanity check
+ u3_assert(u3_nul == sip);
+}
+
+/* _n_prog_from_ops(): new program from _n_comp() product
+ */
+static u3n_prog*
+_n_prog_from_ops(u3_noun ops)
+{
+ u3_noun sip;
+ u3n_prog* pog_u;
+ c3_w byc_w = 1, // HALT
+ cal_w = 0,
+ reg_w = 0,
+ lit_w = 0,
+ mem_w = 0;
+
+ sip = _n_melt(ops, &byc_w, &cal_w, &reg_w, &lit_w, &mem_w);
+ pog_u = _n_prog_new(byc_w, cal_w, reg_w, lit_w, mem_w);
+ _n_prog_asm(ops, pog_u, sip);
+ return pog_u;
+}
+
+#if 0
+/* _n_print_stack(): print out the cap stack up to a designated "empty"
+ * used only for debugging
+ */
+static void _n_print_stack(u3p(u3_noun) empty) {
+ c3_w cur_p = u3R->cap_p;
+ fprintf(stderr, "[");
+ int first = 1;
+ while ( cur_p != empty ) {
+ if ( first ) {
+ first = 0;
+ }
+ else {
+ fprintf(stderr, " ");
+ }
+ if ( c3y == u3a_is_north(u3R) ) {
+ fprintf(stderr, "%u", *(u3to(u3_noun, cur_p)));
+ cur_p++;
+ }
+ else {
+ fprintf(stderr, "%u", *(u3to(u3_noun, cur_p-1)));
+ cur_p--;
+ }
+ }
+ fprintf(stderr, "]\r\n");
+}
+#endif
+
+// Define X to select the opcode string representation from OPCODES.
+# define X(opcode, name, indirect_jump) name
+static c3_c* opcode_names[] = { OPCODES };
+# undef X
+
+/* _n_apen(): emit the instructions contained in src to dst
+ */
+static inline void
+_n_apen(u3_noun* dst, u3_noun src)
+{
+ *dst = u3kb_weld(src, *dst);
+}
+
+/* _n_emit(): emit a single instruction to ops
+ */
+static inline void
+_n_emit(u3_noun *ops, u3_noun op)
+{
+ *ops = u3nc(op, *ops);
+}
+
+static c3_w _n_comp(u3_noun*, u3_noun, c3_o, c3_o);
+
+/* _n_bint(): hint-processing helper for _n_comp.
+ * hif: hint-formula (first part of 11). RETAIN.
+ * nef: next-formula (second part of 11). RETAIN.
+ */
+static c3_w
+_n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o)
+{
+ c3_w tot_w = 0;
+
+ if ( c3n == u3du(hif) ) {
+ // compile whitelisted atomic hints to dispatch protocol;
+ // compute and drop all others;
+ //
+ switch ( hif ) {
+ default: {
+ return _n_comp(ops, nef, los_o, tel_o);
+ }
+ case c3__cash:
+ case c3__xray:
+ case c3__meme:
+ case c3__nara:
+ case c3__hela:
+ case c3__bout: {
+ u3_noun fen = u3_nul;
+ c3_w nef_w = _n_comp(&fen, nef, los_o, c3n);
+ // add appropriate hind opcode
+ ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HILL : HILK);
+ // skip over the cleanup opcode
+ ++nef_w; _n_emit(&fen, u3nc(SBIP, 1));
+
+ // call hilt_fore
+ // HILB overflows to HILS
+ ++tot_w; _n_emit(ops, u3nc(HILB, u3nc(u3k(hif), u3k(nef))));
+ // if fore return c3n, skip fen
+ ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w));
+ tot_w += nef_w; _n_apen(ops, fen);
+ // post-skip cleanup opcode
+ ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP);
+ } break;
+ }
+ }
+ else {
+ u3_noun zep, hod;
+ u3x_cell(hif, &zep, &hod);
+
+ switch ( zep ) {
+ default: {
+ // compile whitelisted dynamic hints to dispatch protocol;
+ // compute and drop all others;
+ //
+ switch ( zep ) {
+ default: {
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, TOSS);
+ tot_w += _n_comp(ops, nef, los_o, tel_o);
+ } break;
+ case c3__xray:
+ case c3__meme:
+ case c3__nara:
+ case c3__hela:
+ case c3__spin:
+ case c3__bout: {
+ u3_noun fen = u3_nul;
+ c3_w nef_w = _n_comp(&fen, nef, los_o, c3n);
+ // add appropriate hind opcode
+ ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HINL : HINK);
+ // skip over the cleanup opcode
+ ++nef_w; _n_emit(&fen, u3nc(SBIP, 1));
+
+ // push clue
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ // call hint_fore
+ // HINB overflows to HINS
+ ++tot_w; _n_emit(ops, u3nc(HINB, u3nc(u3k(zep), u3k(nef))));
+ // if fore return c3n, skip fen
+ ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w));
+ tot_w += nef_w; _n_apen(ops, fen);
+ // post-skip cleanup opcode
+ ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP);
+ } break;
+ }
+ } break;
+
+ case c3__hunk:
+ case c3__lose:
+ case c3__mean:
+ case c3__spot:
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, u3nc(BUSH, zep)); // overflows to SUSH
+ tot_w += _n_comp(ops, nef, los_o, c3n);
+ ++tot_w; _n_emit(ops, DROP);
+ break;
+
+ case c3__live:
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, HECK);
+ tot_w += _n_comp(ops, nef, los_o, tel_o);
+ break;
+
+ case c3__slog:
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, SLOG);
+ tot_w += _n_comp(ops, nef, los_o, tel_o);
+ break;
+
+ // germ and sole are unused...
+
+ case c3__fast:
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, nef, los_o, c3n);
+ // overflows to SALT / SAST
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? BALT : BAST);
+ break;
+
+ case c3__memo: {
+ u3_noun mem = u3_nul;
+ c3_w mem_w = 0;
+ c3_y op_y;
+
+ tot_w += _n_comp(ops, hod, c3n, c3n);
+ ++tot_w; _n_emit(ops, TOSS);
+
+ mem_w += _n_comp(&mem, nef, c3y, c3n);
+ ++mem_w; _n_emit(&mem, SAVE);
+
+ op_y = (c3y == los_o) ? SLIB : SKIB; // overflows to SLIS / SKIS
+ u3z_cid cid = u3z_memo_toss;
+ {
+ u3_weak con = u3r_skip(hod);
+ if ( (u3_none != con) && (c3y == u3du(con)) ) {
+ cid = u3z_memo_keep;
+ }
+ }
+ ++tot_w; _n_emit(ops, u3nq(op_y, cid, mem_w, u3k(nef)));
+ tot_w += mem_w; _n_apen(ops, mem);
+ break;
+ }
+ }
+ }
+
+ return tot_w;
+}
+
+static c3_t
+_n_formulaic(u3_noun fol)
+{
+ u3_noun op, ar, a, b, c;
+ if ( c3n == u3r_cell(fol, &op, &ar) ) {
+ return 0;
+ }
+ if ( c3y == u3du(op) ) {
+ return _n_formulaic(op) && _n_formulaic(ar);
+ }
+ else switch ( op ) {
+ case 0:
+ return ( c3y == u3ud(ar) );
+ case 1:
+ return 1;
+ case 3:
+ case 4:
+ return _n_formulaic(ar);
+ case 2:
+ case 5:
+ case 7:
+ case 8:
+ case 12:
+ return (c3y == u3r_cell(ar, &a, &b))
+ && _n_formulaic(a) && _n_formulaic(b);
+ case 6: {
+ u3_noun lit;
+
+ if ( c3n == u3r_trel(ar, &a, &b, &c) || !_n_formulaic(a) ) {
+ return 0;
+ }
+
+ if ( c3n == u3r_safe(a, &lit) || u3_none == lit ) {
+ return _n_formulaic(b) || _n_formulaic(c);
+ }
+
+ switch (lit) {
+ case 0: return _n_formulaic(b);
+ case 1: return _n_formulaic(c);
+ default: return 0;
+ }
+ }
+ case 9:
+ return (c3y == u3r_cell(ar, &a, &b))
+ && (c3y == u3ud(a))
+ && _n_formulaic(b);
+ case 10:
+ if ( c3n == u3r_cell(ar, &a, &b) ) {
+ return 0;
+ }
+ if ( c3n == u3du(a) ) {
+ return 0;
+ }
+ if ( c3n == u3ud(u3h(a)) ) {
+ return 0;
+ }
+ return _n_formulaic(u3t(a)) && _n_formulaic(b);
+ case 11:
+ if ( c3n == u3r_cell(ar, &a, &b) ) {
+ return 0;
+ }
+ if ( !_n_formulaic(b) ) {
+ return 0;
+ }
+ if ( c3y == u3ud(a) ) {
+ return 1;
+ }
+ else {
+ return ( c3y == u3ud(u3h(a)) ) && _n_formulaic(u3t(a));
+ }
+ default:
+ return 0;
+ }
+}
+
+/* _n_comp(): compile nock formula to reversed opcode list
+ * ops is a pointer to a list (to be emitted to)
+ * fol is the nock formula to compile. RETAIN.
+ * los_o indicates whether we should remove our
+ * subject from the stack
+ * tel_o is yes if this formula is in tail position
+ * return: number of instructions added to the opcode list
+ */
+static c3_w
+_n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o)
+{
+ c3_y op_y;
+ c3_w tot_w = 0;
+ u3_noun cod, arg, hed, tel;
+ u3x_cell(fol, &cod, &arg);
+ if ( c3y == u3du(cod) ) {
+ tot_w += _n_comp(ops, cod, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, arg, los_o, c3n);
+ ++tot_w; _n_emit(ops, (c3y == los_o ) ? AULT : AUTO);
+ }
+ else switch ( cod ) {
+ case 0:
+ if ( c3n == u3ud(arg) ) {
+ u3m_bail(c3__exit);
+ return 0;
+ }
+ switch ( arg ) {
+ case 0:
+ ++tot_w; _n_emit(ops, BAIL);
+ break;
+ case 1:
+ if ( c3n == los_o ) {
+ ++tot_w; _n_emit(ops, COPY);
+ }
+ break;
+ case 2:
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? HELD : HEAD);
+ break;
+ case 3:
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? TALL : TAIL);
+ break;
+ default:
+ op_y = (c3y == los_o)
+ ? (arg <= 0xFF ? FABL : arg <= 0xFFFF ? FASL : FIBL) // overflows to FISL
+ : (arg <= 0xFF ? FABK : arg <= 0xFFFF ? FASK : FIBK); // overflows to FISK
+ ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg)));
+ break;
+ }
+ break;
+
+ case 1:
+ switch ( arg ) {
+ case 0:
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0);
+ break;
+ case 1:
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1);
+ break;
+ default:
+ op_y = (c3y == los_o)
+ ? (arg <= 0xFF ? LILB : arg <= 0xFFFF ? LILS : LIBL) // overflows to LISL
+ : (arg <= 0xFF ? LITB : arg <= 0xFFFF ? LITS : LIBK); // overflows to LISK
+ ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg)));
+ break;
+ }
+ break;
+
+ case 2:
+ u3x_cell(arg, &hed, &tel);
+ tot_w += _n_comp(ops, hed, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, tel, los_o, c3n);
+ /* things in tail position replace (so, lose) top of stack,
+ * so NOCT "loses" and there is no non-losing version */
+ op_y = (c3y == tel_o) ? NOCT
+ : ((c3y == los_o) ? NOLK : NOCK);
+ ++tot_w; _n_emit(ops, op_y);
+ break;
+
+ case 3:
+ tot_w += _n_comp(ops, arg, los_o, c3n);
+ ++tot_w; _n_emit(ops, DEEP);
+ break;
+
+ case 4:
+ tot_w += _n_comp(ops, arg, los_o, c3n);
+ ++tot_w; _n_emit(ops, BUMP);
+ break;
+
+ case 5: {
+ u3x_cell(arg, &hed, &tel);
+
+ if ( c3n == u3du(hed) ) {
+ u3m_bail(c3__exit);
+ return 0;
+ }
+ else {
+ c3_t hec_t, tec_t;
+ hec_t = (1 == u3h(hed));
+ if ( c3n == u3du(tel) ) {
+ u3m_bail(c3__exit);
+ break;
+ }
+ else {
+ tec_t = (1 == u3h(tel));
+ }
+ if ( hec_t && tec_t ) {
+ if ( c3y == u3r_sing(u3t(hed), u3t(tel)) ) {
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0);
+ }
+ else {
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1);
+ }
+ }
+ else if ( !hec_t && !tec_t ) {
+ tot_w += _n_comp(ops, hed, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, tel, los_o, c3n);
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? SALM : SAME);
+ }
+ else {
+ tot_w += _n_comp(ops, (hec_t ? tel : hed), los_o, c3n);
+ u3_noun lit = u3t(hec_t ? hed : tel);
+ switch ( lit ) {
+ case 0:
+ ++tot_w; _n_emit(ops, SAM0);
+ break;
+ case 1:
+ ++tot_w; _n_emit(ops, SAM1);
+ break;
+ default:
+ // overflows to SANS
+ op_y = lit <= 0xFF ? SAMB : lit <= 0xFFFF ? SAMS : SANB;
+ ++tot_w; _n_emit(ops, u3nc(op_y, u3k(lit)));
+ }
+ }
+ }
+ break;
+ }
+
+ case 6: {
+ u3_noun mid, lit;
+ u3x_trel(arg, &hed, &mid, &tel);
+ if ( c3y == u3r_safe(hed, &lit) && u3_none != lit ) {
+ switch ( lit ) {
+ case 0:
+ tot_w += _n_comp(ops, mid, los_o, tel_o);
+ break;
+
+ case 1:
+ tot_w += _n_comp(ops, tel, los_o, tel_o);
+ break;
+
+ default:
+ ++tot_w; _n_emit(ops, BAIL);
+ break;
+ }
+ }
+ else {
+ u3_noun yep = u3_nul,
+ nop = u3_nul;
+ c3_w yep_w, nop_w;
+ c3_t yep_t, nop_t;
+
+ tot_w += _n_comp(ops, hed, c3n, c3n);
+ yep_t = _n_formulaic(mid);
+ nop_t = _n_formulaic(tel);
+
+ if ( !yep_t && !nop_t ) {
+ u3m_bail(c3__exit);
+ break;
+ }
+
+ if ( yep_t ) {
+ yep_w = _n_comp(&yep, mid, los_o, tel_o);
+ }
+ else {
+ yep_w = 1; _n_emit(&yep, BAIL);
+ }
+
+ if ( nop_t ) {
+ nop_w = _n_comp(&nop, tel, los_o, tel_o);
+ }
+ else {
+ nop_w = 1; _n_emit(&nop, BAIL);
+ }
+
+ // SBIP and SBIN get sized during assembly
+ ++yep_w; _n_emit(&yep, u3nc(SBIP, nop_w));
+ ++tot_w; _n_emit(ops, u3nc(SBIN, yep_w));
+ tot_w += yep_w; _n_apen(ops, yep);
+ tot_w += nop_w; _n_apen(ops, nop);
+ }
+ break;
+ }
+
+ case 7:
+ u3x_cell(arg, &hed, &tel);
+ tot_w += _n_comp(ops, hed, los_o, c3n);
+ tot_w += _n_comp(ops, tel, c3y, tel_o);
+ break;
+
+ case 8:
+ u3x_cell(arg, &hed, &tel);
+ tot_w += _n_comp(ops, hed, c3n, c3n);
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? SNOL : SNOC);
+ tot_w += _n_comp(ops, tel, c3y, tel_o);
+ break;
+
+ case 9:
+ u3x_cell(arg, &hed, &tel);
+ if ( (1 == hed) || (3 == u3qc_cap(u3x_atom(hed))) ) {
+ u3_noun mac = u3nq(7, u3k(tel), 2, u3nt(u3nc(0, 1), 0, u3k(hed)));
+ tot_w += _n_comp(ops, mac, los_o, tel_o);
+ u3z(mac);
+ }
+ else {
+ tot_w += _n_comp(ops, tel, (c3y == tel_o ? c3y : los_o), c3n);
+ op_y = (c3y == tel_o) ? TICB : KICB; // overflows to TICS/KICS
+ ++tot_w; _n_emit(ops, u3nc(op_y, u3k(hed)));
+ }
+ break;
+
+ case 10: {
+ u3_noun axe, nef;
+ u3x_cell(arg, &hed, &tel);
+ u3x_cell(hed, &axe, &nef);
+ tot_w += _n_comp(ops, tel, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, nef, los_o, c3n);
+
+ ++tot_w;
+ switch ( axe ) {
+ case 2:
+ _n_emit(ops, (c3y == los_o) ? MUTH : KUTH);
+ break;
+
+ case 3:
+ _n_emit(ops, (c3y == los_o) ? MUTT : KUTT);
+ break;
+
+ case u3x_sam:
+ _n_emit(ops, (c3y == los_o) ? MUSM : KUSM);
+ break;
+
+ default:
+ op_y = (c3y == los_o)
+ ? (axe <= 0xFF) ? MUTB : (axe <= 0xFFFF) ? MUTS : MITB // overflows to MITS
+ : (axe <= 0xFF) ? KUTB : (axe <= 0xFFFF) ? KUTS : KITB; // overflows to KITS
+ _n_emit(ops, u3nc(op_y, u3k(axe)));
+ break;
+ }
+ break;
+ }
+
+ case 11:
+ u3x_cell(arg, &hed, &tel);
+ tot_w += _n_bint(ops, hed, tel, los_o, tel_o);
+ break;
+
+ case 12:
+ u3x_cell(arg, &hed, &tel);
+ tot_w += _n_comp(ops, hed, c3n, c3n);
+ ++tot_w; _n_emit(ops, SWAP);
+ tot_w += _n_comp(ops, tel, los_o, c3n);
+ ++tot_w; _n_emit(ops, (c3y == los_o) ? WILS : WISH);
+ break;
+
+ default:
+ u3m_bail(c3__exit);
+ return 0;
+ }
+ return tot_w;
+}
+
+/* _n_push(): push a noun onto the stack. RETAIN
+ * mov: -1 north, 1 south
+ * off: 0 north, -1 south
+ */
+static inline void
+_n_push(c3_ys mov, c3_ys off, u3_noun a)
+{
+ u3R->cap_p += mov;
+
+ // XX switch to u3a_push()
+ //
+#ifndef U3_GUARD_PAGE
+ if ( 0 == off ) {
+ if( !(u3R->cap_p > u3R->hat_p) ) {
+ u3m_bail(c3__meme);
+ }
+ }
+ else {
+ if( !(u3R->cap_p < u3R->hat_p) ) {
+ u3m_bail(c3__meme);
+ }
+ }
+#endif
+
+ u3_noun* p = u3to(u3_noun, u3R->cap_p + off);
+ *p = a;
+}
+
+/* _n_peek(): pointer to noun at top of stack
+ * off: 0 north, -1 south
+ */
+static inline u3_noun*
+_n_peek(c3_ys off)
+{
+ return u3to(u3_noun, u3R->cap_p + off);
+}
+
+/* _n_peet(): address of the next-to-top of stack
+ * mov: -1 north, 1 south
+ * off: 0 north, -1 south
+ */
+static inline u3_noun*
+_n_peet(c3_ys mov, c3_ys off)
+{
+ return u3to(u3_noun, (u3R->cap_p - mov) + off);
+}
+
+/* _n_pop(): pop a noun from the cap stack
+ * mov: -1 north, 1 south
+ */
+static inline void
+_n_pop(c3_ys mov)
+{
+ u3R->cap_p -= mov;
+}
+
+/* _n_pep(): pop and return noun from the cap stack
+ * mov: -1 north, 1 south
+ * off: 0 north, -1 south
+ */
+static inline u3_noun
+_n_pep(c3_ys mov, c3_ys off)
+{
+ u3_noun r = *(_n_peek(off));
+ _n_pop(mov);
+ return r;
+}
+
+/* _n_toss(): pep and lose
+ */
+static inline void
+_n_toss(c3_ys mov, c3_ys off)
+{
+ u3z(_n_pep(mov, off));
+}
+
+/* _n_resh(): read a c3_s from the bytecode stream
+ */
+static inline c3_s
+_n_resh(c3_y* buf, c3_w* ip_w)
+{
+ c3_y les = buf[(*ip_w)++];
+ c3_y mos = buf[(*ip_w)++];
+ return les | (mos << 8);
+}
+
+/* _n_rewo(): read a c3_w from the bytecode stream.
+ */
+static inline c3_w
+_n_rewo(c3_y* buf, c3_w* ip_w)
+{
+ c3_y one = buf[(*ip_w)++],
+ two = buf[(*ip_w)++],
+ tre = buf[(*ip_w)++],
+ qua = buf[(*ip_w)++];
+ return one | (two << 8) | (tre << 16) | (qua << 24);
+}
+
+/* _n_swap(): swap two items on the top of the stack, return pointer to top
+ */
+static inline u3_noun*
+_n_swap(c3_ys mov, c3_ys off)
+{
+ u3_noun* top = _n_peek(off);
+ u3_noun* up = _n_peet(mov, off);
+ u3_noun tmp = *up;
+ *up = *top;
+ *top = tmp;
+ return top;
+}
+
+#ifdef VERBOSE_BYTECODE
+/* _n_print_byc(): print bytecode. used for debugging.
+ */
+static void
+_n_print_byc(c3_y* pog, c3_w her_w)
+{
+ c3_w ip_w = 0;
+ if ( her_w == 0 ) {
+ fprintf(stderr, "begin: {");
+ }
+ else {
+ fprintf(stderr, "resume: {");
+ }
+ int first = 1;
+ while ( pog[ip_w] ) {
+ if ( first ) {
+ first = 0;
+ }
+ else if (ip_w == her_w) {
+ fprintf(stderr, " [*]");
+ }
+ else {
+ fprintf(stderr, " ");
+ }
+ switch ( _n_arg(pog[ip_w]) ) {
+ case 0:
+ fprintf(stderr, "%s", opcode_names[pog[ip_w++]]);
+ break;
+
+ case 1:
+ fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]);
+ fprintf(stderr, "%u]", pog[ip_w++]);
+ break;
+
+ case 2:
+ fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]);
+ fprintf(stderr, "%u]", _n_resh(pog, &ip_w));
+ break;
+
+ case 4:
+ fprintf(stderr, "[%s", opcode_names[pog[ip_w++]]);
+ fprintf(stderr, "%u]", _n_rewo(pog, &ip_w));
+ break;
+ default:
+ u3_assert(0);
+ break;
+ }
+ }
+ fprintf(stderr, " halt}\r\n");
+}
+#endif
+
+/* _n_bite(): compile a nock formula to bytecode. RETAIN.
+ */
+static inline u3n_prog*
+_n_bite(u3_noun fol) {
+ u3_noun ops = u3_nul;
+ _n_comp(&ops, fol, c3y, c3y);
+ return _n_prog_from_ops(ops);
+}
+
+static inline c3_w
+_cn_of_prog(u3n_prog *pog_u)
+{
+ u3_post pog_p = u3of(u3n_prog, pog_u);
+ return pog_p >> u3a_vits;
+}
+
+static inline u3n_prog*
+_cn_to_prog(c3_w pog_w)
+{
+ u3_post pog_p = pog_w << u3a_vits;
+ return u3to(u3n_prog, pog_p);
+}
+
+/* _n_find(): return prog for given formula with prefix (u3_nul for none).
+ * RETAIN.
+ */
+static u3n_prog*
+_n_find(u3_noun pre, u3_noun fol)
+{
+ u3_noun key = u3nc(u3k(pre), u3k(fol));
+ u3_weak pog = u3h_git(u3R->byc.har_p, key);
+ if ( u3_none != pog ) {
+ u3z(key);
+ return _cn_to_prog(pog);
+ }
+ else if ( u3R != &u3H->rod_u ) {
+ u3a_road* rod_u = u3R;
+ while ( rod_u->par_p ) {
+ rod_u = u3to(u3a_road, rod_u->par_p);
+ pog = u3h_git(rod_u->byc.har_p, key);
+ if ( u3_none != pog ) {
+ c3_w i_w;
+ u3n_prog* old = _n_prog_old(_cn_to_prog(pog));
+ for ( i_w = 0; i_w < old->reg_u.len_w; ++i_w ) {
+ u3j_rite* rit_u = &(old->reg_u.rit_u[i_w]);
+ rit_u->own_o = c3n;
+ }
+ for ( i_w = 0; i_w < old->cal_u.len_w; ++i_w ) {
+ u3j_site* sit_u = &(old->cal_u.sit_u[i_w]);
+ sit_u->bat = u3_none;
+ sit_u->pog_p = 0;
+ sit_u->fon_o = c3n;
+ }
+ u3h_put(u3R->byc.har_p, key, _cn_of_prog(old));
+ u3z(key);
+ return old;
+ }
+ }
+ }
+
+ {
+ u3n_prog* gop = _n_bite(fol);
+ u3h_put(u3R->byc.har_p, key, _cn_of_prog(gop));
+ u3z(key);
+ return gop;
+ }
+}
+
+/* u3n_find(): return prog for given formula,
+ * split by key (u3_nul for no key). RETAIN.
+ */
+u3p(u3n_prog)
+u3n_find(u3_noun key, u3_noun fol)
+{
+ u3p(u3n_prog) pog_p;
+ u3t_on(noc_o);
+ pog_p = u3of(u3n_prog, _n_find(key, fol));
+ u3t_off(noc_o);
+ return pog_p;
+}
+
+/* _cn_prog_free(): free memory retained by program pog_u
+*/
+static void
+_cn_prog_free(u3n_prog* pog_u)
+{
+ c3_w dex_w;
+ for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) {
+ u3z(pog_u->lit_u.non[dex_w]);
+ }
+ for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) {
+ u3z(pog_u->mem_u.sot_u[dex_w].key);
+ }
+ for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) {
+ u3j_site_lose(&(pog_u->cal_u.sit_u[dex_w]));
+ }
+ for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) {
+ u3j_rite_lose(&(pog_u->reg_u.rit_u[dex_w]));
+ }
+ u3a_free(pog_u);
+}
+
+/* _cn_intlen(): find the number of characters num_w would take to print.
+** num_w: an int we want to later serialize to a string
+*/
+c3_w
+_cn_intlen(c3_w num_w)
+{
+ c3_w len_w=0;
+ while(num_w){
+ num_w/=10;
+ len_w++;
+ }
+ return len_w;
+}
+
+/* _cn_is_indexed(): return true if bop_w is an opcodes that uses pog_u->lit_u.non
+** bop_w: opcode (assumed 0-94)
+*/
+c3_b
+_cn_is_indexed(c3_w bop_w)
+{
+ switch (bop_w) {
+ case FIBK: case FISK:
+ case FIBL: case FISL:
+ case LIBK: case LISK:
+ case LIBL: case LISL:
+ case BUSH: case SUSH:
+ case SANB: case SANS:
+ case KITB: case KITS:
+ case MITB: case MITS:
+ case HILB: case HILS:
+ case HINB: case HINS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* _cn_pog_to_num(): read a bytecode from the steam and advance the index
+** par_w: c3_w: can be 0, 2, 4
+** pog_y: c3_y*: a bytecode stream
+** ip_w: c3_w: an index into pog
+*/
+#define _cn_pog_to_num(par_w, pog_y, ip_w) (\
+ par_w == 4 ? _n_rewo(pog_y, &ip_w): \
+ par_w == 2 ? _n_resh(pog_y, &ip_w): \
+ pog_y[ip_w++])
+
+/* _cn_etch_bytecode(): render a nock program as string of bytecodes
+** fol: a nock formula to compile and render
+** returns: a u3i_string noun of the rendered bytecode
+*/
+u3_noun
+_cn_etch_bytecode(u3_noun fol) {
+ u3n_prog* pog_u = _n_bite(fol);
+ c3_y* pog_y = pog_u->byc_u.ops_y;
+ c3_w len_w = pog_u->byc_u.len_w;
+ c3_w ip_w=0, num_w=0, bop_w=0, dex_w=0;
+ c3_w len_c = 2; // closing "}", null terminator
+ // set par_w (parameter flag) to an invalid value,
+ // so we can break imeadately if needed
+ c3_w par_w = 5;
+ // lets count the chars in this string
+ while ( ip_w < len_w ) {
+ par_w = _n_arg(pog_y[ip_w]);
+ bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name
+ dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument
+ len_c += 5; // a leading space, and opcode name
+ if (par_w > 0) { // if pair: "[bytecode arg]" else "bytecode"
+ len_c += 3; // "[", space between opcode & arg, "]"
+ if ( dex_w ) len_c += 2; // 'i:'
+ len_c += _cn_intlen( // length of the bytecode argument
+ _cn_pog_to_num(par_w, pog_y, ip_w)
+ );
+ }
+ }
+ // reset so we can loop again
+ ip_w=0, num_w=0, bop_w=0, dex_w=0, par_w=5;
+ // init our string, and give it a trailing null
+ c3_c str_c[len_c];
+ str_c[0] = 0;
+ // lets print this string
+ while ( ip_w < len_w ) {
+ par_w = _n_arg(pog_y[ip_w]);
+ bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name
+ dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument
+ strcat(str_c, " "); // leading space
+ if (par_w > 0) strcat(str_c, "["); // add "[" if the opcode pairs
+ strncat(str_c, opcode_names[bop_w], 4); // add the opcode name
+ if (par_w > 0) { // finish the pair
+ strcat(str_c, " "); // add the space between byt and arg
+ if ( dex_w ) strcat(str_c, "i:"); // indexed args are labeled as "index of arg"
+ num_w = _cn_pog_to_num(par_w, pog_y, ip_w); // the bytecode argument
+ if (num_w == 0) { //
+ strcat(str_c, "0"); // handle a literal zero
+ } //
+ else { //
+ c3_w x = 0; //
+ for (x = _cn_intlen(num_w); x > 0; x--) { //
+ strcat(str_c, "_"); // prefill the buffer
+ } //
+ c3_w f = strlen(str_c)-1; // get the index of the last prefill
+ while (num_w > 0) { // stringify number in LSB order
+ str_c[f--] = (num_w%10)+'0'; // .. stringify the tail of num into tail of buf
+ num_w /= 10; // .. turncate num by one digit
+ } //
+ } //
+ strcat(str_c, "]"); // add the closing brace
+ }
+ }
+ // replace the first leading space and append the last char to the string
+ str_c[0] = '{';
+ strcat(str_c, "}");
+ _cn_prog_free(pog_u);
+ return u3i_string(str_c);
+}
+
+
+/* _n_hilt_fore(): literal (atomic) dynamic hint, before formula evaluation.
+** hin: [hint-atom, formula]. TRANSFER
+** bus: subject. RETAIN
+** out: token for _n_hilt_hind(); convention:
+** [hint-atom] or [hint-atom data], ~ if unused.
+**
+** any hints herein must be whitelisted in _n_burn().
+*/
+static c3_o
+_n_hilt_fore(u3_noun hin, u3_noun bus, u3_noun* out)
+{
+ u3_noun tag, fol;
+ u3x_cell(hin, &tag, &fol);
+
+ switch ( tag ) {
+ case c3__cash: {
+ u3_atom har = u3i_word(u3h_count(u3R->cax.har_p));
+ u3h_discount(u3R->cax.har_p);
+ u3_atom per = u3i_word(u3h_count(u3R->cax.per_p));
+ u3h_discount(u3R->cax.per_p);
+ *out = u3i_cell(tag, u3i_cell(har, per));
+ } break;
+
+ case c3__bout: {
+ u3_atom now = u3i_chub(u3t_trace_time());
+ *out = u3i_cell(tag, now);
+ } break;
+
+ case c3__nara : {
+ u3t_slog_nara(0);
+ *out = u3_nul;
+ } break;
+
+ case c3__hela : {
+ u3t_slog_hela(0);
+ *out = u3_nul;
+ } break;
+
+ case c3__xray : {
+ u3t_slog(u3nc(0, _cn_etch_bytecode(fol)));
+ *out = u3_nul;
+ } break;
+
+ case c3__meme : {
+ u3t_slog(u3nc(0, u3t_etch_meme(0)));
+ *out = u3_nul;
+ } break;
+
+ default: {
+ *out = u3_nul;
+ } break;
+ }
+
+ u3z(hin);
+ return c3y;
+}
+
+/* _n_hilt_hind(): literal (atomic) dynamic hint, after formula evaluation.
+** tok: token from _n_hilt_fore(). TRANSFER
+** pro: product of formula evaluation. RETAIN
+*/
+static void
+_n_hilt_hind(u3_noun tok, u3_noun pro)
+{
+ u3_noun p_tok, q_tok, r_tok;
+ if ( (c3y == u3r_cell(tok, &p_tok, &q_tok)) && (c3__bout == p_tok) ) {
+ u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(q_tok));
+ c3_c str_c[64];
+ u3a_print_time(str_c, "took", u3r_chub(0, delta));
+ u3t_slog(u3nc(0, u3i_string(str_c)));
+ u3z(delta);
+ }
+ else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) &&
+ (c3__cash == p_tok) ) {
+ c3_c str_c[4096];
+
+ u3_atom har = u3i_word(u3h_count(u3R->cax.har_p));
+ u3h_discount(u3R->cax.har_p);
+ u3_atom har_delta = u3ka_sub(har, u3k(q_tok));
+ u3a_print_memory_str(str_c, "ephemeral cache",
+ u3r_word(0, har_delta));
+ u3t_slog(u3nc(0, u3i_string(str_c)));
+
+ u3_atom per = u3i_word(u3h_count(u3R->cax.per_p));
+ u3h_discount(u3R->cax.per_p);
+ u3_atom per_delta = u3ka_sub(per, u3k(r_tok));
+ u3a_print_memory_str(str_c, "persistent cache",
+ u3r_word(0, per_delta));
+ u3t_slog(u3nc(0, u3i_string(str_c)));
+
+ u3z(har_delta);
+ u3z(per_delta);
+ }
+ else {
+ u3_assert( u3_nul == tok );
+ }
+
+ u3z(tok);
+}
+
+/* _n_hint_fore(): arbitrary dynamic hint, before formula evaluation
+** hin: [hint-atom, formula]. TRANSFER
+** bus: subject. RETAIN
+** clu: product of the hint-formula. TRANSFER
+** also, token for _n_hilt_hind(); convention:
+** [hint-atom] or [hint-atom data], ~ if unused.
+**
+** any hints herein must be whitelisted in _n_burn().
+*/
+static c3_o
+_n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu)
+{
+ u3_noun tag, fol;
+ u3x_cell(hin, &tag, &fol);
+
+ switch ( tag ) {
+ case c3__bout: {
+ u3_atom now = u3i_chub(u3t_trace_time());
+ *clu = u3nt(u3k(tag), *clu, now);
+ } break;
+
+ case c3__spin: {
+ u3t_sstack_push(*clu);
+ *clu = c3__spin;
+ } break;
+
+ case c3__nara: {
+ u3_noun pri, tan;
+ if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
+ c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0;
+ u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan));
+ u3t_slog_nara(pri_l);
+ }
+ u3z(*clu);
+ *clu = u3_nul;
+ } break;
+
+ case c3__hela: {
+ u3_noun pri, tan;
+ if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
+ c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0;
+ u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan));
+ u3t_slog_hela(pri_l);
+ }
+ u3z(*clu);
+ *clu = u3_nul;
+ } break;
+
+ case c3__xray : {
+ u3_noun pri, tan;
+ if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
+ c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0;
+ u3t_slog_cap(pri_l, u3k(tan), _cn_etch_bytecode(fol));
+ }
+ u3z(*clu);
+ *clu = u3_nul;
+ } break;
+
+ case c3__meme : {
+ u3_noun pri, tan;
+ if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
+ c3_l mod_l = c3y == u3a_is_cat(pri) ? pri : 0;
+ // replace with better str fmt
+ u3t_slog_cap(1, u3k(tan), u3t_etch_meme(mod_l));
+ }
+ u3z(*clu);
+ *clu = u3_nul;
+ } break;
+
+ default: {
+ u3z(*clu);
+ *clu = u3_nul;
+ } break;
+ }
+
+ u3z(hin);
+ return c3y;
+}
+
+/* _n_hint_hind(): arbitrary dynamic hint, after formula evaluation.
+** tok: token from _n_hint_fore(). TRANSFER
+** pro: product of formula evaluation. RETAIN
+*/
+static void
+_n_hint_hind(u3_noun tok, u3_noun pro)
+{
+ u3_noun p_tok, q_tok, r_tok;
+ if ( c3__spin == tok ) {
+ u3t_sstack_pop();
+ }
+ else if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) {
+ // get the microseconds elapsed
+ u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(r_tok));
+
+ // unpack q_tok to get the priority integer and the tank
+ // p_q_tok is the priority, q_q_tok is the tank we will work with
+ u3_noun p_q_tok, q_q_tok;
+ u3_assert(c3y == u3r_cell(q_tok, &p_q_tok, &q_q_tok));
+
+ // format the timing report
+ c3_c str_c[64];
+ u3a_print_time(str_c, "took", u3r_chub(0, delta));
+
+ // join the timing report with the original tank from q_q_tok like so:
+ // "q_q_tok: report"
+ // prepend the priority to form a cell of the same shape q_tok
+ // send this to ut3_slog so that it can be logged out
+ c3_l pri_l = c3y == u3a_is_cat(p_q_tok) ? p_q_tok : 0;
+ u3t_slog_cap(pri_l, u3k(q_q_tok), u3i_string(str_c));
+ u3z(delta);
+ }
+ else {
+ u3_assert( u3_nul == tok );
+ }
+
+ u3z(tok);
+}
+
+/* _n_kick(): stop tracing noc and kick a u3j_site.
+ */
+static u3_weak
+_n_kick(u3_noun cor, u3j_site* sit_u)
+{
+ u3_weak pro;
+ u3t_off(noc_o);
+ pro = u3j_site_kick(cor, sit_u);
+ u3t_on(noc_o);
+ return pro;
+}
+
+/* _n_kale(): bail(exit) if not cell
+ */
+static inline u3_noun
+_n_kale(u3_noun a)
+{
+ if ( c3n == u3du(a) ) {
+ u3m_bail(c3__exit);
+ }
+ return a;
+}
+
+typedef struct __attribute__((__packed__)) {
+ u3n_prog* pog_u;
+ c3_w ip_w;
+} burnframe;
+
+/* _n_burn(): pog: program
+ * bus: subject (TRANSFER)
+ * mov: -1 north, 1 south
+ * off: 0 north, -1 south
+ */
+static u3_noun
+_n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off)
+{
+
+ // Opcode jump table. Define X to select the opcode computed goto from
+ // OPCODES.
+# define X(opcode, name, indirect_jump) indirect_jump
+ static void* lab[] = { OPCODES };
+# undef X
+
+ u3j_site* sit_u;
+ u3j_rite* rit_u;
+ u3n_memo* mem_u;
+ c3_y *pog = pog_u->byc_u.ops_y;
+ c3_w sip_w, ip_w = 0;
+ u3_noun* top;
+ u3_noun x, o;
+ u3p(void) empty;
+ burnframe* fam;
+
+ empty = u3R->cap_p;
+ _n_push(mov, off, bus);
+
+#ifdef U3_CPU_DEBUG
+ u3R->pro.nox_d += 1;
+#endif
+#ifdef VERBOSE_BYTECODE
+ #define BURN() fprintf(stderr, "%s ", opcode_names[pog[ip_w]]); goto *lab[pog[ip_w++]]
+#else
+ #define BURN() goto *lab[pog[ip_w++]]
+#endif
+ BURN();
+ {
+ do_halt: // [product ...burnframes...]
+ x = _n_pep(mov, off);
+#ifdef VERBOSE_BYTECODE
+ fprintf(stderr, "return\r\n");
+#endif
+ if ( empty == u3R->cap_p ) {
+ return x;
+ }
+ else {
+ fam = u3to(burnframe, u3R->cap_p) + off;
+ pog_u = fam->pog_u;
+ pog = pog_u->byc_u.ops_y;
+ ip_w = fam->ip_w;
+
+ u3R->cap_p = u3of(burnframe, fam - (mov+off));
+ _n_push(mov, off, x);
+#ifdef VERBOSE_BYTECODE
+ _n_print_byc(pog, ip_w);
+#endif
+ BURN();
+ }
+
+ do_bail:
+ u3m_bail(c3__exit);
+ return u3_none;
+
+ do_copy:
+ top = _n_peek(off);
+ _n_push(mov, off, u3k(*top));
+ BURN();
+
+ do_swap:
+ _n_swap(mov, off);
+ BURN();
+
+ do_toss:
+ _n_toss(mov, off);
+ BURN();
+
+ do_auto: // [tel bus hed]
+ x = _n_pep(mov, off); // [bus hed]
+ top = _n_swap(mov, off); // [hed bus]
+ *top = u3nc(*top, x); // [pro bus]
+ BURN();
+
+ do_ault: // [tel hed]
+ x = _n_pep(mov, off); // [hed]
+ top = _n_peek(off);
+ *top = u3nc(*top, x); // [pro]
+ BURN();
+
+ do_snoc: // [hed tel]
+ x = _n_pep(mov, off);
+ top = _n_peek(off);
+ _n_push(mov, off, u3nc(x, u3k(*top)));
+ BURN();
+
+ do_snol:
+ x = _n_pep(mov, off);
+ top = _n_peek(off);
+ *top = u3nc(x, *top);
+ BURN();
+
+ do_head:
+ top = _n_peek(off);
+ _n_push(mov, off, u3k(u3h(_n_kale(*top))));
+ BURN();
+
+ do_held:
+ top = _n_peek(off);
+ o = _n_kale(*top);
+ *top = u3k(u3h(o));
+ u3z(o);
+ BURN();
+
+ do_tail:
+ top = _n_peek(off);
+ _n_push(mov, off, u3k(u3t(_n_kale(*top))));
+ BURN();
+
+ do_tall:
+ top = _n_peek(off);
+ o = _n_kale(*top);
+ *top = u3k(u3t(o));
+ u3z(o);
+ BURN();
+
+ do_fisk:
+ x = pog_u->lit_u.non[_n_resh(pog, &ip_w)];
+ goto frag_in;
+
+ do_fibk:
+ x = pog_u->lit_u.non[pog[ip_w++]];
+ goto frag_in;
+
+ do_fask:
+ x = _n_resh(pog, &ip_w);
+ goto frag_in;
+
+ do_fabk:
+ x = pog[ip_w++];
+ frag_in:
+ top = _n_peek(off);
+ _n_push(mov, off, u3k(u3x_at(x, *top)));
+ BURN();
+
+ do_fisl:
+ x = pog_u->lit_u.non[_n_resh(pog, &ip_w)];
+ goto flag_in;
+
+ do_fibl:
+ x = pog_u->lit_u.non[pog[ip_w++]];
+ goto flag_in;
+
+ do_fasl:
+ x = _n_resh(pog, &ip_w);
+ goto flag_in;
+
+ do_fabl:
+ x = pog[ip_w++];
+ flag_in:
+ top = _n_peek(off);
+ o = *top;
+ *top = u3k(u3x_at(x, o));
+ u3z(o);
+ BURN();
+
+ do_lit0:
+ _n_push(mov, off, 0);
+ BURN();
+
+ do_lit1:
+ _n_push(mov, off, 1);
+ BURN();
+
+ do_litb:
+ _n_push(mov, off, pog[ip_w++]);
+ BURN();
+
+ do_lits:
+ _n_push(mov, off, _n_resh(pog, &ip_w));
+ BURN();
+
+ do_libk:
+ _n_push(mov, off, u3k(pog_u->lit_u.non[pog[ip_w++]]));
+ BURN();
+
+ do_lisk:
+ _n_push(mov, off, u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)]));
+ BURN();
+
+ do_lil1:
+ x = 1;
+ goto lil_in;
+
+ do_lilb:
+ x = pog[ip_w++];
+ goto lil_in;
+
+ do_lils:
+ x = _n_resh(pog, &ip_w);
+ goto lil_in;
+
+ do_libl:
+ x = u3k(pog_u->lit_u.non[pog[ip_w++]]);
+ goto lil_in;
+
+ do_lisl:
+ x = u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)]);
+ goto lil_in;
+
+ do_lil0:
+ x = 0;
+ lil_in:
+ top = _n_peek(off);
+ u3z(*top);
+ *top = x;
+ BURN();
+
+ do_noct: // [fol bus]
+ o = _n_pep(mov, off); // [bus]
+ goto nock_out;
+
+ do_nolk: // [fol bus]
+ o = _n_pep(mov, off); // [bus]
+ goto nock_in;
+
+ do_nock: // [fol old bus]
+ o = _n_pep(mov, off); // [old bus]
+ _n_swap(mov, off); // [bus old]
+ nock_in:
+ x = _n_pep(mov, off);
+ fam = u3to(burnframe, u3R->cap_p) + off + mov;
+ u3R->cap_p = u3of(burnframe, fam - off);
+ fam->ip_w = ip_w;
+ fam->pog_u = pog_u;
+ _n_push(mov, off, x);
+ nock_out:
+ pog_u = _n_find(u3_nul, o);
+ pog = pog_u->byc_u.ops_y;
+ ip_w = 0;
+#ifdef U3_CPU_DEBUG
+ u3R->pro.nox_d += 1;
+#endif
+#ifdef VERBOSE_BYTECODE
+ fprintf(stderr, "\r\nnock jump: %u\r\n", o);
+ _n_print_byc(pog, ip_w);
+#endif
+ u3z(o);
+ BURN();
+
+ do_deep:
+ top = _n_peek(off);
+ o = *top;
+ *top = u3du(o);
+ u3z(o);
+ BURN();
+
+ do_bump:
+ top = _n_peek(off);
+ *top = u3i_vint(*top);
+ BURN();
+
+ do_sam0:
+ top = _n_peek(off);
+ if ( *top == 0 ) {
+ *top = c3y;
+ }
+ else {
+ u3z(*top);
+ *top = c3n;
+ }
+ BURN();
+
+ do_sam1:
+ top = _n_peek(off);
+ if ( *top == 1 ) {
+ *top = c3y;
+ }
+ else {
+ u3z(*top);
+ *top = c3n;
+ }
+ BURN();
+
+ do_samb:
+ top = _n_peek(off);
+ if ( *top == pog[ip_w++] ) {
+ *top = c3y;
+ }
+ else {
+ u3z(*top);
+ *top = c3n;
+ }
+ BURN();
+
+ do_sams:
+ top = _n_peek(off);
+ if ( *top == _n_resh(pog, &ip_w) ) {
+ *top = c3y;
+ }
+ else {
+ u3z(*top);
+ *top = c3n;
+ }
+ BURN();
+
+ do_sans:
+ x = pog_u->lit_u.non[_n_resh(pog, &ip_w)];
+ goto samn_in;
+ do_sanb:
+ x = pog_u->lit_u.non[pog[ip_w++]];
+ samn_in:
+ top = _n_peek(off);
+ o = *top;
+ *top = u3r_sing(o, x);
+ u3z(o);
+ BURN();
+
+ do_same:
+ x = _n_pep(mov, off);
+ _n_swap(mov, off);
+ goto same_in;
+
+ do_salm:
+ x = _n_pep(mov, off);
+ goto same_in;
+
+ same_in:
+ top = _n_peek(off);
+ o = *top;
+ *top = u3r_sing(x, o);
+ u3z(o);
+ u3z(x);
+ BURN();
+
+ do_samc:
+ top = _n_peek(off);
+ o = *top;
+ *top = u3r_sing(u3h(o), u3t(o));
+ u3z(o);
+ BURN();
+
+ do_sbip:
+ sip_w = pog[ip_w++];
+ ip_w += sip_w;
+ BURN();
+
+ do_sips:
+ sip_w = _n_resh(pog, &ip_w);
+ ip_w += sip_w;
+ BURN();
+
+ do_swip:
+ sip_w = _n_rewo(pog, &ip_w);
+ ip_w += sip_w;
+ BURN();
+
+ do_swin:
+ sip_w = _n_rewo(pog, &ip_w);
+ goto skin_in;
+
+ do_sins:
+ sip_w = _n_resh(pog, &ip_w);
+ goto skin_in;
+
+ do_sbin:
+ sip_w = pog[ip_w++];
+ skin_in:
+ x = _n_pep(mov, off);
+ if ( c3n == x ) {
+ ip_w += sip_w;
+ }
+ else if ( c3y != x ) {
+ u3m_bail(c3__exit);
+ return u3_none;
+ }
+ BURN();
+
+ do_kics:
+ x = _n_resh(pog, &ip_w);
+ goto kick_in;
+
+ do_kicb:
+ x = pog[ip_w++];
+ kick_in:
+ sit_u = &(pog_u->cal_u.sit_u[x]);
+ top = _n_peek(off);
+ o = *top;
+ *top = _n_kick(o, sit_u);
+ if ( u3_none == *top ) {
+ _n_pop(mov);
+
+ fam = u3to(burnframe, u3R->cap_p) + off + mov;
+ u3R->cap_p = u3of(burnframe, fam - off);
+ fam->ip_w = ip_w;
+ fam->pog_u = pog_u;
+
+ pog_u = u3to(u3n_prog, sit_u->pog_p);
+ pog = pog_u->byc_u.ops_y;
+ ip_w = 0;
+#ifdef U3_CPU_DEBUG
+ u3R->pro.nox_d += 1;
+#endif
+#ifdef VERBOSE_BYTECODE
+ fprintf(stderr, "\r\nhead kick jump: %u, sp: %p\r\n", u3r_at(sit_u->axe, cor), top);
+ _n_print_byc(pog, ip_w);
+#endif
+ _n_push(mov, off, o);
+ }
+#ifdef VERBOSE_BYTECODE
+ else {
+ fprintf(stderr, "head jet\r\n");
+ }
+#endif
+ BURN();
+
+ do_tics:
+ x = _n_resh(pog, &ip_w);
+ goto tick_in;
+
+ do_ticb:
+ x = pog[ip_w++];
+ tick_in:
+ sit_u = &(pog_u->cal_u.sit_u[x]);
+ top = _n_peek(off);
+ o = *top;
+ *top = _n_kick(o, sit_u);
+ if ( u3_none == *top ) {
+ *top = o;
+ pog_u = u3to(u3n_prog, sit_u->pog_p);
+ pog = pog_u->byc_u.ops_y;
+ ip_w = 0;
+#ifdef U3_CPU_DEBUG
+ u3R->pro.nox_d += 1;
+#endif
+#ifdef VERBOSE_BYTECODE
+ fprintf(stderr, "\r\ntail kick jump: %u, sp: %p\r\n", u3x_at(sit_u->axe, o);, top);
+ _n_print_byc(pog, ip_w);
+#endif
+ }
+#ifdef VERBOSE_BYTECODE
+ else {
+ fprintf(stderr, "tail jet\r\n");
+ }
+#endif
+ BURN();
+
+ do_wils: // [gof ref]
+ o = _n_pep(mov,off); // [ref]
+ top = _n_peek(off);
+ goto wish_in;
+
+ do_wish: // [gof bus ref]
+ o = _n_pep(mov,off); // [bus ref]
+ top = _n_swap(mov, off); // [ref bus]
+ wish_in:
+ u3t_off(noc_o);
+ x = u3m_soft_esc(u3k(*top), u3k(o));
+ u3t_on(noc_o);
+
+ if ( c3n == u3du(x) ) {
+ u3m_bail(u3nc(1, o));
+ return u3_none;
+ }
+ else if ( c3n == u3du(u3t(x)) ) {
+ u3t_push(u3nt(c3__hunk, *top, o));
+ u3m_bail(c3__exit);
+ return u3_none;
+ }
+ else {
+ u3z(o);
+ u3z(*top);
+ *top = u3k(u3t(u3t(x)));
+ u3z(x);
+ BURN();
+ }
+
+ do_sush:
+ x = _n_resh(pog, &ip_w);
+ goto cush_in;
+
+ do_bush:
+ x = pog[ip_w++];
+ cush_in:
+ x = u3k(pog_u->lit_u.non[x]);
+ o = _n_pep(mov, off);
+ u3t_push(u3nc(x, o));
+ BURN();
+
+ do_drop:
+ u3t_drop();
+ BURN();
+
+ do_heck:
+ x = _n_pep(mov, off);
+ if ( c3y == u3ud(x) ) {
+ u3t_off(noc_o);
+ u3t_heck(x);
+ u3t_on(noc_o);
+ }
+ else {
+ u3z(x);
+ }
+ BURN();
+
+ do_slog:
+ x = _n_pep(mov, off);
+ if ( !(u3C.wag_w & u3o_quiet) ) {
+ u3t_off(noc_o);
+ u3t_slog(x);
+ u3t_on(noc_o);
+ }
+ else {
+ u3z(x);
+ }
+ BURN();
+
+
+ do_sast:
+ x = _n_resh(pog, &ip_w);
+ goto fast_in;
+
+ do_bast:
+ x = pog[ip_w++];
+ goto fast_in;
+
+ do_salt:
+ x = _n_resh(pog, &ip_w);
+ goto falt_in;
+ do_balt:
+ x = pog[ip_w++];
+ falt_in: // [pro clu]
+ o = _n_pep(mov, off); // [clu]
+ top = _n_peek(off);
+ goto fast_out;
+
+ fast_in: // [pro bus clu]
+ o = _n_pep(mov, off); // [bus clu]
+ top = _n_swap(mov, off); // [clu bus]
+ fast_out:
+ rit_u = &(pog_u->reg_u.rit_u[x]);
+ u3t_off(noc_o);
+ u3j_rite_mine(rit_u, *top, u3k(o));
+ u3t_on(noc_o);
+ *top = o;
+ BURN();
+
+ do_skis:
+ x = _n_resh(pog, &ip_w);
+ goto skim_in;
+
+ do_skib:
+ x = pog[ip_w++];
+ skim_in:
+ mem_u = &(pog_u->mem_u.sot_u[x]);
+ top = _n_peek(off);
+ x = u3k(*top);
+ goto skim_out;
+
+ do_slis:
+ x = _n_resh(pog, &ip_w);
+ goto slim_in;
+
+ do_slib:
+ x = pog[ip_w++];
+ slim_in:
+ mem_u = &(pog_u->mem_u.sot_u[x]);
+ x = _n_pep(mov, off);
+ skim_out:
+ o = u3k(mem_u->key);
+ x = u3nc(x, o);
+ o = u3z_find_m(mem_u->cid, 144 + c3__nock, x);
+ if ( u3_none == o ) {
+ _n_push(mov, off, u3nc(mem_u->cid, x));
+ _n_push(mov, off, u3k(u3h(x)));
+ }
+ else {
+ ip_w += mem_u->sip_l;
+ _n_push(mov, off, o);
+ u3z(x);
+ }
+ BURN();
+
+ do_save:
+ x = _n_pep(mov, off); // product
+ top = _n_peek(off);
+ o = *top;
+ if ( ( u3z_memo_toss == u3h(o) )
+ ? ( &(u3H->rod_u) != u3R )
+ : ( 0 == u3R->ski.gul ) ) { // prevents userspace from persistence
+ u3z_save_m(u3h(o), 144 + c3__nock, u3t(o), x);
+ }
+ // XX can we still print?
+ // else if ( u3z_memo_keep == u3h(o) ) {
+ // fprintf(stderr, "\r\nnock: userspace can't save to persistent cache\r\n");
+ // }
+ *top = x;
+ u3z(o);
+ BURN();
+
+ do_hilb:
+ x = pog[ip_w++];
+ goto hilt_fore_in;
+
+ do_hils:
+ x = _n_resh(pog, &ip_w);
+ hilt_fore_in:
+ x = u3k(pog_u->lit_u.non[x]);
+ top = _n_peek(off); // bus
+ x = _n_hilt_fore(x, *top, &o);
+ _n_push(mov, off, o);
+ _n_swap(mov, off); // bus
+ _n_push(mov, off, x); // shortcircuit if c3n
+ BURN();
+
+ do_hinb:
+ x = pog[ip_w++];
+ goto hint_fore_in;
+
+ do_hins:
+ x = _n_resh(pog, &ip_w);
+ hint_fore_in: // [clu bus]
+ x = u3k(pog_u->lit_u.non[x]);
+ o = _n_pep(mov, off); // [bus]
+ top = _n_peek(off);
+ x = _n_hint_fore(x, *top, &o);
+ _n_push(mov, off, o); // [tok bus]
+ _n_swap(mov, off); // [bus tok]
+ _n_push(mov, off, x); // [kip bus tok]
+ BURN();
+
+ do_hilk: // [pro bus tok]
+ x = _n_pep(mov, off); // [bus tok]
+ _n_swap(mov, off); // [tok bus]
+ o = _n_pep(mov, off); // [bus]
+ _n_push(mov, off, x); // [pro bus]
+ _n_hilt_hind(o, x);
+ BURN();
+
+ do_hill: // [pro tok]
+ top = _n_swap(mov, off); // [tok pro]
+ o = _n_pep(mov, off); // [pro]
+ top = _n_peek(off);
+ _n_hilt_hind(o, *top);
+ BURN();
+
+ do_hink: // [pro bus tok]
+ x = _n_pep(mov, off); // [bus tok]
+ _n_swap(mov, off); // [tok bus]
+ o = _n_pep(mov, off); // [bus]
+ _n_push(mov, off, x); // [pro bus]
+ _n_hint_hind(o, x);
+ BURN();
+
+ do_hinl: // [pro tok]
+ top = _n_swap(mov, off); // [tok pro]
+ o = _n_pep(mov, off); // [pro]
+ top = _n_peek(off);
+ _n_hint_hind(o, *top);
+ BURN();
+
+ do_kuth:
+ x = _n_pep(mov, off);
+ top = _n_swap(mov, off);
+ goto muth_in;
+ do_muth:
+ x = _n_pep(mov, off);
+ top = _n_peek(off);
+ muth_in:
+ o = *top;
+ *top = u3nc(x, u3k(u3t(o)));
+ u3z(o);
+ BURN();
+
+ do_kutt:
+ x = _n_pep(mov, off);
+ top = _n_swap(mov, off);
+ goto mutt_in;
+ do_mutt:
+ x = _n_pep(mov, off);
+ top = _n_peek(off);
+ mutt_in:
+ o = *top;
+ *top = u3nc(u3k(u3h(o)), x);
+ u3z(o);
+ BURN();
+
+ do_kusm:
+ x = _n_pep(mov, off);
+ top = _n_swap(mov, off);
+ goto musm_in;
+ do_musm:
+ x = _n_pep(mov, off);
+ top = _n_peek(off);
+ musm_in:
+ o = *top;
+ *top = u3nt(u3k(u3h(o)), x, u3k(u3t(u3t(o))));
+ u3z(o);
+ BURN();
+
+ do_kitb:
+ x = pog_u->lit_u.non[pog[ip_w++]];
+ goto kut_in;
+
+ do_kits:
+ x = pog_u->lit_u.non[_n_resh(pog, &ip_w)];
+ goto kut_in;
+
+ do_kuts:
+ x = _n_resh(pog, &ip_w);
+ goto kut_in;
+
+ do_kutb:
+ x = pog[ip_w++];
+ kut_in:
+ o = _n_pep(mov, off);
+ top = _n_swap(mov, off);
+ goto edit_in;
+
+ do_mitb:
+ x = pog_u->lit_u.non[pog[ip_w++]];
+ goto mut_in;
+
+ do_mits:
+ x = pog_u->lit_u.non[_n_resh(pog, &ip_w)];
+ goto mut_in;
+
+ do_muts:
+ x = _n_resh(pog, &ip_w);
+ goto mut_in;
+
+ do_mutb:
+ x = pog[ip_w++];
+ mut_in:
+ o = _n_pep(mov, off);
+ top = _n_peek(off);
+ edit_in:
+ *top = u3i_edit(*top, x, o);
+ BURN();
+ }
+}
+
+/* _n_burn_out(): execute u3n_prog with bus as subject.
+ */
+static u3_noun
+_n_burn_out(u3_noun bus, u3n_prog* pog_u)
+{
+ c3_ys mov, off;
+ if ( c3y == u3a_is_north(u3R) ) {
+ mov = -1;
+ off = 0;
+ }
+ else {
+ mov = 1;
+ off = -1;
+ }
+ return _n_burn(pog_u, bus, mov, off);
+}
+
+/* u3n_burn(): execute u3n_prog with bus as subject.
+ */
+u3_noun
+u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus)
+{
+ u3_noun pro;
+ u3t_on(noc_o);
+ pro = _n_burn_out(bus, u3to(u3n_prog, pog_p));
+ u3t_off(noc_o);
+ return pro;
+}
+
+/* _n_burn_on(): produce .*(bus fol) with bytecode interpreter
+ */
+static u3_noun
+_n_burn_on(u3_noun bus, u3_noun fol)
+{
+ u3n_prog* pog_u = _n_find(u3_nul, fol);
+
+ u3z(fol);
+ return _n_burn_out(bus, pog_u);
+}
+
+/* u3n_nock_on(): produce .*(bus fol). Do not virtualize.
+*/
+u3_noun
+u3n_nock_on(u3_noun bus, u3_noun fol)
+{
+ u3_noun pro;
+
+ u3t_on(noc_o);
+#if 0
+ pro = _n_nock_on(bus, fol);
+#else
+ pro = _n_burn_on(bus, fol);
+#endif
+ u3t_off(noc_o);
+
+ return pro;
+}
+
+/* _cn_take_prog_dat(): take references from junior u3n_prog.
+*/
+static void
+_cn_take_prog_dat(u3n_prog* dst_u, u3n_prog* src_u)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) {
+ dst_u->lit_u.non[i_w] = u3a_take(src_u->lit_u.non[i_w]);
+ }
+
+ for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) {
+ u3n_memo* emo_u = &(src_u->mem_u.sot_u[i_w]);
+ u3n_memo* ome_u = &(dst_u->mem_u.sot_u[i_w]);
+ ome_u->sip_l = emo_u->sip_l;
+ ome_u->key = u3a_take(emo_u->key);
+ ome_u->cid = emo_u->cid;
+ }
+
+ for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) {
+ u3j_site_take(&(dst_u->cal_u.sit_u[i_w]),
+ &(src_u->cal_u.sit_u[i_w]));
+ }
+
+ for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) {
+ u3j_rite_take(&(dst_u->reg_u.rit_u[i_w]),
+ &(src_u->reg_u.rit_u[i_w]));
+ }
+}
+
+/* _cn_take_prog_cb(): u3h_take_with cb for taking junior u3n_prog's.
+*/
+static u3p(u3n_prog)
+_cn_take_prog_cb(c3_w pog_w)
+{
+ u3n_prog* pog_u = _cn_to_prog(pog_w);
+ u3n_prog* gop_u;
+
+ if ( c3y == pog_u->byc_u.own_o ) {
+ c3_w pad_w = (8 - pog_u->byc_u.len_w % 8) % 8;
+ gop_u = _n_prog_new(pog_u->byc_u.len_w,
+ pog_u->cal_u.len_w,
+ pog_u->reg_u.len_w,
+ pog_u->lit_u.len_w,
+ pog_u->mem_u.len_w);
+ memcpy(gop_u->byc_u.ops_y, pog_u->byc_u.ops_y, pog_u->byc_u.len_w + pad_w);
+ }
+ else {
+ gop_u = _n_prog_old(pog_u);
+ }
+
+ _cn_take_prog_dat(gop_u, pog_u);
+ // _n_prog_take_dat(gop_u, pog_u, c3n);
+
+ return _cn_of_prog(gop_u);
+}
+
+/* u3n_take(): copy junior bytecode state.
+*/
+u3p(u3h_root)
+u3n_take(u3p(u3h_root) har_p)
+{
+ return u3h_take_with(har_p, _cn_take_prog_cb);
+}
+
+/* _cn_merge_prog_dat(): copy references from src_u u3n_prog to dst_u.
+*/
+static void
+_cn_merge_prog_dat(u3n_prog* dst_u, u3n_prog* src_u)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) {
+ u3z(dst_u->lit_u.non[i_w]);
+ dst_u->lit_u.non[i_w] = src_u->lit_u.non[i_w];
+ }
+
+ for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) {
+ u3n_memo* emo_u = &(dst_u->mem_u.sot_u[i_w]);
+ u3n_memo* ome_u = &(src_u->mem_u.sot_u[i_w]);
+ u3z(emo_u->key);
+ emo_u->sip_l = ome_u->sip_l;
+ emo_u->key = ome_u->key;
+ emo_u->cid = ome_u->cid;
+ }
+
+ for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) {
+ u3j_site_merge(&(dst_u->cal_u.sit_u[i_w]),
+ &(src_u->cal_u.sit_u[i_w]));
+ }
+
+ for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) {
+ u3j_rite_merge(&(dst_u->reg_u.rit_u[i_w]),
+ &(src_u->reg_u.rit_u[i_w]));
+ }
+}
+
+/* _cn_merge_prog_cb(): u3h_walk_with cb for integrating taken u3n_prog's.
+*/
+static void
+_cn_merge_prog_cb(u3_noun kev, void* wit)
+{
+ u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit;
+ u3n_prog* pog_u;
+ u3_weak got;
+ u3_noun key;
+ c3_w pog_w;
+ u3x_cell(kev, &key, &pog_w);
+
+ pog_u = _cn_to_prog(pog_w);
+ got = u3h_git(har_p, key);
+
+ if ( u3_none != got ) {
+ u3n_prog* sep_u = _cn_to_prog(got);
+ _cn_merge_prog_dat(sep_u, pog_u);
+ u3a_free(pog_u);
+ pog_u = sep_u;
+ }
+
+ u3h_put(har_p, key, _cn_of_prog(pog_u));
+}
+
+/* u3n_reap(): promote bytecode state.
+*/
+void
+u3n_reap(u3p(u3h_root) har_p)
+{
+ u3h_walk_with(har_p, _cn_merge_prog_cb, &u3R->byc.har_p);
+ // NB *not* u3n_free, _cn_merge_prog_cb() transfers u3n_prog's
+ u3h_free(har_p);
+}
+
+/* _n_ream(): ream program call sites
+*/
+void
+_n_ream(u3_noun kev)
+{
+ u3n_prog* pog_u = _cn_to_prog(u3t(kev));
+
+ c3_w pad_w = (8 - pog_u->byc_u.len_w % 8) % 8;
+ c3_w pod_w = pog_u->lit_u.len_w % 2;
+ c3_w ped_w = pog_u->mem_u.len_w % 2;
+ // fix up pointers for loom portability
+ pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u);
+ pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w + pad_w);
+ pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w + pod_w);
+ pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w + ped_w);
+ pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w);
+
+ for ( c3_w i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) {
+ u3j_site_ream(&(pog_u->cal_u.sit_u[i_w]));
+ }
+}
+
+/* u3n_ream(): refresh after restoring from checkpoint.
+*/
+void
+u3n_ream()
+{
+ u3_assert(u3R == &(u3H->rod_u));
+ u3h_walk(u3R->byc.har_p, _n_ream);
+}
+
+/* _n_prog_mark(): mark program for gc.
+*/
+static c3_w
+_n_prog_mark(u3n_prog* pog_u)
+{
+ c3_w i_w, tot_w = u3a_mark_mptr(pog_u);
+
+ for ( i_w = 0; i_w < pog_u->lit_u.len_w; ++i_w ) {
+ tot_w += u3a_mark_noun(pog_u->lit_u.non[i_w]);
+ }
+
+ for ( i_w = 0; i_w < pog_u->mem_u.len_w; ++i_w ) {
+ tot_w += u3a_mark_noun(pog_u->mem_u.sot_u[i_w].key);
+ }
+
+ for ( i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) {
+ tot_w += u3j_site_mark(&(pog_u->cal_u.sit_u[i_w]));
+ }
+
+ for ( i_w = 0; i_w < pog_u->reg_u.len_w; ++i_w ) {
+ tot_w += u3j_rite_mark(&(pog_u->reg_u.rit_u[i_w]));
+ }
+
+ return tot_w;
+}
+
+/* _n_bam(): u3h_walk_with helper for u3n_mark
+ */
+static void
+_n_bam(u3_noun kev, void* dat)
+{
+ u3n_prog* pog = _cn_to_prog(u3t(kev));
+ c3_w* bam_w = dat;
+
+ *bam_w += _n_prog_mark(pog);
+}
+
+/* u3n_mark(): mark the bytecode cache for gc.
+ */
+u3m_quac*
+u3n_mark()
+{
+ u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 3);
+
+ qua_u[0] = c3_calloc(sizeof(*qua_u[0]));
+ qua_u[0]->nam_c = strdup("bytecode programs");
+
+ u3p(u3h_root) har_p = u3R->byc.har_p;
+ u3h_walk_with(har_p, _n_bam, &qua_u[0]->siz_w);
+ qua_u[0]->siz_w = qua_u[0]->siz_w * 4;
+
+ qua_u[1] = c3_calloc(sizeof(*qua_u[1]));
+ qua_u[1]->nam_c = strdup("bytecode cache");
+ qua_u[1]->siz_w = u3h_mark(har_p) * 4;
+
+ qua_u[2] = NULL;
+
+ u3m_quac* tot_u = c3_malloc(sizeof(*tot_u));
+ tot_u->nam_c = strdup("total nock stuff");
+ tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w;
+ tot_u->qua_u = qua_u;
+
+ return tot_u;
+}
+
+/* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3n_reclaim(void)
+{
+ // clear the bytecode cache
+ //
+ // We can't just u3h_free() -- the value is a post to a u3n_prog.
+ // Note that the hank cache *must* also be freed (in u3j_reclaim())
+ //
+ u3n_free();
+ u3R->byc.har_p = u3h_new();
+}
+
+/* u3n_rewrite_compact(): rewrite the bytecode cache for compaction.
+ *
+ * NB: u3R->byc.har_p *must* be cleared (currently via u3n_reclaim above),
+ * since it contains things that look like nouns but aren't.
+ * Specifically, it contains "cells" where the tail is a
+ * pointer to a u3a_malloc'ed block that contains loom pointers.
+ *
+ * You should be able to walk this with u3h_walk and rewrite the
+ * pointers, but you need to be careful to handle that u3a_malloc
+ * pointers can't be turned into a box by stepping back two words. You
+ * must step back one word to get the padding, step then step back that
+ * many more words (plus one?).
+ */
+void
+u3n_rewrite_compact()
+{
+ u3h_relocate(&(u3R->byc.har_p));
+}
+
+
+/* _n_feb(): u3h_walk helper for u3n_free
+ */
+static void
+_n_feb(u3_noun kev)
+{
+ _cn_prog_free(_cn_to_prog(u3t(kev)));
+}
+
+/* u3n_free(): free bytecode cache
+ */
+void
+u3n_free()
+{
+ u3p(u3h_root) har_p = u3R->byc.har_p;
+ u3h_walk(har_p, _n_feb);
+ u3h_free(har_p);
+}
+
+/* u3n_kick_on(): fire `gat` without changing the sample.
+*/
+u3_noun
+u3n_kick_on(u3_noun gat)
+{
+ return u3j_kink(gat, 2);
+}
+
+c3_w exc_w;
+
+/* u3n_slam_on(): produce (gat sam).
+*/
+u3_noun
+u3n_slam_on(u3_noun gat, u3_noun sam)
+{
+ u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat)))));
+
+#if 0
+ if ( &u3H->rod_u == u3R ) {
+ if ( exc_w == 1 ) {
+ u3_assert(0);
+ }
+ exc_w++;
+ }
+#endif
+ u3z(gat);
+ return u3n_kick_on(cor);
+}
+
+/* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace.
+*/
+u3_noun
+u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol)
+{
+ return u3m_soft_run(gul, u3n_nock_on, bus, fol);
+}
+
+/* u3n_slam_et(): produce (gat sam), as ++toon, in namespace.
+*/
+u3_noun
+u3n_slam_et(u3_noun gul, u3_noun gat, u3_noun sam)
+{
+ return u3m_soft_run(gul, u3n_slam_on, gat, sam);
+}
+
+/* u3n_nock_an(): as nock_et(), but with the scry handler that always blocks.
+*/
+u3_noun
+u3n_nock_an(u3_noun bus, u3_noun fol)
+{
+ u3_noun gul = u3nt(u3nc(1, 0), u3nc(0, 0), 0); // |~(^ ~)
+ return u3n_nock_et(gul, bus, fol);
+}
+
+
diff --git a/vere/pkg/noun/nock.h b/vere/pkg/noun/nock.h
new file mode 100644
index 0000000..5c34515
--- /dev/null
+++ b/vere/pkg/noun/nock.h
@@ -0,0 +1,149 @@
+/// @file
+
+#ifndef U3_NOCK_H
+#define U3_NOCK_H
+
+#include <stdio.h>
+
+#include "c3/c3.h"
+#include "jets.h"
+#include "types.h"
+#include "zave.h"
+
+ /** Data structures.
+ ***
+ **/
+
+ /* u3n_memo: %memo hint space
+ */
+ typedef struct {
+ c3_l sip_l;
+ u3_noun key;
+ u3z_cid cid;
+ } u3n_memo;
+
+ /* u3n_prog: program compiled from nock
+ */
+ typedef struct _u3n_prog {
+ struct {
+ c3_o own_o; // program owns ops_y?
+ c3_w len_w; // length of bytecode (bytes)
+ c3_y* ops_y; // actual array of bytes
+ } byc_u; // bytecode
+ struct {
+ c3_w len_w; // number of literals
+ u3_noun* non; // array of literals
+ } lit_u; // literals
+ struct {
+ c3_w len_w; // number of memo slots
+ u3n_memo* sot_u; // array of memo slots
+ } mem_u; // memo slot data
+ struct {
+ c3_w len_w; // number of calls sites
+ u3j_site* sit_u; // array of sites
+ } cal_u; // call site data
+ struct {
+ c3_w len_w; // number of registration sites
+ u3j_rite* rit_u; // array of sites
+ } reg_u; // registration site data
+ } u3n_prog;
+
+ /** Functions.
+ **/
+ /* u3n_nock_on(): produce .*(bus fol).
+ */
+ u3_noun
+ u3n_nock_on(u3_noun bus, u3_noun fol);
+
+ /* u3n_find(): return prog for given formula,
+ * split by key (u3_nul for none). RETAIN.
+ */
+ u3p(u3n_prog)
+ u3n_find(u3_noun key, u3_noun fol);
+
+ /* u3n_burn(): execute u3n_prog with bus as subject.
+ */
+ u3_noun
+ u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus);
+
+ /* u3n_slam_on(): produce (gat sam).
+ */
+ u3_noun
+ u3n_slam_on(u3_noun gat, u3_noun sam);
+
+ /* u3n_kick_on(): fire `gat` without changing the sample.
+ */
+ u3_noun
+ u3n_kick_on(u3_noun gat);
+
+ /* u3n_nock_in(): produce .*(bus fol), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_nock_in(u3_noun fly, u3_noun bus, u3_noun fol);
+
+ /* u3n_nock_it(): produce .*(bus fol), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_nock_it(u3_noun sea, u3_noun bus, u3_noun fol);
+
+ /* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol);
+
+ /* u3n_slam_in(): produce (gat sam), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_slam_in(u3_noun fly, u3_noun gat, u3_noun sam);
+
+ /* u3n_slam_it(): produce (gat sam), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_slam_it(u3_noun sea, u3_noun gat, u3_noun sam);
+
+ /* u3n_slam_et(): produce (gat sam), as ++toon, in namespace.
+ */
+ u3_noun
+ u3n_slam_it(u3_noun gul, u3_noun gat, u3_noun sam);
+
+ /* u3n_nock_an(): as slam_in(), but with empty fly.
+ */
+ u3_noun
+ u3n_nock_an(u3_noun bus, u3_noun fol);
+
+ /* u3n_reap(): promote bytecode state.
+ */
+ void
+ u3n_reap(u3p(u3h_root) har_p);
+
+ /* u3n_take(): copy junior bytecode state.
+ */
+ u3p(u3h_root)
+ u3n_take(u3p(u3h_root) har_p);
+
+ /* u3n_mark(): mark bytecode cache.
+ */
+ u3m_quac*
+ u3n_mark();
+
+ /* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3n_reclaim(void);
+
+ /* u3n_rewrite_compact(): rewrite bytecode cache for compaction.
+ */
+ void
+ u3n_rewrite_compact(void);
+
+ /* u3n_free(): free bytecode cache.
+ */
+ void
+ u3n_free(void);
+
+ /* u3n_ream(): refresh after restoring from checkpoint.
+ */
+ void
+ u3n_ream(void);
+
+#endif /* ifndef U3_NOCK_H */
diff --git a/vere/pkg/noun/nock_tests.c b/vere/pkg/noun/nock_tests.c
new file mode 100644
index 0000000..8d4a7d2
--- /dev/null
+++ b/vere/pkg/noun/nock_tests.c
@@ -0,0 +1,83 @@
+/// @file
+
+#include "noun.h"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_boot_lite(1 << 24);
+}
+
+static u3_noun
+_nock_fol(u3_noun fol)
+{
+ return u3n_nock_on(u3_nul, fol);
+}
+
+static c3_i
+_test_nock_meme(void)
+{
+ // (jam !=(=(~ =|(i=@ |-(?:(=(i ^~((bex 32))) ~ [i $(i +(i))]))))))
+ //
+ const c3_y buf_y[] = {
+ 0xe1, 0x16, 0x1b, 0x4, 0x1b, 0xe1, 0x20, 0x58, 0x1c, 0x76, 0x4d, 0x96, 0xd8,
+ 0x31, 0x60, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x8, 0x37, 0xce, 0xd, 0x92, 0x21,
+ 0x83, 0x68, 0x61, 0x87, 0x39, 0xce, 0x4d, 0xe, 0x92, 0x21, 0x87, 0x19, 0x8
+ };
+ u3_noun fol = u3s_cue_bytes(sizeof(buf_y), buf_y);
+ u3_noun gon;
+ c3_w i_w;
+ c3_i ret_i = 1;
+
+ for ( i_w = 0; i_w < 3; i_w++ ) {
+ gon = u3m_soft(0, _nock_fol, u3k(fol));
+
+ if ( c3n == u3r_p(gon, c3__meme, 0) ) {
+ u3m_p("nock meme unexpected mote", u3h(gon));
+ ret_i = 0;
+ u3z(gon);
+ break;
+ }
+
+ u3z(gon);
+ }
+
+ u3z(fol);
+
+ return ret_i;
+}
+
+static c3_i
+_test_meme(void)
+{
+ c3_i ret_i = 1;
+
+ if ( !_test_nock_meme() ) {
+ fprintf(stderr, "test nock meme: failed\r\n");
+ ret_i = 0;
+ }
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_meme() ) {
+ fprintf(stderr, "test meme: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test meme: ok\r\n");
+ return 0;
+}
diff --git a/vere/pkg/noun/noun.h b/vere/pkg/noun/noun.h
new file mode 100644
index 0000000..965330a
--- /dev/null
+++ b/vere/pkg/noun/noun.h
@@ -0,0 +1,26 @@
+/// @file
+
+#ifndef U3_NOUN_H
+#define U3_NOUN_H
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "error.h"
+#include "jets.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "manage.h"
+#include "options.h"
+#include "serial.h"
+#include "types.h"
+#include "vortex.h"
+#include "zave.h"
+#include "imprison.h"
+#include "log.h"
+#include "nock.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "urth.h"
+#include "xtract.h"
+
+#endif /* ifndef U3_NOUN_H */
diff --git a/vere/pkg/noun/options.c b/vere/pkg/noun/options.c
new file mode 100644
index 0000000..cef3479
--- /dev/null
+++ b/vere/pkg/noun/options.c
@@ -0,0 +1,5 @@
+/// @file
+
+#include "options.h"
+
+u3o_config u3o_Config;
diff --git a/vere/pkg/noun/options.h b/vere/pkg/noun/options.h
new file mode 100644
index 0000000..615b765
--- /dev/null
+++ b/vere/pkg/noun/options.h
@@ -0,0 +1,59 @@
+/// @file
+
+#ifndef U3_OPTIONS_H
+#define U3_OPTIONS_H
+
+#include "c3/c3.h"
+#include "types.h"
+
+ /** Data structures.
+ **/
+ /* u3o_config: process / system configuration.
+ */
+ typedef struct _u3o_config {
+ u3_noun who; // single identity
+ c3_c* dir_c; // execution directory (pier)
+ c3_c* eph_c; // ephemeral file
+ c3_w wag_w; // flags (both ways)
+ size_t wor_i; // loom word-length (<= u3a_words)
+ c3_w tos_w; // loom toss skip-length
+ c3_w hap_w; // transient memoization cache size
+ c3_w per_w; // persistent memoization cache size
+ void (*stderr_log_f)(c3_c*); // errors from c code
+ void (*slog_f)(u3_noun); // function pointer for slog
+ void (*sign_hold_f)(void); // suspend system signal regime
+ void (*sign_move_f)(void); // restore system signal regime
+ } u3o_config;
+
+ /* u3o_flag: process/system flags.
+ **
+ ** _debug flags are set outside u3 and heard inside it.
+ ** _check flags are set inside u3 and heard outside it.
+ */
+ enum u3o_flag { // execution flags
+ u3o_debug_ram = 1 << 0, // debug: gc
+ u3o_debug_cpu = 1 << 1, // debug: profile
+ u3o_check_corrupt = 1 << 2, // check: gc memory
+ u3o_check_fatal = 1 << 3, // check: unrecoverable
+ u3o_verbose = 1 << 4, // be remarkably wordy
+ u3o_dryrun = 1 << 5, // don't touch checkpoint
+ u3o_quiet = 1 << 6, // disable ~&
+ u3o_hashless = 1 << 7, // disable hashboard
+ u3o_trace = 1 << 8, // enables trace dumping
+ u3o_no_demand = 1 << 9, // disables demand paging
+ u3o_auto_meld = 1 << 10, // enables meld under pressure
+ u3o_soft_mugs = 1 << 11, // continue replay on mismatch
+ u3o_swap = 1 << 12, // enables ephemeral file
+ u3o_toss = 1 << 13, // reclaim often
+ u3o_cash = 1 << 14, // memo cache harvesting
+ u3o_yolo = 1 << 15 // no brakes!
+ };
+
+ /** Globals.
+ **/
+ /* u3_Config / u3C: global memory control.
+ */
+ extern u3o_config u3o_Config;
+# define u3C u3o_Config
+
+#endif /* ifndef U3_OPTIONS_H */
diff --git a/vere/pkg/noun/palloc.c b/vere/pkg/noun/palloc.c
new file mode 100644
index 0000000..f8999d6
--- /dev/null
+++ b/vere/pkg/noun/palloc.c
@@ -0,0 +1,2400 @@
+
+#include "c3/c3.h"
+#include "allocate.h"
+#include "options.h"
+#include "vortex.h"
+
+#undef SANITY
+
+#ifdef ASAN_ENABLED
+ // XX build problems importing <sanitizers/asan_interface.h>
+ //
+ void __asan_poison_memory_region(void const volatile *addr, size_t size);
+ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+# define ASAN_POISON_MEMORY_REGION(addr, size) \
+ __asan_poison_memory_region((addr), (size))
+# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+ __asan_unpoison_memory_region((addr), (size))
+#else
+# define ASAN_POISON_MEMORY_REGION(addr, size) ((void) (addr), (void) (size))
+# define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void) (addr), (void) (size))
+#endif
+
+#ifndef BASE
+ #define BASE u3R->rut_p
+#endif
+
+#define page_to_post(pag_w) (BASE + (HEAP.dir_ws * (c3_ws)((c3_w)(pag_w - HEAP.off_ws) << u3a_page)))
+#define post_to_page(som_p) (_abs_dif(som_p, (c3_ws)BASE + HEAP.off_ws) >> u3a_page)
+
+#ifndef HEAP
+ #define HEAP u3R->hep
+#endif
+
+static u3_post _imalloc(c3_w);
+static void _ifree(u3_post);
+
+static __inline__ c3_w
+_abs_dif(c3_w a_w, c3_w b_w)
+{
+ // c3_ds dif_ds = a_w - b_w;
+ // c3_d mas_d = dif_ds >> 63;
+ // return (dif_ds + mas_d) ^ mas_d;
+ return (a_w > b_w ) ? a_w - b_w : b_w - a_w;
+}
+
+static void
+_init_once(void)
+{
+ u3a_hunk_dose *hun_u;
+ c3_s mun_w = 0;
+
+ for (c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) {
+ hun_u = &(u3a_Hunk[bit_g]);
+ hun_u->log_s = bit_g + u3a_min_log;
+ hun_u->len_s = 1U << hun_u->log_s;
+ hun_u->tot_s = 1U << (u3a_page - hun_u->log_s);
+ hun_u->map_s = (hun_u->tot_s + 31) >> 5;
+ hun_u->siz_s = c3_wiseof(u3a_crag) + hun_u->map_s - 1;
+
+ // metacircular base case
+ //
+ // trivially deducible from exhaustive enumeration
+ //
+ if ( hun_u->len_s <= (hun_u->siz_s << 1) ) {
+ hun_u->hun_s = 1U + ((hun_u->siz_s - 1) >> hun_u->log_s);
+ }
+ else {
+ hun_u->hun_s = 0;
+ }
+
+ hun_u->ful_s = hun_u->tot_s - hun_u->hun_s;
+ mun_w = c3_max(mun_w, hun_u->hun_s);
+ }
+
+ u3_assert( 32 > mun_w );
+}
+
+static void
+_drop(u3_post som_p, c3_w len_w)
+{
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(som_p), (c3_z)len_w << 2);
+}
+
+static void
+_init_heap(void)
+{
+ u3p(u3a_crag) *dir_u;
+
+ if ( c3y == u3a_is_north(u3R) ) {
+ HEAP.dir_ws = 1;
+ HEAP.off_ws = 0;
+ }
+ else {
+ HEAP.dir_ws = -1;
+ HEAP.off_ws = -1;
+ }
+
+ assert( !(u3R->hat_p & ((1U << u3a_page) - 1)) );
+ assert( u3R->hat_p > u3a_rest_pg );
+ assert( u3R->hat_p == u3R->rut_p );
+
+ // XX check for overflow
+
+ HEAP.pag_p = u3R->hat_p;
+ HEAP.pag_p += HEAP.off_ws * (c3_ws)(1U << u3a_page);
+ HEAP.siz_w = 1U << u3a_page;
+ HEAP.len_w = 1;
+
+ u3R->hat_p += HEAP.dir_ws * (c3_ws)(1U << u3a_page);
+
+ dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+
+ memset(dir_u, 0, 1U << (u3a_page + 2));
+ dir_u[0] = u3a_head_pg;
+
+#ifdef SANITY
+ assert( 0 == post_to_page(HEAP.pag_p) );
+ assert( HEAP.pag_p == page_to_post(0) );
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+#endif
+
+ HEAP.cac_p = _imalloc(c3_wiseof(u3a_dell));
+}
+
+static void
+_extend_directory(c3_w siz_w) // num pages
+{
+ u3p(u3a_crag) *dir_u, *old_u;
+ u3_post old_p = HEAP.pag_p;
+ c3_w nex_w, dif_w, pag_w;
+
+ old_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ nex_w = HEAP.len_w + siz_w; // num words
+ nex_w += (1U << u3a_page) - 1;
+ nex_w &= ~((1U << u3a_page) - 1);
+ dif_w = nex_w >> u3a_page; // new pages
+
+ HEAP.pag_p = u3R->hat_p;
+ HEAP.pag_p += HEAP.off_ws * (c3_ws)nex_w;
+ u3R->hat_p += HEAP.dir_ws * (c3_ws)nex_w; // XX overflow
+
+ // XX depend on the guard page for these?
+ //
+ if ( 1 == HEAP.dir_ws ) {
+ if ( u3R->hat_p >= u3R->cap_p ) {
+ u3m_bail(c3__meme); return;
+ }
+ }
+ else {
+ if ( u3R->hat_p <= u3R->cap_p ) {
+ u3m_bail(c3__meme); return;
+ }
+ }
+
+ dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ pag_w = post_to_page(HEAP.pag_p);
+
+#ifdef SANITY
+ assert( pag_w == (HEAP.len_w - (HEAP.off_ws * (dif_w - 1))) );
+#endif
+
+ {
+ c3_z len_z = (c3_z)HEAP.len_w << 2;
+ c3_z dif_z = (c3_z)dif_w << 2;
+
+ ASAN_UNPOISON_MEMORY_REGION(dir_u, (c3_z)nex_w << 2);
+
+ memcpy(dir_u, old_u, len_z);
+
+ dir_u[pag_w] = u3a_head_pg;
+
+ for ( c3_w i_w = 1; i_w < dif_w; i_w++ ) {
+ dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] = u3a_rest_pg;
+ }
+
+ memset((c3_y*)dir_u + len_z + dif_z, 0, ((c3_z)nex_w << 2) - len_z - dif_z);
+ }
+
+ HEAP.len_w += dif_w;
+ HEAP.siz_w = nex_w;
+
+ _ifree(old_p);
+
+#ifdef SANITY
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+ assert( dir_u[HEAP.len_w - 1] );
+#endif
+}
+
+static u3_post
+_extend_heap(c3_w siz_w) // num pages
+{
+ u3_post pag_p;
+
+#ifdef SANITY
+ assert( HEAP.siz_w >= HEAP.len_w );
+#endif
+
+ if ( (HEAP.siz_w - HEAP.len_w) < siz_w ) {
+ _extend_directory(siz_w);
+ }
+
+ pag_p = u3R->hat_p;
+ pag_p += HEAP.off_ws * (c3_ws)(siz_w << u3a_page);
+
+ u3R->hat_p += HEAP.dir_ws * (c3_ws)(siz_w << u3a_page);
+
+ // XX depend on the guard page for these?
+ //
+ if ( 1 == HEAP.dir_ws ) {
+ if ( u3R->hat_p >= u3R->cap_p ) {
+ return u3m_bail(c3__meme);
+ }
+ }
+ else {
+ if ( u3R->hat_p <= u3R->cap_p ) {
+ return u3m_bail(c3__meme);
+ }
+ }
+
+ HEAP.len_w += siz_w;
+
+ ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), siz_w << (u3a_page + 2));
+
+#ifdef SANITY
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+#endif
+
+ return pag_p;
+}
+
+static u3_post
+_alloc_pages(c3_w siz_w) // num pages
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ u3a_dell* fre_u = u3tn(u3a_dell, HEAP.fre_p);
+ u3a_dell* del_u = NULL;
+ c3_w pag_w = 0;
+
+ while ( fre_u ) {
+ // XX sanity
+
+ if ( fre_u->siz_w < siz_w ) {
+ fre_u = u3tn(u3a_dell, fre_u->nex_p);
+ continue;
+ }
+ else if ( fre_u->siz_w == siz_w ) {
+ pag_w = fre_u->pag_w;
+
+ if ( fre_u->nex_p ) {
+ u3to(u3a_dell, fre_u->nex_p)->pre_p = fre_u->pre_p;
+ }
+ else {
+ HEAP.erf_p = fre_u->pre_p;
+ }
+
+ if ( fre_u->pre_p ) {
+ u3to(u3a_dell, fre_u->pre_p)->nex_p = fre_u->nex_p;
+ }
+ else {
+ HEAP.fre_p = fre_u->nex_p;
+ }
+
+ del_u = fre_u;
+ }
+ else {
+ pag_w = fre_u->pag_w;
+ fre_u->pag_w += siz_w;
+ fre_u->siz_w -= siz_w;
+ }
+ break;
+ }
+
+ u3_post pag_p;
+
+ if ( pag_w ) {
+ // XX groace
+ //
+ pag_w -= HEAP.off_ws * (siz_w - 1);
+ pag_p = page_to_post(pag_w);
+
+#ifdef SANITY
+ assert( pag_w < HEAP.len_w );
+
+ // XX sanity
+ assert( u3a_free_pg == dir_u[pag_w] );
+ for ( c3_w i_w = 1; i_w < siz_w; i_w++ ) {
+ assert( u3a_free_pg == dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] );
+ }
+#endif
+ }
+ else {
+ pag_p = _extend_heap(siz_w);
+ pag_w = post_to_page(pag_p);
+ dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+
+#ifdef SANITY
+ assert( pag_w < HEAP.len_w );
+ assert( (pag_w + ((HEAP.off_ws + 1) * siz_w) - HEAP.off_ws) == HEAP.len_w );
+#endif
+ }
+
+ dir_u[pag_w] = u3a_head_pg;
+
+ for ( c3_w i_w = 1; i_w < siz_w; i_w++ ) {
+ dir_u[pag_w + (HEAP.dir_ws * (c3_ws)i_w)] = u3a_rest_pg;
+ }
+
+ // XX junk
+
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), siz_w << (u3a_page + 2));
+
+ if ( del_u ) {
+ if ( !HEAP.cac_p ) {
+ HEAP.cac_p = u3of(u3a_dell, del_u);
+ }
+ else {
+ _ifree(u3of(u3a_dell, del_u));
+ }
+ }
+
+#ifdef SANITY
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+ assert( dir_u[HEAP.len_w - 1] );
+#endif
+
+ return pag_p;
+}
+
+static void
+_rake_chunks(c3_w len_w, c3_w max_w, c3_t rak_t, c3_w* out_w, u3_post* out_p)
+{
+ c3_g bit_g = (c3_g)c3_bits_word(len_w - 1) - u3a_min_log; // 0-9, inclusive
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ u3_post pag_p = HEAP.wee_p[bit_g];
+ u3a_crag *pag_u;
+ c3_w hav_w = *out_w;
+
+ if ( rak_t ) {
+ c3_w *map_w;
+ c3_g pos_g;
+ u3_post bas_p;
+ c3_w off_w;
+
+ while ( pag_p ) {
+ pag_u = u3to(u3a_crag, pag_p);
+ bas_p = page_to_post(pag_u->pag_w);
+ map_w = pag_u->map_w;
+
+ while ( !*map_w ) { map_w++; }
+ off_w = (map_w - pag_u->map_w) << 5;
+
+ if ( (max_w - hav_w) < pag_u->fre_s ) {
+ while ( hav_w < max_w ) {
+ pos_g = c3_tz_w(*map_w);
+ *map_w &= ~(1U << pos_g);
+
+ out_p[hav_w++] = bas_p + ((off_w + pos_g) << pag_u->log_s);
+ pag_u->fre_s--;
+
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(out_p[hav_w - 1]), (c3_z)hun_u->len_s << 2);
+
+ if ( !*map_w ) {
+ do { map_w++; } while ( !*map_w );
+ off_w = (map_w - pag_u->map_w) << 5;
+ }
+ }
+
+ HEAP.wee_p[bit_g] = pag_p;
+ *out_w = hav_w;
+ return;
+ }
+
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(bas_p), 1U << (u3a_page + 2));
+
+ while ( 1 ) {
+ pos_g = c3_tz_w(*map_w);
+ *map_w &= ~(1U << pos_g);
+
+ out_p[hav_w++] = bas_p + ((off_w + pos_g) << pag_u->log_s);
+
+ if ( !--pag_u->fre_s ) {
+ break;
+ }
+
+ if ( !*map_w ) {
+ do { map_w++; } while ( !*map_w );
+ off_w = (map_w - pag_u->map_w) << 5;
+ }
+ }
+
+ pag_p = pag_u->nex_p;
+ pag_u->nex_p = 0;
+
+ if ( hav_w == max_w ) {
+ HEAP.wee_p[bit_g] = pag_p;
+ *out_w = hav_w;
+ return;
+ }
+ }
+
+ HEAP.wee_p[bit_g] = 0;
+ }
+
+ // XX s/b ful_s
+ if ( hun_u->tot_s > (max_w - hav_w) ) {
+ *out_w = hav_w;
+ return;
+ }
+
+ // manually inlined _make_chunks(), storing each chunk-post to [*out_p]
+ //
+ {
+ u3_post hun_p;
+ c3_w pag_w;
+
+ pag_p = _alloc_pages(1);
+ pag_w = post_to_page(pag_p);
+ hun_p = ( hun_u->hun_s ) ? pag_p : _imalloc(hun_u->siz_s);
+ pag_u = u3to(u3a_crag, hun_p);
+ pag_u->pag_w = pag_w;
+ pag_u->log_s = hun_u->log_s;
+ pag_u->fre_s = 0;
+ pag_u->nex_p = 0;
+ // initialize bitmap (zeros, none free)
+ //
+ memset(pag_u->map_w, 0, (c3_z)hun_u->map_s << 2);
+
+ {
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ dir_u[pag_w] = hun_p;
+ }
+
+ for ( c3_s i_s = hun_u->hun_s; i_s < hun_u->tot_s; i_s++ ) {
+ out_p[hav_w++] = pag_p + (i_s << pag_u->log_s);
+ }
+
+ *out_w = hav_w;
+ }
+}
+
+static u3_post
+_make_chunks(c3_g bit_g) // 0-9, inclusive
+{
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ u3a_crag *pag_u;
+ u3_post hun_p, pag_p = _alloc_pages(1);
+ c3_w pag_w = post_to_page(pag_p);
+
+ ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), 1U << (u3a_page + 2));
+
+ if ( hun_u->hun_s ) {
+ hun_p = pag_p;
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), (c3_z)hun_u->hun_s << (hun_u->log_s + 2));
+ }
+ else {
+ hun_p = _imalloc(hun_u->siz_s);
+ }
+
+ pag_u = u3to(u3a_crag, hun_p);
+ pag_u->pag_w = pag_w;
+ pag_u->log_s = hun_u->log_s;
+ pag_u->fre_s = hun_u->ful_s;
+
+ // initialize bitmap (ones, all free)
+ //
+ if ( hun_u->tot_s < 32 ) {
+ pag_u->map_w[0] = (1U << hun_u->tot_s) - 1;
+ }
+ else {
+ memset(pag_u->map_w, 0xff, (c3_z)hun_u->map_s << 2);
+ }
+
+ // reserve chunks stolen for pginfo
+ // NB: max [hun_s] guarded by assertion in _init_once()
+ //
+ pag_u->map_w[0] &= ~0U << hun_u->hun_s;
+
+ {
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ dir_u[pag_w] = hun_p;
+ }
+
+ pag_u->nex_p = HEAP.wee_p[bit_g];
+ HEAP.wee_p[bit_g] = hun_p;
+
+ return hun_p;
+}
+
+static u3_post
+_alloc_words(c3_w len_w) // 4-2.048, inclusive
+{
+ c3_g bit_g = (c3_g)c3_bits_word(len_w - 1) - u3a_min_log; // 0-9, inclusive
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ u3a_crag *pag_u;
+ c3_w *map_w;
+ c3_g pos_g;
+
+ if ( !HEAP.wee_p[bit_g] ) {
+ pag_u = u3to(u3a_crag, _make_chunks(bit_g));
+ }
+ else {
+ pag_u = u3to(u3a_crag, HEAP.wee_p[bit_g]);
+ // XX sanity
+
+ if ( 1 == pag_u->fre_s ) {
+ HEAP.wee_p[bit_g] = pag_u->nex_p;
+ pag_u->nex_p = 0;
+ }
+ }
+
+ pag_u->fre_s--;
+ map_w = pag_u->map_w;
+ while ( !*map_w ) { map_w++; }
+
+ pos_g = c3_tz_w(*map_w);
+ *map_w &= ~(1U << pos_g);
+
+ {
+ u3_post out_p, bas_p = page_to_post(pag_u->pag_w);
+ c3_w off_w = (map_w - pag_u->map_w) << 5;
+
+ out_p = bas_p + ((off_w + pos_g) << pag_u->log_s);
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(out_p), hun_u->len_s << 2);
+ // XX poison suffix
+
+ return out_p;
+ }
+}
+
+static u3_post
+_imalloc(c3_w len_w)
+{
+ if ( len_w > (1U << (u3a_page - 1)) ) {
+ len_w += (1U << u3a_page) - 1;
+ len_w >>= u3a_page;
+ // XX poison suffix
+ return _alloc_pages(len_w);
+ }
+
+ return _alloc_words(c3_max(len_w, u3a_minimum));
+}
+
+static inline c3_w
+_pages_size(c3_w pag_w)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w siz_w = 1;
+
+ // head-page 0 in a south road can only have a size of 1
+ //
+ if ( pag_w || !HEAP.off_ws ) {
+ while( dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] == u3a_rest_pg ) {
+ siz_w++;
+ }
+ }
+
+ return siz_w;
+}
+
+static c3_w
+_free_pages(u3_post som_p, c3_w pag_w, u3_post dir_p)
+{
+ u3a_dell *cac_u, *fre_u, *del_u = NULL;
+ c3_w nex_w, siz_w = 1;
+ u3_post fre_p;
+
+ if ( u3a_free_pg == dir_p ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: double free page som_p=0x%x pag_w=%u\r\n"
+ "\033[0m",
+ som_p, pag_w);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ if ( u3a_head_pg != dir_p ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: wrong page som_p=0x%x dir_p=0x%x\r\n"
+ "\033[0m",
+ som_p, dir_p);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ if ( som_p & ((1U << u3a_page) - 1) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: bad page alignment som_p=0x%x\r\n"
+ "\033[0m",
+ som_p);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ {
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+
+ dir_u[pag_w] = u3a_free_pg;
+
+ // head-page 0 in a south road can only have a size of 1
+ //
+ if ( pag_w || !HEAP.off_ws ) {
+ while( dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] == u3a_rest_pg ) {
+ dir_u[pag_w + (HEAP.dir_ws * (c3_ws)siz_w)] = u3a_free_pg;
+ siz_w++;
+ }
+ }
+ }
+
+ // XX groace
+ //
+ if ( HEAP.off_ws ) {
+ nex_w = pag_w + 1;
+ pag_w = nex_w - siz_w;
+ }
+ else {
+ nex_w = pag_w + siz_w;
+ }
+
+#ifdef SANITY
+ assert( pag_w < HEAP.len_w );
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+#endif
+
+ if ( nex_w == HEAP.len_w ) {
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w wiz_w = siz_w;
+
+ // check if prior pages are already free
+ //
+ if ( !dir_u[HEAP.len_w - (siz_w + 1)] ) {
+ assert( HEAP.erf_p );
+ fre_u = u3to(u3a_dell, HEAP.erf_p);
+ assert( (fre_u->pag_w + fre_u->siz_w) == pag_w );
+
+ if ( fre_u->pre_p ) {
+ HEAP.erf_p = fre_u->pre_p;
+ u3to(u3a_dell, fre_u->pre_p)->nex_p = 0;
+ }
+ else {
+ HEAP.fre_p = HEAP.erf_p = 0;
+ }
+
+ pag_w = fre_u->pag_w; // NB: clobbers
+ siz_w += fre_u->siz_w;
+
+ // XX groace
+ //
+ pag_w -= HEAP.off_ws * (siz_w - 1);
+ som_p = page_to_post(pag_w);
+ }
+ else {
+ fre_u = NULL;
+ }
+
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(som_p), siz_w << (u3a_page + 2));
+ u3R->hat_p -= HEAP.dir_ws * (c3_ws)(siz_w << u3a_page);
+ HEAP.len_w -= siz_w;
+
+ // fprintf(stderr, "shrink heap 0x%x 0x%x %u:%u (%u) 0x%x\r\n",
+ // som_p, som_p + (siz_w << u3a_page), pag_w, wiz_w, siz_w, u3R->hat_p);
+
+#ifdef SANITY
+ assert( HEAP.len_w == post_to_page(u3R->hat_p + HEAP.off_ws) );
+ assert( dir_u[HEAP.len_w - 1] );
+#endif
+
+ if ( fre_u ) {
+ _ifree(u3of(u3a_dell, fre_u));
+ }
+
+ return wiz_w;
+ }
+
+ // XX madv_free
+
+ ASAN_POISON_MEMORY_REGION(u3a_into(som_p), siz_w << (u3a_page + 2));
+
+ // XX add temporary freelist entry?
+ // if ( !HEAP.cac_p && !HEAP.fre_p
+ // && !HEAP.wee_p[(c3_bits_word(c3_wiseof(*cac_u) - 1) - u3a_min_log)] )
+ // {
+ // fprintf(stderr, "palloc: growing heap to free pages\r\n");
+ // }
+
+ if ( !HEAP.cac_p ) {
+ fre_p = _imalloc(c3_wiseof(*cac_u));
+ }
+ else {
+ fre_p = HEAP.cac_p;
+ HEAP.cac_p = 0;
+ }
+
+ cac_u = u3to(u3a_dell, fre_p);
+ cac_u->pag_w = pag_w;
+ cac_u->siz_w = siz_w;
+
+ if ( !(fre_u = u3tn(u3a_dell, HEAP.fre_p)) ) {
+ // fprintf(stderr, "free pages 0x%x (%u) via 0x%x\r\n", som_p, siz_w, HEAP.cac_p);
+ cac_u->nex_p = 0;
+ cac_u->pre_p = 0;
+ HEAP.fre_p = HEAP.erf_p = fre_p;
+ fre_p = 0;
+ }
+ else {
+ c3_w fex_w;
+
+ while ( ((fex_w = fre_u->pag_w + fre_u->siz_w) < pag_w)
+ && fre_u->nex_p )
+ {
+ fre_u = u3to(u3a_dell, fre_u->nex_p);
+ }
+
+ if ( fre_u->pag_w > nex_w ) { // insert before
+ cac_u->nex_p = u3of(u3a_dell, fre_u);
+ cac_u->pre_p = fre_u->pre_p;
+
+ fre_u->pre_p = fre_p;
+
+ // XX sanity
+ if ( cac_u->pre_p ) {
+ u3to(u3a_dell, cac_u->pre_p)->nex_p = fre_p;
+ }
+ else {
+ HEAP.fre_p = fre_p;
+ }
+
+ fre_p = 0;
+ }
+ else if ( fex_w == pag_w ) { // append to entry
+ fre_u->siz_w += siz_w;
+
+ // coalesce with next entry
+ //
+ if ( fre_u->nex_p
+ && ((fex_w + siz_w) == u3to(u3a_dell, fre_u->nex_p)->pag_w) )
+ {
+ del_u = u3to(u3a_dell, fre_u->nex_p);
+ fre_u->siz_w += del_u->siz_w;
+ fre_u->nex_p = del_u->nex_p;
+
+ // XX sanity
+ if ( del_u->nex_p ) {
+ u3to(u3a_dell, del_u->nex_p)->pre_p = u3of(u3a_dell, fre_u);
+ }
+ else {
+ HEAP.erf_p = u3of(u3a_dell, fre_u);
+ }
+ }
+ }
+ else if ( fre_u->pag_w == nex_w ) { // prepend to entry
+ fre_u->siz_w += siz_w;
+ fre_u->pag_w = pag_w;
+ }
+ else if ( !fre_u->nex_p ) { // insert after
+ cac_u->nex_p = 0;
+ cac_u->pre_p = u3of(u3a_dell, fre_u);
+ HEAP.erf_p = fre_u->nex_p = fre_p;
+ fre_p = 0;
+ }
+ else {
+ fprintf(stderr, "\033[31m"
+ "palloc: free list hosed at som_p=0x%x pag=%u len=%u\r\n"
+ "\033[0m",
+ (u3_post)u3of(u3a_dell, fre_u), fre_u->pag_w, fre_u->siz_w);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+ }
+
+ if ( fre_p ) {
+ if ( !HEAP.cac_p ) {
+ HEAP.cac_p = fre_p;
+ }
+ else {
+ _ifree(fre_p);
+ }
+
+ if ( del_u ) {
+ _ifree(u3of(u3a_dell, del_u));
+ }
+ }
+
+ return siz_w;
+}
+
+static void
+_free_words(u3_post som_p, c3_w pag_w, u3_post dir_p)
+{
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+
+#ifdef SANITY
+ assert( page_to_post(pag_u->pag_w) == (som_p & ~((1U << u3a_page) - 1)) );
+ assert( pag_u->log_s < u3a_page );
+#endif
+
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+
+ if ( som_p & (hun_u->len_s - 1) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: bad alignment som_p=0x%x pag=%u cag=0x%x len_s=%u\r\n"
+ "\033[0m",
+ som_p, post_to_page(som_p), dir_p, hun_u->len_s);
+ u3_assert(!"loom: corrupt"); return;
+ }
+
+ if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: double free som_p=0x%x pag=0x%x\r\n"
+ "\033[0m",
+ som_p, dir_p);
+ u3_assert(!"loom: corrupt"); return;
+ }
+
+ pag_u->map_w[pos_w >> 5] |= (1U << (pos_w & 31));
+ pag_u->fre_s++;
+
+ ASAN_POISON_MEMORY_REGION(u3a_into(som_p), hun_u->len_s << 2);
+
+ {
+ u3_post *bit_p = &(HEAP.wee_p[bit_g]);
+ u3a_crag *bit_u, *nex_u;
+
+ if ( 1 == pag_u->fre_s ) {
+ // page newly non-full, link
+ //
+
+ if ( &(u3H->rod_u) == u3R ) {
+ while ( *bit_p ) {
+ bit_u = u3to(u3a_crag, *bit_p);
+ nex_u = u3tn(u3a_crag, bit_u->nex_p);
+
+ if ( nex_u && (nex_u->pag_w < pag_u->pag_w) ) {
+ bit_p = &(bit_u->nex_p);
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ pag_u->nex_p = *bit_p;
+ *bit_p = dir_p;
+ }
+ else if ( pag_u->fre_s == hun_u->ful_s ) {
+ // page now free
+ //
+ while ( *bit_p != dir_p ) {
+ bit_u = u3to(u3a_crag, *bit_p);
+ bit_p = &(bit_u->nex_p);
+
+ // XX sanity: must be in list
+ }
+
+ *bit_p = pag_u->nex_p;
+
+ dir_u[pag_u->pag_w] = u3a_head_pg;
+ som_p = page_to_post(pag_u->pag_w); // NB: clobbers
+ if ( som_p != dir_p ) {
+ _ifree(dir_p);
+ }
+ _ifree(som_p);
+ }
+ }
+}
+
+static void
+_ifree(u3_post som_p)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w pag_w = post_to_page(som_p);
+
+ if ( pag_w >= HEAP.len_w ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: page out of heap som_p=0x%x pag_w=%u len_w=%u\r\n"
+ "\033[0m",
+ som_p, pag_w, HEAP.len_w);
+ u3_assert(!"loom: corrupt"); return;
+ }
+
+ u3_post dir_p = dir_u[pag_w];
+
+ if ( dir_p <= u3a_rest_pg ) {
+ (void)_free_pages(som_p, pag_w, dir_p);
+ }
+ else {
+ _free_words(som_p, pag_w, dir_p);
+ }
+}
+
+static u3_post
+_irealloc(u3_post som_p, c3_w len_w)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w pag_w = post_to_page(som_p);
+ c3_w old_w;
+
+ if ( pag_w >= HEAP.len_w ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: realloc page out of heap som_p=0x%x pag_w=%u\r\n"
+ "\033[0m",
+ som_p, pag_w);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ u3_post dir_p = dir_u[pag_w];
+
+ if ( u3a_head_pg == dir_p ) {
+ if ( som_p & ((1U << u3a_page) - 1) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: realloc bad page alignment som_p=0x%x\r\n"
+ "\033[0m",
+ som_p);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ {
+ c3_w dif_w, siz_w = _pages_size(pag_w);
+
+ old_w = siz_w << u3a_page;
+
+ if ( (len_w < old_w)
+ && (dif_w = (old_w - len_w) >> u3a_page) )
+ {
+ pag_w += HEAP.dir_ws * (siz_w - dif_w);
+ (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg);
+
+ // XX junk
+ // XX unpoison prefix, poison suffix
+ return som_p;
+ }
+
+ // XX also grow in place if sufficient adjacent pages are free?
+ }
+ }
+ else if ( u3a_rest_pg >= dir_p ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: realloc wrong page som_p=0x%x\r\n"
+ "\033[0m",
+ som_p);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[pag_u->log_s - u3a_min_log]);
+
+ if ( som_p & (hun_u->len_s - 1) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: realloc bad alignment som_p=0x%x pag=0x%x len_s=%u\r\n"
+ "\033[0m",
+ som_p, dir_p, hun_u->len_s);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) {
+ fprintf(stderr, "\033[31m"
+ "palloc: realloc free som_p=0x%x pag=0x%x\r\n"
+ "\033[0m",
+ som_p, dir_p);
+ u3_assert(!"loom: corrupt"); return 0;
+ }
+
+ old_w = hun_u->len_s;
+
+ if ( (len_w <= old_w)
+ && ((len_w > (old_w >> 1)) || (u3a_minimum == old_w)) )
+ {
+ // XX junk
+ // XX unpoison prefix, poison suffix
+ return som_p;
+ }
+ }
+
+ {
+ u3_post new_p = _imalloc(len_w);
+
+ memcpy(u3a_into(new_p), u3a_into(som_p), (c3_z)c3_min(len_w, old_w) << 2);
+ _ifree(som_p);
+
+ return new_p;
+ }
+}
+
+static void
+_post_status(u3_post som_p)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w pag_w = post_to_page(som_p);
+
+ if ( pag_w >= HEAP.len_w ) {
+ fprintf(stderr, "palloc: out of heap: post som_p=0x%x pag_w=%u len_w=%u\r\n",
+ som_p, pag_w, HEAP.len_w);
+ return;
+ }
+
+ u3_post dir_p = dir_u[pag_w];
+
+ if ( dir_p <= u3a_rest_pg ) {
+ if ( som_p & ((1U << u3a_page) - 1) ) {
+ fprintf(stderr, "palloc: page not aligned som_p=0x%x (0x%x)\r\n",
+ som_p, som_p & ~(((1U << u3a_page) - 1)));
+ }
+
+ if ( u3a_free_pg == dir_p ) {
+ fprintf(stderr, "palloc: free page som_p=0x%x pag_w=%u\r\n",
+ som_p, pag_w);
+ }
+ else if ( u3a_head_pg != dir_p ) {
+ fprintf(stderr, "palloc: rest page som_p=0x%x dir_p=0x%x\r\n",
+ som_p, dir_p);
+ }
+ else {
+ // XX include size
+ fprintf(stderr, "palloc: head page in-use som_p=0x%x\r\n",
+ som_p);
+ }
+ }
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+
+#ifdef SANITY
+ assert( page_to_post(pag_u->pag_w) == (som_p & ~((1U << u3a_page) - 1)) );
+ assert( pag_u->log_s < u3a_page );
+#endif
+
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[pag_u->log_s - u3a_min_log]);
+
+ if ( som_p & (hun_u->len_s - 1) ) {
+ fprintf(stderr, "palloc: bad alignment som_p=0x%x (0x%x) pag=0x%x len_s=%u\r\n",
+ som_p, som_p & ~((1U << u3a_page) - 1),
+ dir_p, hun_u->len_s);
+ }
+
+ if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) {
+ fprintf(stderr, "palloc: words free som_p=0x%x pag=0x%x len=%u\r\n",
+ som_p, dir_p, hun_u->len_s);
+ }
+ else {
+ fprintf(stderr, "palloc: words in-use som_p=0x%x pag=0x%x, len=%u\r\n",
+ som_p, dir_p, hun_u->len_s);
+ }
+ }
+}
+
+static c3_w
+_idle_pages(void)
+{
+ u3a_dell* fre_u = u3tn(u3a_dell, HEAP.fre_p);
+ c3_w tot_w = 0;
+
+ while ( fre_u ) {
+ tot_w += fre_u->siz_w;
+ fre_u = u3tn(u3a_dell, fre_u->nex_p);
+ }
+
+ return tot_w;
+}
+
+static c3_w
+_idle_words(void)
+{
+ u3a_crag *pag_u;
+ c3_w pag_w, siz_w, tot_w = 0;
+
+ for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) {
+ pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]);
+ siz_w = pag_w = 0;
+
+ while ( pag_u ) {
+ siz_w += pag_u->fre_s;
+ pag_u = u3tn(u3a_crag, pag_u->nex_p);
+ pag_w++;
+ }
+
+ if ( (u3C.wag_w & u3o_verbose) && siz_w ) {
+ fprintf(stderr, "idle words: class=%u (%u words) blocks=%u (in %u pages) ",
+ i_w, (1U << (i_w + u3a_min_log)), siz_w, pag_w);
+ u3a_print_memory(stderr, "total", siz_w << (i_w + u3a_min_log));
+ }
+
+ tot_w += siz_w << (i_w + u3a_min_log);
+ }
+
+ return tot_w;
+}
+
+static void
+_poison_pages(void)
+{
+ u3a_dell *fre_u = u3tn(u3a_dell, HEAP.fre_p);
+ u3_post pag_p;
+
+ while ( fre_u ) {
+ pag_p = page_to_post(fre_u->pag_w);
+ ASAN_POISON_MEMORY_REGION(u3a_into(pag_p), fre_u->siz_w << (u3a_page + 2));
+ fre_u = u3tn(u3a_dell, fre_u->nex_p);
+ }
+}
+
+static void
+_poison_words(void)
+{
+ const u3a_hunk_dose *hun_u;
+ u3_post pag_p, hun_p;
+ u3a_crag *pag_u;
+ c3_w off_w, wor_w, len_w, *map_w;
+ c3_g pos_g;
+ c3_s fre_s;
+
+ for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) {
+ hun_u = &(u3a_Hunk[i_w]);
+ pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]);
+
+ while ( pag_u ) {
+ pag_p = page_to_post(pag_u->pag_w);
+ map_w = pag_u->map_w;
+ len_w = (c3_w)hun_u->len_s << 2;
+ fre_s = pag_u->fre_s;
+
+ do {
+ while ( !*map_w ) { map_w++; }
+ wor_w = *map_w;
+ off_w = (map_w - pag_u->map_w) << 5;
+
+ do {
+ pos_g = c3_tz_w(wor_w);
+ wor_w &= ~(1U << pos_g);
+ hun_p = pag_p + ((off_w + pos_g) << pag_u->log_s);
+
+ ASAN_POISON_MEMORY_REGION(u3a_into(hun_p), len_w);
+
+ } while ( --fre_s && wor_w );
+
+ map_w++;
+ } while ( fre_s );
+
+ pag_u = u3tn(u3a_crag, pag_u->nex_p);
+ }
+ }
+}
+
+static void
+_unpoison_words(void)
+{
+ u3a_crag *pag_u;
+ u3_post pag_p;
+
+ for ( c3_w i_w = 0; i_w < u3a_crag_no; i_w++ ) {
+ pag_u = u3tn(u3a_crag, HEAP.wee_p[i_w]);
+
+ while ( pag_u ) {
+ pag_p = page_to_post(pag_u->pag_w);
+ ASAN_UNPOISON_MEMORY_REGION(u3a_into(pag_p), 1U << (u3a_page + 2));
+ pag_u = u3tn(u3a_crag, pag_u->nex_p);
+ }
+ }
+}
+
+static c3_w
+_mark_post(u3_post som_p)
+{
+ c3_w pag_w = post_to_page(som_p);
+ c3_w blk_w = pag_w >> 5;
+ c3_w bit_w = pag_w & 31;
+ c3_w siz_w;
+
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ u3_post dir_p = dir_u[pag_w];
+
+ // som_p is a one-or-more page allocation
+ //
+ if ( dir_p <= u3a_rest_pg ) {
+ if ( som_p & ((1U << u3a_page) - 1) ) {
+ fprintf(stderr, "palloc: mark: page not aligned som_p=0x%x (0x%x)\r\n",
+ som_p, som_p & ~(((1U << u3a_page) - 1)));
+ return 0;
+ }
+
+ if ( u3a_free_pg == dir_p ) {
+ fprintf(stderr, "palloc: mark: free page som_p=0x%x pag_w=%u\r\n",
+ som_p, pag_w);
+ return 0;
+ }
+ else if ( u3a_head_pg != dir_p ) {
+ fprintf(stderr, "palloc: mark: rest page som_p=0x%x dir_p=0x%x\r\n",
+ som_p, dir_p);
+ return 0;
+ }
+
+ // page(s) already marked
+ //
+ if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) {
+ return 0;
+ }
+
+ u3a_Mark.bit_w[blk_w] |= 1U << bit_w;
+
+ siz_w = _pages_size(pag_w);
+ siz_w <<= u3a_page;
+
+ return siz_w;
+ }
+ // som_p is a chunk allocation
+ //
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s;
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ c3_w *mar_w;
+
+ if ( som_p & (hun_u->len_s - 1) ) {
+ fprintf(stderr, "palloc: mark: bad alignment som_p=0x%x (0x%x) pag=0x%x (%u) len_s=%u\r\n",
+ som_p, som_p & ~((1U << u3a_page) - 1),
+ dir_p, pag_u->pag_w, hun_u->len_s);
+ return 0;
+ }
+
+ if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) {
+ fprintf(stderr, "palloc: mark: words free som_p=0x%x pag=0x%x (%u) len=%u\r\n",
+ som_p, dir_p, pag_u->pag_w, hun_u->len_s);
+ return 0;
+ }
+
+ // page is marked
+ //
+ if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) {
+ mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+
+ if ( !(mar_w[pos_w >> 5] & (1U << (pos_w & 31))) ) {
+ return 0;
+ }
+ }
+ // page is unmarked, allocate and initialize mark-array
+ //
+ else {
+ mar_w = u3a_mark_alloc(hun_u->map_s);
+ u3a_Mark.buf_w[pag_w] = mar_w - u3a_Mark.buf_w;
+ memset(mar_w, 0xff, (c3_z)hun_u->map_s << 2);
+
+ // mark page metadata
+ //
+ if ( !hun_u->hun_s ) {
+ u3a_Mark.wee_w[bit_g] += _mark_post(dir_p);
+ mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+ }
+ else {
+ // NB: max [hun_s] guarded by assertion in _init_once()
+ //
+ mar_w[0] &= ~0U << hun_u->hun_s;
+ u3a_Mark.wee_w[bit_g] += (c3_w)hun_u->hun_s << pag_u->log_s;
+ }
+
+ u3a_Mark.bit_w[blk_w] |= 1U << bit_w;
+ }
+
+ mar_w[pos_w >> 5] &= ~(1U << (pos_w & 31));
+ siz_w = hun_u->len_s;
+
+ return siz_w;
+ }
+}
+
+static void
+_print_chunk(FILE* fil_u, u3_post som_p, c3_w siz_w)
+{
+ c3_w *ptr_w = u3to(c3_w, som_p);
+
+ fprintf(fil_u, "{ ");
+ // XX log minimum or u3a_minimum
+ for ( c3_w j_w = 0; j_w < 4; j_w++ ) {
+ fprintf(fil_u, "0x%x, ", ptr_w[j_w]);
+ }
+
+ if ( siz_w > 4 ) {
+ fprintf(fil_u, "... ");
+ }
+
+ fprintf(fil_u, "}\r\n");
+}
+
+static c3_w
+_sweep_directory(void)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w pag_w, blk_w, bit_w, siz_w, leq_w = 0, tot_w = 0;
+ u3_post dir_p;
+
+ // unlink leaked whole chunk-pages
+ // (we do this first so we won't need to dereference the metadata)
+ //
+ {
+ u3a_crag *pag_u;
+ u3_post *bit_p;
+ c3_g bit_g;
+
+ for ( bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) {
+ bit_p = &(HEAP.wee_p[bit_g]);
+
+ while ( *bit_p ) {
+ pag_u = u3to(u3a_crag, *bit_p);
+ pag_w = pag_u->pag_w;
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ *bit_p = pag_u->nex_p;
+ }
+ else {
+ bit_p = &(pag_u->nex_p);
+ }
+ }
+ }
+ }
+
+ for ( pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) {
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+ dir_p = dir_u[pag_w];
+
+ if ( u3a_head_pg == dir_p ) {
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ siz_w = _free_pages(page_to_post(pag_w), pag_w, dir_p);
+ if ( 1 == siz_w ) {
+ fprintf(stderr, "palloc: leaked page %u\r\n", pag_w);
+ }
+ else {
+ fprintf(stderr, "palloc: leaked pages %u-%u\r\n",
+ pag_w, pag_w + siz_w - 1);
+ }
+ leq_w += siz_w << u3a_page;
+ }
+ else {
+ siz_w = _pages_size(pag_w);
+ tot_w += siz_w << u3a_page;
+ }
+ }
+ else if ( u3a_rest_pg < dir_p ) {
+ // entire chunk page is unmarked
+ //
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ fprintf(stderr, "palloc: leaked chunk page %u\r\n", pag_w);
+ (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg);
+ leq_w += 1U << u3a_page;
+ }
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ u3_post som_p, bas_p = page_to_post(pag_u->pag_w);
+ c3_w *mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+
+ siz_w = hun_u->len_s;
+
+ if ( 0 == memcmp(mar_w, pag_u->map_w, (c3_z)hun_u->map_s << 2) ) {
+ tot_w += siz_w * (hun_u->tot_s - pag_u->fre_s);
+ }
+ // NB: since at least one chunk is marked,
+ // _free_words() will never free [pag_u]
+ //
+ else {
+ for ( c3_s i_s = 0; i_s < hun_u->tot_s; i_s++ ) {
+ blk_w = i_s >> 5;
+ bit_w = i_s & 31;
+
+ if ( !(pag_u->map_w[blk_w] & (1U << bit_w)) ) {
+ if ( !(mar_w[blk_w] & (1U << bit_w)) ) {
+ tot_w += siz_w;
+ }
+ else {
+ som_p = bas_p + ((c3_w)i_s << pag_u->log_s);
+
+ fprintf(stderr, "palloc: leak: 0x%x (chunk %u in page %u)\r\n", som_p, i_s, pag_w);
+
+ _print_chunk(stderr, som_p, siz_w);
+ _free_words(som_p, pag_w, dir_p);
+ leq_w += siz_w;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( leq_w ) {
+ u3a_print_memory(stderr, "palloc: sweep: leaked", leq_w);
+ // u3_assert(0);
+ }
+
+ if ( u3C.wag_w & u3o_verbose ) {
+ u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Mark.len_w);
+ u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Mark.siz_w);
+ }
+
+ u3a_mark_done(); // XX move
+
+ return tot_w;
+}
+
+static c3_w
+_count_post(u3_post som_p, c3_y rat_y)
+{
+ c3_w pag_w = post_to_page(som_p);
+ c3_w blk_w = pag_w >> 5;
+ c3_w bit_w = pag_w & 31;
+ c3_w siz_w;
+
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ u3_post dir_p = dir_u[pag_w];
+
+ // som_p is a one-or-more page allocation
+ //
+ if ( dir_p <= u3a_rest_pg ) {
+ if ( som_p & ((1U << u3a_page) - 1) ) {
+ fprintf(stderr, "palloc: mark: page not aligned som_p=0x%x (0x%x)\r\n",
+ som_p, som_p & ~(((1U << u3a_page) - 1)));
+ return 0;
+ }
+
+ if ( u3a_free_pg == dir_p ) {
+ fprintf(stderr, "palloc: mark: free page som_p=0x%x pag_w=%u\r\n",
+ som_p, pag_w);
+ return 0;
+ }
+ else if ( u3a_head_pg != dir_p ) {
+ fprintf(stderr, "palloc: mark: rest page som_p=0x%x dir_p=0x%x\r\n",
+ som_p, dir_p);
+ return 0;
+ }
+
+ switch ( rat_y ) {
+ case 0: { // not refcounted
+ u3_assert( (c3_ws)u3a_Mark.buf_w[pag_w] <= 0 );
+ u3a_Mark.buf_w[pag_w] -= 1;
+ } break;
+
+ case 1: { // refcounted
+ // NB: "premarked"
+ //
+ if ( 0x80000000 == u3a_Mark.buf_w[pag_w] ) {
+ u3a_Mark.buf_w[pag_w] = 1;
+ }
+ else {
+ u3_assert( (c3_ws)u3a_Mark.buf_w[pag_w] >= 0 );
+ u3a_Mark.buf_w[pag_w] += 1;
+ }
+ } break;
+
+ case 2: { // refcounted, pre-mark
+ if ( !u3a_Mark.buf_w[pag_w] ) {
+ u3a_Mark.buf_w[pag_w] = 0x80000000;
+ }
+ } break;
+
+ default: u3_assert(0);
+ }
+
+ // page(s) already marked
+ //
+ if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) {
+ return 0;
+ }
+
+ u3a_Mark.bit_w[blk_w] |= 1U << bit_w;
+
+ siz_w = _pages_size(pag_w);
+ siz_w <<= u3a_page;
+
+ return siz_w;
+ }
+ // som_p is a chunk allocation
+ //
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> pag_u->log_s;
+ c3_w *mar_w;
+
+ if ( som_p & (hun_u->len_s - 1) ) {
+ fprintf(stderr, "palloc: count: bad alignment som_p=0x%x (0x%x) pag=0x%x (%u) len_s=%u\r\n",
+ som_p, som_p & ~((1U << u3a_page) - 1),
+ dir_p, pag_u->pag_w, hun_u->len_s);
+ return 0;
+ }
+
+ if ( pag_u->map_w[pos_w >> 5] & (1U << (pos_w & 31)) ) {
+ fprintf(stderr, "palloc: count: words free som_p=0x%x pag=0x%x (%u) len=%u\r\n",
+ som_p, dir_p, pag_u->pag_w, hun_u->len_s);
+ return 0;
+ }
+
+ // page is marked
+ //
+ if ( u3a_Mark.bit_w[blk_w] & (1U << bit_w) ) {
+ mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+ siz_w = (!mar_w[pos_w]) ? hun_u->len_s : 0;
+ }
+ // page is unmarked, allocate and initialize mark-array
+ //
+ else {
+ siz_w = hun_u->len_s;
+ mar_w = u3a_mark_alloc(hun_u->tot_s);
+ u3a_Mark.buf_w[pag_w] = mar_w - u3a_Mark.buf_w;
+ memset(mar_w, 0, (c3_z)hun_u->tot_s << 2);
+
+ // mark page metadata
+ //
+ if ( !hun_u->hun_s ) {
+ u3a_Mark.wee_w[bit_g] += _count_post(dir_p, 0);
+ mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+ }
+ else {
+ memset(mar_w, 0xff, (c3_z)hun_u->hun_s << 2);
+ u3a_Mark.wee_w[bit_g] += (c3_w)hun_u->hun_s << pag_u->log_s;
+ }
+
+ u3a_Mark.bit_w[blk_w] |= 1U << bit_w;
+ }
+
+ switch ( rat_y ) {
+ case 0: { // not refcounted
+ u3_assert( (c3_ws)mar_w[pos_w] <= 0 );
+ mar_w[pos_w] -= 1;
+ } break;
+
+ case 1: { // refcounted
+ // NB: "premarked"
+ //
+ if ( 0x80000000 == mar_w[pos_w] ) {
+ mar_w[pos_w] = 1;
+ }
+ else {
+ u3_assert( (c3_ws)mar_w[pos_w] >= 0 );
+ mar_w[pos_w] += 1;
+ }
+ } break;
+
+ case 2: { // refcounted, pre-mark
+ if ( !mar_w[pos_w] ) {
+ mar_w[pos_w] = 0x80000000;
+ }
+ } break;
+
+ default: u3_assert(0);
+ }
+
+ return siz_w;
+ }
+}
+
+static c3_w
+_sweep_counts(void)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w pag_w, blk_w, bit_w, siz_w, weq_w = 0, leq_w = 0, tot_w = 0;
+ u3_post dir_p, som_p;
+ c3_w *use_w;
+
+ // unlink leaked whole chunk-pages
+ // (we do this first so we won't need to dereference the metadata)
+ //
+ {
+ u3a_crag *pag_u;
+ u3_post *bit_p;
+ c3_g bit_g;
+
+ for ( bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) {
+ bit_p = &(HEAP.wee_p[bit_g]);
+
+ while ( *bit_p ) {
+ pag_u = u3to(u3a_crag, *bit_p);
+ pag_w = pag_u->pag_w;
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ *bit_p = pag_u->nex_p;
+ }
+ else {
+ bit_p = &(pag_u->nex_p);
+ }
+ }
+ }
+ }
+
+ for ( pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) {
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+ dir_p = dir_u[pag_w];
+
+ if ( u3a_head_pg == dir_p ) {
+ som_p = page_to_post(pag_w);
+
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ siz_w = _free_pages(som_p, pag_w, dir_p);
+ if ( 1 == siz_w ) {
+ fprintf(stderr, "palloc: leaked page %u (0x%x)\r\n", pag_w, page_to_post(pag_w));
+ }
+ else {
+ fprintf(stderr, "palloc: leaked pages %u-%u (0x%x)\r\n",
+ pag_w, pag_w + siz_w - 1, page_to_post(pag_w));
+ }
+ leq_w += siz_w << u3a_page;
+ }
+ else {
+ siz_w = _pages_size(pag_w);
+
+ if ( (c3_ws)u3a_Mark.buf_w[pag_w] > 0 ) {
+ use_w = u3to(c3_w, som_p);
+
+ if ( *use_w != u3a_Mark.buf_w[pag_w] ) {
+ fprintf(stderr, "weak: 0x%x have %u need %u\r\n", som_p, *use_w, u3a_Mark.buf_w[pag_w]);
+ *use_w = u3a_Mark.buf_w[pag_w];
+ weq_w += siz_w << u3a_page;;
+ }
+ else {
+ tot_w += siz_w << u3a_page;
+ }
+ }
+ else if ( 0x80000000 == u3a_Mark.buf_w[pag_w] ) {
+ fprintf(stderr, "sweep: error: premarked %u pages at 0x%x\r\n",
+ siz_w, som_p);
+ u3_assert(0);
+ }
+ else {
+ tot_w += siz_w << u3a_page;
+ }
+ }
+ }
+ else if ( u3a_rest_pg < dir_p ) {
+ // entire chunk page is unmarked
+ //
+ if ( !(u3a_Mark.bit_w[blk_w] & (1U << bit_w)) ) {
+ fprintf(stderr, "palloc: leaked chunk page %u\r\n", pag_w);
+ (void)_free_pages(page_to_post(pag_w), pag_w, u3a_head_pg);
+ leq_w += 1U << u3a_page;
+ }
+ else {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+ u3_post bas_p = page_to_post(pag_u->pag_w);
+ c3_w *mar_w = u3a_Mark.buf_w + u3a_Mark.buf_w[pag_w];
+ c3_w pos_w;
+
+ siz_w = hun_u->len_s;
+
+ // NB: since at least one chunk is marked,
+ // _free_words() will never free [pag_u]
+ //
+ for ( c3_s i_s = 0; i_s < hun_u->tot_s; i_s++ ) {
+ pos_w = i_s;
+ blk_w = i_s >> 5;
+ bit_w = i_s & 31;
+ som_p = bas_p + ((c3_w)i_s << pag_u->log_s);
+
+ if ( !(pag_u->map_w[blk_w] & (1U << bit_w)) ) {
+ if ( mar_w[pos_w] ) {
+ if ( (c3_ws)mar_w[pos_w] > 0 ) {
+ use_w = u3to(c3_w, som_p);
+
+ if ( *use_w != mar_w[pos_w] ) {
+ fprintf(stderr, "weak: 0x%x have %u need %u\r\n", som_p, *use_w, mar_w[pos_w]);
+ _print_chunk(stderr, som_p, siz_w);
+ *use_w = mar_w[pos_w];
+ weq_w += siz_w;
+ }
+ else {
+ tot_w += siz_w;
+ }
+ }
+ else if ( 0x80000000 == mar_w[pos_w] ) {
+ fprintf(stderr, "sweep: error: premarked 0x%x (chunk %u in page %u)\r\n",
+ som_p, i_s, pag_w);
+ u3_assert(0);
+ }
+ else {
+ if ( (c3_ws)mar_w[pos_w] < -1 ) {
+ fprintf(stderr, "alias: 0x%x count %d\r\n", som_p, (c3_ws)mar_w[pos_w]);
+ }
+ tot_w += siz_w;
+ }
+ }
+ else {
+ fprintf(stderr, "palloc: leak: 0x%x (chunk %u in page %u)\r\n", som_p, i_s, pag_w);
+
+ _print_chunk(stderr, som_p, siz_w);
+ _free_words(som_p, pag_w, dir_p);
+ leq_w += siz_w;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( leq_w ) {
+ u3a_print_memory(stderr, "palloc: sweep: leaked", leq_w);
+ // u3_assert(0);
+ }
+ if ( weq_w ) {
+ u3a_print_memory(stderr, "palloc: sweep: weaked", weq_w);
+ // u3_assert(0);
+ }
+
+ if ( u3C.wag_w & u3o_verbose ) {
+ u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Mark.len_w);
+ u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Mark.siz_w);
+ }
+
+ u3a_mark_done(); // XX move
+
+ return tot_w;
+}
+
+typedef struct {
+ u3_post dir_p;
+ c3_s log_s; // log2(len)
+ struct {
+ c3_w pag_w; // previous page in class (original number)
+ c3_s fre_s; // previous hunks available
+ c3_s pos_s; // previous hunks used
+ } pre_u;
+ c3_w mar_w[0];
+} _ca_prag;
+
+typedef struct {
+ u3_post dir_p;
+ c3_s log_s;
+ c3_w mar_w[0];
+} _ca_frag;
+
+// adapted from https://stackoverflow.com/a/27663998 and
+// https://gist.github.com/ideasman42/5921b0edfc6aa41a9ce0
+//
+static u3p(u3a_crag)
+_sort_crag(u3p(u3a_crag) hed_p)
+{
+ c3_w bon_w, biz_w = 1; // block count, size
+ u3p(u3a_crag) s_p, l_p, r_p, *tal_p;
+ c3_w l_w, r_w;
+ c3_t l_t, r_t;
+
+ do {
+ l_p = r_p = hed_p;
+
+ hed_p = 0;
+ tal_p = &hed_p;
+ bon_w = 0;
+
+ while ( l_p ) {
+ r_w = biz_w;
+
+ bon_w++;
+ for ( l_w = 0; (l_w < biz_w) && r_p; l_w++) {
+ r_p = u3to(u3a_crag, r_p)->nex_p;
+ }
+
+ l_t = (0 == l_w);
+ r_t = (0 == r_w) || !r_p;
+
+ while ( !l_t || !r_t ) {
+ if ( r_t || (!l_t && (u3to(u3a_crag, l_p)->pag_w < u3to(u3a_crag, r_p)->pag_w)) ) {
+ s_p = l_p;
+ l_p = u3to(u3a_crag, l_p)->nex_p;
+ l_w--;
+ l_t = (0 == l_w);
+ }
+ else {
+ s_p = r_p;
+ r_p = u3to(u3a_crag, r_p)->nex_p;
+ r_w--;
+ r_t = (0 == r_w) || !r_p;
+ }
+
+ *tal_p = s_p;
+ tal_p = &(u3to(u3a_crag, s_p)->nex_p);
+ }
+
+ l_p = r_p;
+ }
+
+ *tal_p = 0;
+ biz_w <<= 1;
+ }
+ while ( bon_w > 1 );
+
+ return hed_p;
+}
+
+static void
+_pack_seek_hunks(void)
+{
+ const u3a_hunk_dose *hun_u;
+ u3_post dir_p, nex_p, fre_p;
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w len_w, sum_w, i_w, *hap_w, *hum_w;
+ c3_g bit_g = u3a_crag_no;
+ u3a_crag *pag_u;
+ _ca_prag *rag_u;
+
+ struct {
+ c3_w pag_w; // previous page in class (original number)
+ c3_s fre_s; // previous hunks available
+ c3_s pos_s; // previous hunks used
+ u3_post dir_p;
+ } pre_u;
+
+ while ( bit_g-- ) {
+ if ( !HEAP.wee_p[bit_g] ) {
+ continue;
+ }
+
+ // XX investigate, should only be required on inner roads
+ //
+ HEAP.wee_p[bit_g] = _sort_crag(HEAP.wee_p[bit_g]);
+ dir_p = HEAP.wee_p[bit_g];
+ hun_u = &(u3a_Hunk[bit_g]);
+ memset(&pre_u, 0, sizeof(pre_u));
+
+ len_w = c3_wiseof(_ca_prag) + (3 * hun_u->map_s);
+
+ while ( dir_p ) {
+ pag_u = u3to(u3a_crag, dir_p);
+ nex_p = pag_u->nex_p;
+ pag_u->nex_p = 0;
+
+ u3_assert( (pre_u.pag_w < pag_u->pag_w)
+ || (!pre_u.pag_w && !pag_u->pag_w) );
+
+ rag_u = u3a_pack_alloc(len_w);
+ hap_w = &(rag_u->mar_w[hun_u->map_s]);
+ hum_w = &(hap_w[hun_u->map_s]);
+ rag_u->log_s = hun_u->log_s;
+ rag_u->pre_u.pag_w = pre_u.pag_w;
+ rag_u->pre_u.fre_s = pre_u.fre_s;
+ rag_u->pre_u.pos_s = pre_u.pos_s;
+
+ memset(rag_u->mar_w, 0, hun_u->map_s << 2);
+
+ for ( i_w = 0; i_w < hun_u->map_s; i_w++ ) {
+ hap_w[i_w] = ~(pag_u->map_w[i_w]);
+ }
+
+ if ( hun_u->tot_s < 32 ) {
+ hap_w[0] &= (1U << hun_u->tot_s) - 1;
+ }
+
+ sum_w = 0;
+ for ( i_w = 0; i_w < hun_u->map_s; i_w++ ) {
+ hum_w[i_w] = sum_w;
+ sum_w += c3_pc_w(hap_w[i_w]);
+ }
+
+ u3a_Gack.buf_w[pag_u->pag_w] = ((c3_w*)rag_u - u3a_Gack.buf_w) | (1U << 31);
+
+ c3_s pos_s = hun_u->ful_s - pag_u->fre_s;
+
+ u3_assert( (pos_s + hun_u->hun_s) == sum_w );
+
+ // there is a previous page, and it will be full
+ //
+ if ( (pos_s == pre_u.fre_s)
+ || (pre_u.dir_p && (pos_s > pre_u.fre_s)) )
+ {
+ u3a_crag *peg_u = u3to(u3a_crag, pre_u.dir_p);
+ memset(peg_u->map_w, 0, hun_u->map_s << 2);
+ peg_u->fre_s = 0;
+ }
+
+ // current page will be empty
+ //
+ if ( pos_s <= pre_u.fre_s ) {
+ rag_u->dir_p = 0;
+ dir_u[pag_u->pag_w] = u3a_free_pg;
+ fre_p = hun_u->hun_s ? 0 : dir_p;
+ }
+ else {
+ fre_p = 0;
+ }
+
+ // previous page is the same
+ //
+ if ( pos_s < pre_u.fre_s ) {
+ pre_u.fre_s -= pos_s;
+ pre_u.pos_s += pos_s;
+ }
+ // current becomes previous
+ //
+ else if ( pos_s > pre_u.fre_s ) {
+ rag_u->dir_p = dir_p;
+ pos_s -= pre_u.fre_s;
+ pre_u.fre_s += pag_u->fre_s;
+ pre_u.pag_w = pag_u->pag_w;
+ pre_u.pos_s = pos_s;
+ pre_u.dir_p = dir_p;
+ }
+ // no previous page
+ //
+ else {
+ memset(&pre_u, 0, sizeof(pre_u));
+ }
+
+ if ( fre_p ) {
+ _ifree(fre_p);
+ }
+
+ dir_p = nex_p;
+ }
+
+ HEAP.wee_p[bit_g] = pre_u.dir_p;
+
+ if ( pre_u.dir_p ) {
+ u3a_crag *peg_u = u3to(u3a_crag, pre_u.dir_p);
+ c3_s pos_s = pre_u.pos_s + hun_u->hun_s;
+ c3_s max_s = pos_s >> 5;
+
+ memset(peg_u->map_w, 0, max_s << 2);
+ peg_u->map_w[max_s++] = ~0U << (pos_s & 31);
+ memset(&(peg_u->map_w[max_s]), 0xff, (hun_u->map_s - max_s) << 2);
+
+ peg_u->fre_s = pre_u.fre_s;
+ }
+ }
+}
+
+static void
+_pack_seek(void)
+{
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ c3_w blk_w, bit_w, fre_w = 0;
+ u3_post dir_p;
+
+ {
+ u3_post fre_p;
+ u3a_dell *fre_u;
+
+ while ( (fre_p = HEAP.fre_p) ) {
+ fre_u = u3to(u3a_dell, fre_p);
+ HEAP.fre_p = fre_u->nex_p;
+ _ifree(fre_p);
+ }
+ }
+
+ _pack_seek_hunks();
+
+ for ( c3_w pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) {
+ if ( u3a_free_pg == (dir_p = dir_u[pag_w]) ) {
+ fre_w++;
+ continue;
+ }
+
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+ u3a_Gack.pap_w[blk_w] |= 1U << bit_w;
+
+ if ( u3a_rest_pg >= dir_p ) {
+ u3a_Gack.buf_w[pag_w] = dir_p;
+ }
+ // chunk page, not processed above (ie, full)
+ //
+ else if ( !u3a_Gack.buf_w[pag_w] ) {
+ u3a_crag *pag_u = u3to(u3a_crag, dir_p);
+ c3_g bit_g = pag_u->log_s - u3a_min_log;
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[bit_g]);
+
+ _ca_frag *fag_u = u3a_pack_alloc(c3_wiseof(_ca_frag) + hun_u->map_s);
+ u3a_Gack.buf_w[pag_w] = (c3_w*)fag_u - u3a_Gack.buf_w;
+
+ fag_u->dir_p = dir_p;
+ fag_u->log_s = pag_u->log_s;
+ memset(fag_u->mar_w, 0, (c3_z)hun_u->map_s << 2);
+ }
+ }
+
+ // shrink page directory
+ //
+ {
+ c3_w old_w = HEAP.siz_w >> u3a_page;
+ c3_w dif_w = (HEAP.siz_w - (HEAP.len_w - fre_w)) >> u3a_page;
+ c3_w pag_w = post_to_page(HEAP.pag_p);
+ c3_w gap_w;
+
+ for ( c3_w i_w = 0; i_w < dif_w; i_w++ ) {
+ gap_w = pag_w + (HEAP.dir_ws * (old_w - i_w - 1));
+ blk_w = gap_w >> 5;
+ bit_w = gap_w & 31;
+ u3a_Gack.buf_w[gap_w] = u3a_free_pg;
+ u3a_Gack.pap_w[blk_w] &= ~(1U << bit_w);
+ }
+
+ HEAP.siz_w -= dif_w << u3a_page;
+ }
+
+ // calculate cumulative sums of bitmap popcounts
+ //
+ {
+ c3_w sum_w = 0, max_w = (HEAP.len_w + 31) >> 5;
+
+ for ( c3_w i_w = 0; i_w < max_w; i_w++ ) {
+ u3a_Gack.pum_w[i_w] = sum_w;
+ sum_w += c3_pc_w(u3a_Gack.pap_w[i_w]);
+ }
+ }
+}
+
+static inline c3_w
+_pack_relocate_page(c3_w pag_w)
+{
+ c3_w blk_w = pag_w >> 5;
+ c3_w bit_w = pag_w & 31;
+ c3_w top_w = u3a_Gack.pap_w[blk_w] & ((1U << bit_w) - 1);
+ c3_w new_w = u3a_Gack.pum_w[blk_w]; // XX blk_w - 1, since pum_w[0] is always 0?
+
+ return new_w + c3_pc_w(top_w);
+}
+
+static inline u3_post
+_pack_relocate_hunk(_ca_prag *rag_u, c3_w pag_w, c3_w pos_w)
+{
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[rag_u->log_s - u3a_min_log]);
+ c3_w blk_w = pos_w >> 5;
+ c3_w bit_w = pos_w & 31;
+ c3_w *hap_w = &(rag_u->mar_w[hun_u->map_s]);
+ c3_w *hum_w = &(hap_w[hun_u->map_s]);
+ c3_w top_w = hap_w[blk_w] & ((1U << bit_w) - 1);
+ c3_w new_w = hum_w[blk_w]; // XX blk_w - 1, since hum_w[0] is always 0?
+
+ new_w += c3_pc_w(top_w);
+
+ if ( new_w >= hun_u->hun_s ) {
+ if ( new_w < (rag_u->pre_u.fre_s + hun_u->hun_s) ) {
+ pag_w = rag_u->pre_u.pag_w;
+ new_w += rag_u->pre_u.pos_s;
+ }
+ else {
+ new_w -= rag_u->pre_u.fre_s;
+ }
+ }
+
+ {
+ u3_post out_p = page_to_post(_pack_relocate_page(pag_w));
+ out_p += new_w << rag_u->log_s;
+ return out_p;
+ }
+}
+
+static u3_post
+_pack_relocate_mark(u3_post som_p, c3_t *fir_t)
+{
+ c3_w pag_w = post_to_page(som_p);
+ c3_w dir_w = u3a_Gack.buf_w[pag_w];
+ u3_post out_p = 0;
+ c3_t out_t = 0;
+ c3_w blk_w, bit_w;
+
+ u3_assert(som_p);
+
+ // som_p is a one-or-more page allocation
+ //
+ if ( u3a_rest_pg >= dir_w ) {
+ // XX sanity
+ blk_w = pag_w >> 5;
+ bit_w = pag_w & 31;
+
+ if ( !(u3a_Gack.bit_w[blk_w] & (1U << bit_w)) ) {
+ u3a_Gack.bit_w[blk_w] |= (1U << bit_w);
+ out_t = 1;
+ }
+
+ out_p = page_to_post(_pack_relocate_page(pag_w));
+ }
+ // som_p is a chunk in a full page (map old pag_w to new)
+ //
+ else if ( !(dir_w >> 31) ) {
+ // XX sanity
+ _ca_frag *fag_u = (void*)(u3a_Gack.buf_w + dir_w);
+ c3_w rem_w = som_p & ((1U << u3a_page) - 1);
+ c3_w pos_w = rem_w >> fag_u->log_s; // XX c/b pos_s
+
+ blk_w = pos_w >> 5;
+ bit_w = pos_w & 31;
+
+ if ( !(fag_u->mar_w[blk_w] & (1U << bit_w)) ) {
+ fag_u->mar_w[blk_w] |= (1U << bit_w);
+ out_t = 1;
+ }
+
+ out_p = page_to_post(_pack_relocate_page(pag_w));
+ out_p += rem_w;
+ }
+ // som_p is a chunk in a partial page (map old pos_w to new)
+ //
+ else {
+ _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + (dir_w & ((1U << 31) - 1)));
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> rag_u->log_s; // XX c/b pos_s
+
+ // XX sanity
+ // NB map inverted, free state updated
+
+ blk_w = pos_w >> 5;
+ bit_w = pos_w & 31;
+
+ if ( !(rag_u->mar_w[blk_w] & (1U << bit_w)) ) {
+ rag_u->mar_w[blk_w] |= (1U << bit_w);
+ out_t = 1;
+ }
+
+ out_p = _pack_relocate_hunk(rag_u, pag_w, pos_w);
+ }
+
+ *fir_t = out_t;
+ return out_p;
+}
+
+static u3_post
+_pack_relocate(u3_post som_p)
+{
+ c3_w pag_w = post_to_page(som_p);
+ c3_w dir_w = u3a_Gack.buf_w[pag_w];
+ u3_post out_p;
+
+ u3_assert(som_p);
+
+ // som_p is a one-or-more page allocation
+ //
+ if ( u3a_rest_pg >= dir_w ) {
+ // XX sanity
+ out_p = page_to_post(_pack_relocate_page(pag_w));
+ }
+ // som_p is a chunk in a full page (map old pag_w to new)
+ //
+ else if ( !(dir_w >> 31) ) {
+ // XX sanity
+ out_p = page_to_post(_pack_relocate_page(pag_w));
+ out_p += som_p & ((1U << u3a_page) - 1);
+ }
+ // som_p is a chunk in a partial page (map old pos_w to new)
+ //
+ else {
+ _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + (dir_w & ((1U << 31) - 1)));
+ c3_w pos_w = (som_p & ((1U << u3a_page) - 1)) >> rag_u->log_s; // XX c/b pos_s
+
+ // XX sanity
+ // NB map inverted, free state updated
+
+ out_p = _pack_relocate_hunk(rag_u, pag_w, pos_w);
+ }
+
+ return out_p;
+}
+
+static void
+_pack_relocate_heap(void)
+{
+ // this is possible if freeing unused u3a_crag's
+ // caused an entire hunk page to be free'd
+ // NB: this corrupts pre_p
+ //
+ if ( HEAP.fre_p ) {
+ u3a_dell *fre_u;
+
+ if ( !HEAP.cac_p ) {
+ fre_u = u3to(u3a_dell, HEAP.fre_p);
+ HEAP.cac_p = HEAP.fre_p;
+ HEAP.fre_p = fre_u->nex_p;
+ }
+
+ u3_post *ref_p = &(HEAP.fre_p);
+
+ while ( *ref_p ) {
+ fre_u = u3to(u3a_dell, *ref_p);
+ *ref_p = _pack_relocate(*ref_p);
+ ref_p = &(fre_u->nex_p);
+ }
+ }
+
+ HEAP.pag_p = _pack_relocate(HEAP.pag_p);
+
+ if ( HEAP.cac_p ) {
+ HEAP.cac_p = _pack_relocate(HEAP.cac_p);
+ }
+
+ for ( c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) {
+ if ( HEAP.wee_p[bit_g] ) {
+ HEAP.wee_p[bit_g] = _pack_relocate(HEAP.wee_p[bit_g]);
+ }
+ }
+
+ for ( c3_w pag_w = 0; pag_w < HEAP.len_w; pag_w++ ) {
+ c3_w *wor_w, dir_w = u3a_Gack.buf_w[pag_w];
+
+ if ( u3a_rest_pg < dir_w ) {
+ dir_w &= (1U << 31) - 1;
+ wor_w = u3a_Gack.buf_w + dir_w; // (fag_u | rag_u)->dir_p
+ if ( *wor_w ) {
+ u3a_crag *pag_u = u3to(u3a_crag, *wor_w);
+ pag_u->pag_w = _pack_relocate_page(pag_u->pag_w);
+ *wor_w = _pack_relocate(*wor_w);
+ }
+ }
+ }
+}
+
+static c3_i
+_pack_move_chunks(c3_w pag_w, c3_w dir_w)
+{
+ _ca_prag *rag_u = (void*)(u3a_Gack.buf_w + dir_w);
+ const u3a_hunk_dose *hun_u = &(u3a_Hunk[rag_u->log_s - u3a_min_log]);
+ c3_w *hap_w = &(rag_u->mar_w[hun_u->map_s]);
+ c3_w off_w = 1U << rag_u->log_s;
+ c3_z len_i = off_w << 2;
+ c3_w *src_w, *dst_w, new_w;
+ c3_s max_s, fre_s, new_s, pos_s = hun_u->hun_s;
+
+ src_w = u3to(c3_w, page_to_post(pag_w) + (pos_s << rag_u->log_s));
+
+ max_s = 1U << (u3a_page - rag_u->log_s);
+
+ if ( rag_u->pre_u.pag_w ) {
+ new_w = _pack_relocate_page(rag_u->pre_u.pag_w);
+ new_s = hun_u->hun_s + rag_u->pre_u.pos_s;
+ fre_s = rag_u->pre_u.fre_s;
+
+ dst_w = u3to(c3_w, page_to_post(new_w) + (new_s << rag_u->log_s));
+
+ // move up to [fre_s] chunks to (relocated) previous page
+ //
+ while ( (pos_s < max_s) && fre_s ) {
+ if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) {
+ ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i);
+ memcpy(dst_w, src_w, len_i);
+ fre_s--;
+ dst_w += off_w;
+ }
+
+ pos_s++;
+ src_w += off_w;
+ }
+
+ // advance src position past any free chunks
+ //
+ while ( (pos_s < max_s) ) {
+ if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) {
+ break;
+ }
+
+ pos_s++;
+ src_w += off_w;
+ }
+
+ if ( pos_s == max_s ) {
+ return 0;
+ }
+ }
+
+ new_w = _pack_relocate_page(pag_w);
+ new_s = hun_u->hun_s;
+
+ // skip chunks that don't need to move
+ // (possible if a partial-chunk page is in the first
+ // contiguously used pages in the heap)
+ //
+ // XX unlikely()
+ //
+ if ( new_w == pag_w ) {
+ if ( new_s == pos_s ) {
+ while ( (pos_s < max_s)
+ && (hap_w[pos_s >> 5] & (1U << (pos_s & 31))) )
+ {
+ pos_s++;
+ src_w += off_w;
+ }
+
+ new_s = pos_s++;
+ src_w += off_w;
+ }
+ }
+ // relocate inline metadata
+ //
+ else if ( hun_u->hun_s ) {
+ c3_w* soc_w = u3to(c3_w, page_to_post(pag_w));
+ c3_w* doc_w = u3to(c3_w, page_to_post(new_w));
+
+ ASAN_UNPOISON_MEMORY_REGION(doc_w, len_i * hun_u->hun_s);
+ memcpy(doc_w, soc_w, len_i * hun_u->hun_s);
+
+ // XX bump pos_s/src_w if !pos_s ?
+ }
+
+ u3_assert( (new_w < pag_w) || (new_s < pos_s) );
+
+ dst_w = u3to(c3_w, page_to_post(new_w) + (new_s << rag_u->log_s));
+
+ // move remaining chunks to relocated page
+ //
+ while ( pos_s < max_s ) {
+ if ( hap_w[pos_s >> 5] & (1U << (pos_s & 31)) ) {
+ ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i);
+ memcpy(dst_w, src_w, len_i);
+ dst_w += off_w;
+ }
+
+ pos_s++;
+ src_w += off_w;
+ }
+
+ // XX assume(rag_u->dir_p)
+ //
+ u3a_Gack.buf_w[new_w] = rag_u->dir_p;
+ return 1;
+}
+
+static void
+_pack_move(void)
+{
+ c3_z len_i = 1U << (u3a_page + 2);
+ c3_ws off_ws = HEAP.dir_ws * (1U << u3a_page);
+ c3_w dir_w, new_w, pag_w = 0;
+ c3_w *src_w, *dst_w;
+
+ // NB: these loops iterate over the temp page dir instead of
+ // the bitmap, as partial chunk pages can be marked free
+ //
+
+ // skip pages that don't need to move,
+ // compacting partial chunk-pages in-place
+ //
+ while ( (pag_w < HEAP.len_w) && (dir_w = u3a_Gack.buf_w[pag_w]) ) {
+ if ( u3a_rest_pg < dir_w ) {
+ if ( !(dir_w >> 31) ) {
+ u3a_Gack.buf_w[pag_w] = u3a_Gack.buf_w[dir_w]; // NB: fag_u->dir_p
+ }
+ else if ( !_pack_move_chunks(pag_w, dir_w & ((1U << 31) - 1)) ) {
+ break;
+ }
+ }
+
+ pag_w++;
+ }
+
+ new_w = pag_w++;
+ dst_w = u3to(c3_w, page_to_post(new_w));
+ src_w = u3to(c3_w, page_to_post(pag_w));
+
+ while( pag_w < HEAP.len_w ) {
+ // XX assume(new_w < pag_w)
+ // XX assume(new_w == _pack_relocate_page(pag_w))
+ // XX assume(dst_w == u3to(c3_w, page_to_post(new_w)))
+ // XX assume(src_w == u3to(c3_w, page_to_post(pag_w)))
+ //
+ dir_w = u3a_Gack.buf_w[pag_w];
+
+ if ( u3a_free_pg != dir_w ) {
+ if ( (u3a_rest_pg >= dir_w) || !(dir_w >> 31) ) {
+ ASAN_UNPOISON_MEMORY_REGION(dst_w, len_i);
+ memcpy(dst_w, src_w, len_i);
+ u3a_Gack.buf_w[new_w] = (u3a_rest_pg >= dir_w)
+ ? dir_w
+ : u3a_Gack.buf_w[dir_w]; // NB: fag_u->dir_p
+ new_w++;
+ dst_w += off_ws;
+ }
+ else if ( _pack_move_chunks(pag_w, dir_w & ((1U << 31) - 1)) ) {
+ new_w++;
+ dst_w += off_ws;
+ }
+ }
+
+ pag_w++;
+ src_w += off_ws;
+ fflush(stderr); // XX remove
+ }
+
+ _poison_words();
+
+ {
+ u3p(u3a_crag) *dir_u = u3to(u3p(u3a_crag), HEAP.pag_p);
+ HEAP.len_w = new_w;
+ memcpy(dir_u, u3a_Gack.buf_w, new_w << 2);
+ memset(dir_u + new_w, 0, (HEAP.siz_w - new_w) << 2);
+ }
+
+ u3a_print_memory(stderr, "palloc: off-heap: used", u3a_Gack.len_w);
+ u3a_print_memory(stderr, "palloc: off-heap: total", u3a_Gack.siz_w);
+
+ {
+ u3a_dell *fre_u;
+ u3_post fre_p;
+
+ while ( (fre_p = HEAP.fre_p) ) {
+ fre_u = u3to(u3a_dell, fre_p);
+ HEAP.fre_p = fre_u->nex_p;
+ _ifree(fre_p);
+ }
+ }
+}
diff --git a/vere/pkg/noun/palloc_tests.c b/vere/pkg/noun/palloc_tests.c
new file mode 100644
index 0000000..b93f634
--- /dev/null
+++ b/vere/pkg/noun/palloc_tests.c
@@ -0,0 +1,91 @@
+/// @file
+
+#include "events.h"
+
+struct heap {
+ u3p(u3a_dell) fre_p; // free list
+ u3p(u3a_dell) erf_p; // free list
+ u3p(u3a_dell) cac_p; // cached pgfree struct
+ u3_post bot_p; // XX s/b rut_p
+ c3_ws dir_ws; // 1 || -1 (multiplicand for local offsets)
+ c3_ws off_ws; // 0 || -1 (word-offset for hat && rut)
+ c3_w siz_w; // directory size
+ c3_w len_w; // directory entries
+ u3p(u3a_crag*) pag_p; // directory
+ u3p(u3a_crag) wee_p[u3a_crag_no]; // chunk lists
+};
+
+struct heap hep_u;
+
+#define HEAP (hep_u)
+#define BASE (hep_u.bot_p)
+
+#include "./palloc.c"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_init(1 << 22);
+ u3e_init();
+ u3m_pave(c3y);
+}
+
+static void
+_test_print_chunks(void)
+{
+ u3a_hunk_dose *hun_u;
+ c3_g met_g;
+ c3_w hun_w;
+
+ for ( c3_g bit_g = 0; bit_g < u3a_crag_no; bit_g++ ) {
+ hun_u = &(u3a_Hunk[bit_g]);
+ met_g = (c3_g)c3_bits_word((c3_w)hun_u->siz_s - 1) - u3a_min_log;
+ hun_w = 1U + ((hun_u->siz_s - 1) >> hun_u->log_s);
+
+ fprintf(stderr, "chunks: %s pginfo: bit=%u log=%u len=%u tot=%u, siz=%u, chunks=%u met=%u\n",
+ ( hun_u->hun_s ? "inline" : "malloc" ), bit_g,
+ hun_u->log_s, hun_u->len_s, hun_u->tot_s, hun_u->siz_s, hun_w, met_g);
+ }
+}
+
+static void
+_test_print_pages(c3_w max_w)
+{
+ u3_post pot_p;
+ c3_w i_w;
+
+ hep_u.dir_ws = 1;
+ hep_u.off_ws = 0;
+ hep_u.bot_p = 0x1000;
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ pot_p = page_to_post(i_w);
+ fprintf(stderr, "north at bot=0x%x pag=%u == 0x%x == pag=%u\n",
+ hep_u.bot_p, i_w, pot_p, post_to_page(pot_p));
+ }
+
+
+ hep_u.dir_ws = -1;
+ hep_u.off_ws = -1;
+ hep_u.bot_p += max_w << u3a_page;
+
+ for ( i_w = 0; i_w < max_w; i_w++ ) {
+ pot_p = page_to_post(i_w);
+ fprintf(stderr, "south at bot=0x%x pag=%u == 0x%x == pag=%u\n",
+ hep_u.bot_p, i_w, pot_p, post_to_page(pot_p));
+ }
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ _test_print_chunks();
+ _test_print_pages(10);
+ return 0;
+}
diff --git a/vere/pkg/noun/platform/darwin/rsignal.h b/vere/pkg/noun/platform/darwin/rsignal.h
new file mode 100644
index 0000000..a14670e
--- /dev/null
+++ b/vere/pkg/noun/platform/darwin/rsignal.h
@@ -0,0 +1,13 @@
+/// @file
+
+#ifndef NOUN_PLATFORM_DARWIN_RSIGNAL_H
+#define NOUN_PLATFORM_DARWIN_RSIGNAL_H
+
+#define rsignal_jmpbuf sigjmp_buf
+#define rsignal_setjmp(buf) sigsetjmp((buf), 1)
+#define rsignal_longjmp siglongjmp
+#define rsignal_install_handler signal
+#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN)
+#define rsignal_setitimer setitimer
+
+#endif /* ifndef NOUN_PLATFORM_DARWIN_RSIGNAL_H */
diff --git a/vere/pkg/noun/platform/linux/rsignal.h b/vere/pkg/noun/platform/linux/rsignal.h
new file mode 100644
index 0000000..9c55cee
--- /dev/null
+++ b/vere/pkg/noun/platform/linux/rsignal.h
@@ -0,0 +1,13 @@
+/// @file
+
+#ifndef NOUN_PLATFORM_LINUX_RSIGNAL_H
+#define NOUN_PLATFORM_LINUX_RSIGNAL_H
+
+#define rsignal_jmpbuf sigjmp_buf
+#define rsignal_setjmp(buf) sigsetjmp((buf), 1)
+#define rsignal_longjmp siglongjmp
+#define rsignal_install_handler signal
+#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN)
+#define rsignal_setitimer setitimer
+
+#endif /* ifndef NOUN_PLATFORM_LINUX_RSIGNAL_H */
diff --git a/vere/pkg/noun/platform/windows/rsignal.c b/vere/pkg/noun/platform/windows/rsignal.c
new file mode 100644
index 0000000..d927835
--- /dev/null
+++ b/vere/pkg/noun/platform/windows/rsignal.c
@@ -0,0 +1,167 @@
+#include "noun.h"
+#include "rsignal.h"
+#include <windows.h>
+
+int err_win_to_posix(DWORD winerr);
+
+// The current implementation of rsignal_ is single-threaded,
+// but it can be extended to multi-threaded by replacing these
+// static variables with a thread id-based hash map.
+//
+static __p_sig_fn_t _fns[SIG_COUNT];
+static volatile DWORD _tid;
+static HANDLE _hvt;
+
+void rsignal_install_handler(int sig, __p_sig_fn_t fn)
+{
+ if (sig < 0 || sig >= SIG_COUNT)
+ return;
+
+ DWORD newtid = GetCurrentThreadId();
+ DWORD oldtid = InterlockedExchange((volatile LONG*)&_tid, newtid);
+ if (oldtid != 0 && oldtid != newtid) {
+ fprintf(stderr, "\r\nrsignal_install_handler: %lu -> %lu\r\n", oldtid, newtid);
+ return;
+ }
+
+ __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], fn);
+ if (fn != 0 && oldfn != 0 && oldfn != fn) {
+ fprintf(stderr, "\r\nrsignal_install_handler: %p -> %p\r\n", oldfn, fn);
+ }
+}
+
+void rsignal_deinstall_handler(int sig)
+{
+ rsignal_install_handler(sig, 0);
+}
+
+void rsignal_raise(int sig)
+{
+ if (sig < 0 || sig >= SIG_COUNT)
+ return;
+
+ __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], 0);
+ if (oldfn == 0)
+ return;
+
+ if (_tid == GetCurrentThreadId()) {
+ oldfn(sig);
+ return;
+ }
+
+ HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, _tid);
+ if (!hthread) {
+ fprintf(stderr, "\r\nrsignal_raise: OpenThread(%lu): %lu\r\n", _tid, GetLastError());
+ return;
+ }
+
+ if (SuspendThread(hthread) < 0) {
+ fprintf(stderr, "\r\nrsignal_raise: SuspendThread(%lu): %lu\r\n", _tid, GetLastError());
+ goto cleanup;
+ }
+
+ oldfn(sig);
+
+ if (!ResumeThread(hthread)) {
+ fprintf(stderr, "\r\nrsignal_raise: ResumeThread(%lu): %lu\r\n", _tid, GetLastError());
+
+ // abort because the main thread is stuck
+ abort();
+ }
+
+cleanup:
+ CloseHandle(hthread);
+}
+
+static void _rsignal_vt_cb(PVOID param, BOOLEAN timedOut)
+{
+ rsignal_raise(SIGVTALRM);
+}
+
+int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out)
+{
+ if (in == 0) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (type != ITIMER_VIRTUAL || out != 0) {
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ if (_hvt != NULL) {
+ DeleteTimerQueueTimer(NULL, _hvt, NULL);
+ _hvt = NULL;
+ }
+
+ if (timerisset(&in->it_value) && !CreateTimerQueueTimer(&_hvt, NULL, _rsignal_vt_cb, NULL,
+ in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000,
+ in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000, 0))
+ {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+// direct import from ntdll.dll
+extern DWORD64 __imp_KiUserExceptionDispatcher;
+
+static void _rsignal_longjmp(intptr_t* builtin_jb)
+{
+ __builtin_longjmp((void**)builtin_jb, 1);
+}
+
+void rsignal_post_longjmp(DWORD tid, intptr_t* builtin_jb)
+{
+ HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
+ if (!hthread) {
+ fprintf(stderr, "\r\nrsignal: OpenThread(%lu): %lu\r\n", tid, GetLastError());
+ return;
+ }
+
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+ if (!GetThreadContext(hthread, &context)) {
+ fprintf(stderr, "\r\nrsignal: GetThreadContext(%lu): %lu\r\n", tid, GetLastError());
+ goto cleanup;
+ }
+
+ // see if the thread is currently handling a structured exception
+ // if so, let the handler (usually the libsigsegv handler) finish
+ // and set up the the signal to run at the exception resume point
+ // otherwise, passing a parameter to fn is completely unreliable
+ //
+ DWORD64 kibase;
+ PRUNTIME_FUNCTION ki = RtlLookupFunctionEntry(__imp_KiUserExceptionDispatcher, &kibase, NULL);
+ CONTEXT c = context;
+ while (1)
+ {
+ DWORD64 base, frame;
+ PRUNTIME_FUNCTION f = RtlLookupFunctionEntry(c.Rip, &base, NULL);
+ if (!f) break;
+ if (f == ki)
+ {
+ // KiUserExceptionDispatcher has a "bare" frame
+ // with $rsp pointing to the CONTEXT structure
+ //
+ ((PCONTEXT)c.Rsp)->Rip = (DWORD64)_rsignal_longjmp;
+ ((PCONTEXT)c.Rsp)->Rcx = (DWORD64)builtin_jb;
+ goto cleanup;
+ }
+ PVOID handler_data;
+ RtlVirtualUnwind(0, base, c.Rip, f, &c, &handler_data, &frame, NULL);
+ }
+
+ context.Rip = (DWORD64)_rsignal_longjmp;
+ context.Rcx = (DWORD64)builtin_jb;
+ if (!SetThreadContext(hthread, &context)) {
+ fprintf(stderr, "\r\nrsignal: SetThreadContext(%lu): %lu\r\n", tid, GetLastError());
+ goto cleanup;
+ }
+
+cleanup:
+ CloseHandle(hthread);
+}
diff --git a/vere/pkg/noun/platform/windows/rsignal.h b/vere/pkg/noun/platform/windows/rsignal.h
new file mode 100644
index 0000000..998652c
--- /dev/null
+++ b/vere/pkg/noun/platform/windows/rsignal.h
@@ -0,0 +1,21 @@
+#include "windows.h"
+
+#ifndef _RSIGNAL_H
+#define _RSIGNAL_H
+
+#define rsignal_setjmp setjmp
+#define rsignal_longjmp longjmp
+
+void rsignal_raise(int sig);
+void rsignal_install_handler(int sig, __p_sig_fn_t fn);
+void rsignal_deinstall_handler(int sig);
+void rsignal_post_longjmp(unsigned long tid, intptr_t* builtin_jb);
+
+#define ITIMER_VIRTUAL 1
+struct itimerval {
+ struct timeval it_value, it_interval;
+};
+
+int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out);
+
+#endif//_RSIGNAL_H
diff --git a/vere/pkg/noun/platform/windows/veh_handler.c b/vere/pkg/noun/platform/windows/veh_handler.c
new file mode 100644
index 0000000..d2a035c
--- /dev/null
+++ b/vere/pkg/noun/platform/windows/veh_handler.c
@@ -0,0 +1,26 @@
+#include "noun.h"
+#include "rsignal.h"
+
+c3_i
+u3m_fault(void* adr_v, c3_i ser_i);
+
+/* _windows_exception_filter: replaces libsigsegv on windows
+ using vectored exception handling
+ */
+LONG WINAPI
+_windows_exception_filter(struct _EXCEPTION_POINTERS *ExceptionInfo)
+{
+ EXCEPTION_RECORD ExceptionRecord = *ExceptionInfo->ExceptionRecord;
+ if (ExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
+ ExceptionRecord.ExceptionInformation[0] == 1 &&
+ u3m_fault((void*)ExceptionRecord.ExceptionInformation[1], 1))
+ {
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if (ExceptionRecord.ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
+ rsignal_raise(SIGSTK);
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
diff --git a/vere/pkg/noun/platform/windows/veh_handler.h b/vere/pkg/noun/platform/windows/veh_handler.h
new file mode 100644
index 0000000..dfa4b69
--- /dev/null
+++ b/vere/pkg/noun/platform/windows/veh_handler.h
@@ -0,0 +1 @@
+LONG WINAPI _windows_exception_filter(struct _EXCEPTION_POINTERS *ExceptionInfo);
diff --git a/vere/pkg/noun/retrieve.c b/vere/pkg/noun/retrieve.c
new file mode 100644
index 0000000..3d2e182
--- /dev/null
+++ b/vere/pkg/noun/retrieve.c
@@ -0,0 +1,1943 @@
+/// @file
+
+#include "retrieve.h"
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "murmur3.h"
+#include "trace.h"
+#include "xtract.h"
+
+
+// declarations of inline functions
+//
+c3_o
+u3r_cell(u3_noun a, u3_noun* b, u3_noun* c);
+c3_o
+u3r_trel(u3_noun a, u3_noun* b, u3_noun* c, u3_noun* d);
+c3_o
+u3r_qual(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e);
+c3_o
+u3r_quil(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f);
+c3_o
+u3r_hext(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f,
+ u3_noun* g);
+
+/* _frag_word(): fast fragment/branch prediction for top word.
+*/
+static u3_weak
+_frag_word(c3_w a_w, u3_noun b)
+{
+ u3_assert(0 != a_w);
+
+ {
+ c3_w dep_w = u3x_dep(a_w);
+
+ while ( dep_w ) {
+ if ( c3n == u3a_is_cell(b) ) {
+ return u3_none;
+ }
+ else {
+ u3a_cell* b_u = u3a_to_ptr(b);
+
+ b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1))));
+ dep_w--;
+ }
+ }
+ return b;
+ }
+}
+
+/* _frag_deep(): fast fragment/branch for deep words.
+*/
+static u3_weak
+_frag_deep(c3_w a_w, u3_noun b)
+{
+ c3_w dep_w = 32;
+
+ while ( dep_w ) {
+ if ( c3n == u3a_is_cell(b) ) {
+ return u3_none;
+ }
+ else {
+ u3a_cell* b_u = u3a_to_ptr(b);
+
+ b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1))));
+ dep_w--;
+ }
+ }
+ return b;
+}
+
+/* u3r_at():
+**
+** Return fragment (a) of (b), or u3_none if not applicable.
+*/
+u3_weak
+u3r_at(u3_atom a, u3_noun b)
+{
+ u3_assert(u3_none != a);
+ u3_assert(u3_none != b);
+
+ u3t_on(far_o);
+
+ if ( 0 == a ) {
+ u3t_off(far_o);
+ return u3_none;
+ }
+
+ if ( _(u3a_is_cat(a)) ) {
+ u3t_off(far_o);
+ return _frag_word(a, b);
+ }
+ else {
+ if ( !_(u3a_is_pug(a)) ) {
+ u3t_off(far_o);
+ return u3_none;
+ }
+ else {
+ u3a_atom* a_u = u3a_to_ptr(a);
+ c3_w len_w = a_u->len_w;
+
+ b = _frag_word(a_u->buf_w[len_w - 1], b);
+ len_w -= 1;
+
+ if ( u3_none == b ) {
+ u3t_off(far_o);
+ return b;
+ }
+
+ while ( len_w ) {
+ b = _frag_deep(a_u->buf_w[len_w - 1], b);
+
+ if ( u3_none == b ) {
+ u3t_off(far_o);
+
+ return b;
+ } else {
+ len_w--;
+ }
+ }
+ u3t_off(far_o);
+
+ return b;
+ }
+ }
+}
+
+/* u3r_mean():
+**
+** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates.
+** Axes must be sorted in tree order.
+*/
+ struct _mean_pair {
+ c3_w axe_w;
+ u3_noun* som;
+ };
+
+ static c3_w
+ _mean_cut(c3_w len_w,
+ struct _mean_pair* prs_m)
+ {
+ c3_w i_w, cut_t, cut_w;
+
+ cut_t = 0;
+ cut_w = 0;
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w axe_w = prs_m[i_w].axe_w;
+
+ if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) {
+ cut_t = 1;
+ cut_w = i_w;
+ }
+ prs_m[i_w].axe_w = u3x_mas(axe_w);
+ }
+ return cut_t ? cut_w : i_w;
+ }
+
+ static c3_o
+ _mean_extract(u3_noun som,
+ c3_w len_w,
+ struct _mean_pair* prs_m)
+ {
+ if ( len_w == 0 ) {
+ return c3y;
+ }
+ else if ( (len_w == 1) && (1 == prs_m[0].axe_w) ) {
+ *prs_m->som = som;
+ return c3y;
+ }
+ else {
+ if ( c3n == u3a_is_cell(som) ) {
+ return c3n;
+ } else {
+ c3_w cut_w = _mean_cut(len_w, prs_m);
+
+ return c3a
+ (_mean_extract(u3a_h(som), cut_w, prs_m),
+ _mean_extract(u3a_t(som), (len_w - cut_w), (prs_m + cut_w)));
+ }
+ }
+ }
+
+c3_o
+u3r_vmean(u3_noun som, va_list ap)
+{
+ va_list aq;
+ c3_w len_w;
+ struct _mean_pair* prs_m;
+
+ u3_assert(u3_none != som);
+
+ // traverse copy of va_list for alloca
+ //
+ va_copy(aq, ap);
+ len_w = 0;
+
+ while ( 1 ) {
+ if ( 0 == va_arg(aq, c3_w) ) {
+ break;
+ }
+ va_arg(aq, u3_noun*);
+ len_w++;
+ }
+
+ va_end(aq);
+
+ u3_assert( 0 != len_w );
+ prs_m = alloca(len_w * sizeof(struct _mean_pair));
+
+ // traverse va_list and extract args
+ //
+ {
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ prs_m[i_w].axe_w = va_arg(ap, c3_w);
+ prs_m[i_w].som = va_arg(ap, u3_noun*);
+ }
+
+ va_end(ap);
+ }
+
+ // extract axis from som
+ //
+ return _mean_extract(som, len_w, prs_m);
+}
+
+c3_o
+u3r_mean(u3_noun som, ...)
+{
+ c3_o ret_o;
+ va_list ap;
+
+ va_start(ap, som);
+ ret_o = u3r_vmean(som, ap);
+ va_end(ap);
+
+ return ret_o;
+}
+
+// stack frame for tracking noun comparison and unification
+//
+// we always compare arbitrary nouns in a none-frame.
+// when we compare two cells, we change the none-frame to a head-frame
+// and push a new none-frame for their heads. if the heads are equal,
+// we get the cells from the head-frame and unify their head pointers.
+// then, we convert the head-frame to a tail-frame and repeat with
+// the tails, mutatis mutandis.
+//
+// in Hoon, this structure would be:
+//
+// $% [%none a=* b=*]
+// [%head a=^ b=^]
+// [%tail a=^ b=^]
+// ==
+//
+#define SING_NONE 0
+#define SING_HEAD 1
+#define SING_TAIL 2
+
+typedef struct {
+ c3_y sat_y;
+ u3_noun a;
+ u3_noun b;
+} eqframe;
+
+/* _cr_sing_push(): push a new stack frame, initialized as SING_NONE.
+*/
+static inline eqframe*
+_cr_sing_push(u3a_pile* pil_u, u3_noun a, u3_noun b)
+{
+ eqframe* fam_u = u3a_push(pil_u);
+ fam_u->sat_y = SING_NONE;
+ fam_u->a = a;
+ fam_u->b = b;
+ return fam_u;
+}
+
+/* _cr_sing_mug(): short-circuit comparison if mugs are present and not equal.
+*/
+static inline c3_o
+_cr_sing_mug(u3a_noun* a_u, u3a_noun* b_u)
+{
+ // XX add debug assertions that both mugs are 31-bit
+ // (ie, not u3a_take() relocation references)
+ //
+ if ( a_u->mug_w && b_u->mug_w && (a_u->mug_w != b_u->mug_w) ) {
+ return c3n;
+ }
+
+ return c3y;
+}
+
+/* _cr_sing_atom(): check if atom [a] is indirect and equal to noun [b]
+*/
+static inline c3_o
+_cr_sing_atom(u3_atom a, u3_noun b)
+{
+ // [a] is an atom, not pointer-equal to noun [b].
+ // if they're not both indirect atoms, they can't be equal.
+ //
+ if ( (c3n == u3a_is_pug(a))
+ || (c3n == u3a_is_pug(b)) )
+ {
+ return c3n;
+ }
+ else {
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ // [a] and [b] are not equal if their mugs are present and not equal.
+ //
+ if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) {
+ return c3n;
+ }
+ else {
+ c3_w a_w = a_u->len_w;
+ c3_w b_w = b_u->len_w;
+
+ // [a] and [b] are not equal if their lengths are not equal
+ //
+ if ( a_w != b_w ) {
+ return c3n;
+ }
+ else {
+ c3_w i_w;
+
+ // XX memcmp
+ //
+ for ( i_w = 0; i_w < a_w; i_w++ ) {
+ if ( a_u->buf_w[i_w] != b_u->buf_w[i_w] ) {
+ return c3n;
+ }
+ }
+ }
+ }
+ }
+
+ return c3y;
+}
+
+/* _cr_sing_cape_test(): check for previous comparison of [a] and [b].
+*/
+static inline c3_o
+_cr_sing_cape_test(u3p(u3h_root) har_p, u3_noun a, u3_noun b)
+{
+ u3_noun key = u3nc(u3a_to_off(a) >> u3a_vits,
+ u3a_to_off(b) >> u3a_vits);
+ u3_noun val;
+
+ u3t_off(euq_o);
+ val = u3h_git(har_p, key);
+ u3t_on(euq_o);
+
+ u3z(key);
+ return ( u3_none != val ) ? c3y : c3n;
+}
+
+/* _cr_sing_cape_keep(): store [a] and [b] to short-circuit subsequent tests.
+** NB: [a] and [b] (which MUST be equal nouns)
+** are cons'd as offsets (direct atoms) to avoid refcount churn.
+*/
+static inline void
+_cr_sing_cape_keep(u3p(u3h_root) har_p, u3_noun a, u3_noun b)
+{
+ // only store if [a] and [b] are copies of each other
+ //
+ if ( a != b ) {
+ c3_dessert( (c3n == u3a_is_cat(a)) && (c3n == u3a_is_cat(b)) );
+
+ u3_noun key = u3nc(u3a_to_off(a) >> u3a_vits,
+ u3a_to_off(b) >> u3a_vits);
+ u3t_off(euq_o);
+ u3h_put(har_p, key, c3y);
+ u3t_on(euq_o);
+ u3z(key);
+ }
+}
+
+static inline __attribute__((always_inline)) void
+_cr_sing_wed(u3_noun *restrict a, u3_noun *restrict b)
+{
+ if ( *a != *b ) {
+ u3a_wed(a, b);
+ }
+}
+
+/* _cr_sing_cape(): unifying equality with comparison deduplication
+ * (tightly coupled to _cr_sing)
+ */
+static c3_o
+_cr_sing_cape(u3a_pile* pil_u, u3p(u3h_root) har_p)
+{
+ eqframe* fam_u = u3a_peek(pil_u);
+ u3_noun a, b;
+ u3a_cell* a_u;
+ u3a_cell* b_u;
+
+ // loop while arguments remain on the stack
+ //
+ do {
+ a = fam_u->a;
+ b = fam_u->b;
+
+ switch ( fam_u->sat_y ) {
+
+ // [a] and [b] are arbitrary nouns
+ //
+ case SING_NONE: {
+ if ( a == b ) {
+ break;
+ }
+ else if ( c3y == u3a_is_atom(a) ) {
+ if ( c3n == _cr_sing_atom(a, b) ) {
+ return c3n;
+ }
+ else {
+ break;
+ }
+ }
+ else if ( c3y == u3a_is_atom(b) ) {
+ return c3n;
+ }
+ // [a] and [b] are cells
+ //
+ else {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+
+ // short-circuiting mug check
+ //
+ if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) {
+ return c3n;
+ }
+ // short-circuiting re-comparison check
+ //
+ else if ( c3y == _cr_sing_cape_test(har_p, a, b) ) {
+ fam_u = u3a_pop(pil_u);
+ continue;
+ }
+ // upgrade none-frame to head-frame, check heads
+ //
+ else {
+ fam_u->sat_y = SING_HEAD;
+ fam_u = _cr_sing_push(pil_u, a_u->hed, b_u->hed);
+ continue;
+ }
+ }
+ } break;
+
+ // cells [a] and [b] have equal heads
+ //
+ case SING_HEAD: {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+ _cr_sing_wed(&(a_u->hed), &(b_u->hed));
+
+ // upgrade head-frame to tail-frame, check tails
+ //
+ fam_u->sat_y = SING_TAIL;
+ fam_u = _cr_sing_push(pil_u, a_u->tel, b_u->tel);
+ continue;
+ }
+
+ // cells [a] and [b] are equal
+ //
+ case SING_TAIL: {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+ _cr_sing_wed(&(a_u->tel), &(b_u->tel));
+ } break;
+
+ default: {
+ u3_assert(0);
+ } break;
+ }
+
+ // track equal pairs to short-circuit possible (re-)comparison
+ //
+ _cr_sing_cape_keep(har_p, a, b);
+
+ fam_u = u3a_pop(pil_u);
+ }
+ while ( c3n == u3a_pile_done(pil_u) );
+
+ return c3y;
+}
+
+/* _cr_sing(): unifying equality.
+*/
+static c3_o
+_cr_sing(u3_noun a, u3_noun b)
+{
+ c3_s ovr_s = 0;
+ u3a_cell* a_u;
+ u3a_cell* b_u;
+ eqframe* fam_u;
+ u3a_pile pil_u;
+
+ // initialize stack control, push arguments onto the stack (none-frame)
+ //
+ u3a_pile_prep(&pil_u, sizeof(eqframe));
+ fam_u = _cr_sing_push(&pil_u, a, b);
+
+ // loop while arguments are on the stack
+ //
+ while ( c3n == u3a_pile_done(&pil_u) ) {
+ a = fam_u->a;
+ b = fam_u->b;
+
+ switch ( fam_u->sat_y ) {
+
+ // [a] and [b] are arbitrary nouns
+ //
+ case SING_NONE: {
+ if ( a == b ) {
+ break;
+ }
+ else if ( c3y == u3a_is_atom(a) ) {
+ if ( c3n == _cr_sing_atom(a, b) ) {
+ u3R->cap_p = pil_u.top_p;
+ return c3n;
+ }
+ else {
+ break;
+ }
+ }
+ else if ( c3y == u3a_is_atom(b) ) {
+ u3R->cap_p = pil_u.top_p;
+ return c3n;
+ }
+ // [a] and [b] are cells
+ //
+ else {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+
+ // short-circuiting mug check
+ //
+ if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) {
+ u3R->cap_p = pil_u.top_p;
+ return c3n;
+ }
+ // upgrade none-frame to head-frame, check heads
+ //
+ else {
+ fam_u->sat_y = SING_HEAD;
+ fam_u = _cr_sing_push(&pil_u, a_u->hed, b_u->hed);
+ continue;
+ }
+ }
+ } break;
+
+ // cells [a] and [b] have equal heads
+ //
+ case SING_HEAD: {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+ _cr_sing_wed(&(a_u->hed), &(b_u->hed));
+
+ // upgrade head-frame to tail-frame, check tails
+ //
+ fam_u->sat_y = SING_TAIL;
+ fam_u = _cr_sing_push(&pil_u, a_u->tel, b_u->tel);
+ continue;
+ }
+
+ // cells [a] and [b] are equal
+ //
+ case SING_TAIL: {
+ a_u = u3a_to_ptr(a);
+ b_u = u3a_to_ptr(b);
+ _cr_sing_wed(&(a_u->tel), &(b_u->tel));
+ } break;
+
+ default: {
+ u3_assert(0);
+ } break;
+ }
+
+ // [ovr_s] counts comparisons, if it overflows, we've likely hit
+ // a pathological case (highly duplicated tree), so we de-duplicate
+ // subsequent comparisons by maintaining a set of equal pairs.
+ //
+ if ( 0 == ++ovr_s ) {
+ u3p(u3h_root) har_p = u3h_new();
+ c3_o ret_o = _cr_sing_cape(&pil_u, har_p);
+ u3h_free(har_p);
+ u3R->cap_p = pil_u.top_p;
+ return ret_o;
+ }
+
+ fam_u = u3a_pop(&pil_u);
+ }
+
+ return c3y;
+}
+
+/* u3r_sing(): Yes iff [a] and [b] are the same noun.
+*/
+c3_o
+u3r_sing(u3_noun a, u3_noun b)
+{
+ c3_o ret_o;
+ u3t_on(euq_o);
+ ret_o = _cr_sing(a, b);
+ u3t_off(euq_o);
+ return ret_o;
+}
+
+c3_o
+u3r_fing(u3_noun a,
+ u3_noun b)
+{
+ return (a == b) ? c3y : c3n;
+}
+
+/* u3r_sing_cell():
+**
+** Yes iff `[p q]` and `b` are the same noun.
+*/
+c3_o
+u3r_sing_cell(u3_noun p,
+ u3_noun q,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_sing(p, u3a_h(b)),
+ u3r_sing(q, u3a_t(b))));
+}
+c3_o
+u3r_fing_cell(u3_noun p,
+ u3_noun q,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_fing(p, u3a_h(b)),
+ u3r_fing(q, u3a_t(b))));
+}
+
+/* u3r_sing_mixt():
+**
+** Yes iff `[p q]` and `b` are the same noun.
+*/
+c3_o
+u3r_sing_mixt(const c3_c* p_c,
+ u3_noun q,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_sing_c(p_c, u3a_h(b)),
+ u3r_sing(q, u3a_t(b))));
+}
+c3_o
+u3r_fing_mixt(const c3_c* p_c,
+ u3_noun q,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_sing_c(p_c, u3a_h(b)),
+ u3r_fing(q, u3a_t(b))));
+}
+
+/* u3r_sing_trel():
+**
+** Yes iff `[p q r]` and `b` are the same noun.
+*/
+c3_o
+u3r_sing_trel(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_sing(p, u3a_h(b)),
+ u3r_sing_cell(q, r, u3a_t(b))));
+}
+c3_o
+u3r_fing_trel(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_fing(p, u3a_h(b)),
+ u3r_fing_cell(q, r, u3a_t(b))));
+}
+
+/* u3r_sing_qual():
+**
+** Yes iff `[p q r]` and `b` are the same noun.
+*/
+c3_o
+u3r_sing_qual(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun s,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_sing(p, u3a_h(b)),
+ u3r_sing_trel(q, r, s, u3a_t(b))));
+}
+c3_o
+u3r_fing_qual(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun s,
+ u3_noun b)
+{
+ return c3a(_(u3a_is_cell(b)),
+ c3a(u3r_fing(p, u3a_h(b)),
+ u3r_fing_trel(q, r, s, u3a_t(b))));
+}
+
+/* u3r_nord():
+**
+** Return 0, 1 or 2 if `a` is below, equal to, or above `b`.
+*/
+u3_atom
+u3r_nord(u3_noun a,
+ u3_noun b)
+{
+ u3_assert(u3_none != a);
+ u3_assert(u3_none != b);
+
+ if ( a == b ) {
+ return 1;
+ }
+ else {
+ if ( _(u3a_is_atom(a)) ) {
+ if ( !_(u3a_is_atom(b)) ) {
+ return 0;
+ } else {
+ if ( _(u3a_is_cat(a)) ) {
+ if ( _(u3a_is_cat(b)) ) {
+ return (a < b) ? 0 : 2;
+ }
+ else return 0;
+ }
+ else if ( _(u3a_is_cat(b)) ) {
+ return 2;
+ }
+ else {
+ u3a_atom* a_u = u3a_to_ptr(a);
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ c3_w w_rez = a_u->len_w;
+ c3_w w_mox = b_u->len_w;
+
+ if ( w_rez != w_mox ) {
+ return (w_rez < w_mox) ? 0 : 2;
+ }
+ else {
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < w_rez; i_w++ ) {
+ c3_w ai_w = a_u->buf_w[i_w];
+ c3_w bi_w = b_u->buf_w[i_w];
+
+ if ( ai_w != bi_w ) {
+ return (ai_w < bi_w) ? 0 : 2;
+ }
+ }
+ return 1;
+ }
+ }
+ }
+ } else {
+ if ( _(u3a_is_atom(b)) ) {
+ return 2;
+ } else {
+ u3_atom c = u3r_nord(u3a_h(a), u3a_h(b));
+
+ if ( 1 == c ) {
+ return u3r_nord(u3a_t(a), u3a_t(b));
+ } else {
+ return c;
+ }
+ }
+ }
+ }
+}
+
+/* u3r_sing_c(): cord/C-string value equivalence.
+*/
+c3_o
+u3r_sing_c(const c3_c* a_c,
+ u3_noun b)
+{
+ u3_assert(u3_none != b);
+
+ if ( !_(u3a_is_atom(b)) ) {
+ return c3n;
+ }
+ else {
+ c3_w w_sof = strlen(a_c);
+ c3_w i_w;
+
+ if ( w_sof != u3r_met(3, b) ) {
+ return c3n;
+ }
+ for ( i_w = 0; i_w < w_sof; i_w++ ) {
+ if ( u3r_byte(i_w, b) != a_c[i_w] ) {
+ return c3n;
+ }
+ }
+ return c3y;
+ }
+}
+
+/* u3r_bush():
+**
+** Factor [a] as a bush [b.[p q] c].
+*/
+c3_o
+u3r_bush(u3_noun a,
+ u3_noun* b,
+ u3_noun* c)
+{
+ u3_assert(u3_none != a);
+
+ if ( _(u3a_is_atom(a)) ) {
+ return c3n;
+ }
+ else {
+ *b = u3a_h(a);
+
+ if ( _(u3a_is_atom(*b)) ) {
+ return c3n;
+ } else {
+ *c = u3a_t(a);
+ return c3y;
+ }
+ }
+}
+
+/* u3r_bite(): retrieve/default $bloq and $step from $bite.
+*/
+c3_o
+u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step)
+{
+ u3_noun hed, tal;
+
+ if ( c3n == u3r_cell(bite, &hed, &tal) ) {
+ *bloq = bite;
+ *step = 1;
+ return c3y;
+ }
+ else if ( (c3n == u3a_is_atom(hed))
+ || (c3n == u3a_is_atom(tal)) )
+ {
+ return c3n;
+ }
+ else {
+ *bloq = hed;
+ *step = tal;
+ return c3y;
+ }
+}
+
+/* u3r_p():
+**
+** & [0] if [a] is of the form [b *c].
+*/
+c3_o
+u3r_p(u3_noun a,
+ u3_noun b,
+ u3_noun* c)
+{
+ u3_noun feg, nux;
+
+ if ( (c3y == u3r_cell(a, &feg, &nux)) &&
+ (c3y == u3r_sing(feg, b)) )
+ {
+ if ( c ) *c = nux;
+ return c3y;
+ }
+ else return c3n;
+}
+
+/* u3r_pq():
+**
+** & [0] if [a] is of the form [b *c d].
+*/
+c3_o
+u3r_pq(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d)
+{
+ u3_noun nux;
+
+ if ( (c3y == u3r_p(a, b, &nux)) &&
+ (c3y == u3r_cell(nux, c, d)) )
+ {
+ return c3y;
+ }
+ else return c3n;
+}
+
+/* u3r_pqr():
+**
+** & [0] if [a] is of the form [b *c *d *e].
+*/
+c3_o
+u3r_pqr(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e)
+{
+ u3_noun nux;
+
+ if ( (c3y == u3r_p(a, b, &nux)) &&
+ (c3y == u3r_trel(nux, c, d, e)) )
+ {
+ return c3y;
+ }
+ else return c3n;
+}
+
+/* u3r_pqrs():
+**
+** & [0] if [a] is of the form [b *c *d *e *f].
+*/
+c3_o
+u3r_pqrs(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f)
+{
+ u3_noun nux;
+
+ if ( (c3y == u3r_p(a, b, &nux)) &&
+ (c3y == u3r_qual(nux, c, d, e, f)) )
+ {
+ return c3y;
+ }
+ else return c3n;
+}
+
+/* u3r_met():
+**
+** Return the size of (b) in bits, rounded up to
+** (1 << a_y).
+**
+** For example, (a_y == 3) returns the size in bytes.
+** NB: (a_y) must be < 37.
+*/
+c3_w
+u3r_met(c3_y a_y,
+ u3_atom b)
+{
+ c3_dessert(u3_none != b);
+ c3_dessert(_(u3a_is_atom(b)));
+
+ if ( b == 0 ) {
+ return 0;
+ }
+ /* gal_w: number of words besides (daz_w) in (b).
+ ** daz_w: top word in (b).
+ */
+ c3_w gal_w;
+ c3_w daz_w;
+
+ if ( _(u3a_is_cat(b)) ) {
+ gal_w = 0;
+ daz_w = b;
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ gal_w = (b_u->len_w) - 1;
+ daz_w = b_u->buf_w[gal_w];
+ }
+
+ /* 5 because 1<<2 bytes in c3_w, 1<<3 bits in byte.
+ aka log2(CHAR_BIT * sizeof gal_w)
+ a_y < 5 informs whether we shift return left or right
+ */
+ if (a_y < 5) {
+ c3_y max_y = (1 << a_y) - 1;
+ c3_y gow_y = 5 - a_y;
+
+ if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y))
+ return u3m_bail(c3__fail);
+
+ return (gal_w << gow_y)
+ + ((c3_bits_word(daz_w) + max_y)
+ >> a_y);
+ }
+ c3_y gow_y = (a_y - 5);
+ return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y;
+}
+
+/* u3r_bit():
+**
+** Return bit (a_w) of (b).
+*/
+c3_b
+u3r_bit(c3_w a_w,
+ u3_atom b)
+{
+ u3_assert(u3_none != b);
+ u3_assert(_(u3a_is_atom(b)));
+
+ if ( _(u3a_is_cat(b)) ) {
+ if ( a_w >= 31 ) {
+ return 0;
+ }
+ else return (1 & (b >> a_w));
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+ c3_y vut_y = (a_w & 31);
+ c3_w pix_w = (a_w >> 5);
+
+ if ( pix_w >= b_u->len_w ) {
+ return 0;
+ }
+ else {
+ c3_w nys_w = b_u->buf_w[pix_w];
+
+ return (1 & (nys_w >> vut_y));
+ }
+ }
+}
+
+/* u3r_byte():
+**
+** Return byte (a_w) of (b).
+*/
+c3_y
+u3r_byte(c3_w a_w,
+ u3_atom b)
+{
+ u3_assert(u3_none != b);
+ u3_assert(_(u3a_is_atom(b)));
+
+ if ( _(u3a_is_cat(b)) ) {
+ if ( a_w > 3 ) {
+ return 0;
+ }
+ else return (255 & (b >> (a_w << 3)));
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+ c3_y vut_y = (a_w & 3);
+ c3_w pix_w = (a_w >> 2);
+
+ if ( pix_w >= b_u->len_w ) {
+ return 0;
+ }
+ else {
+ c3_w nys_w = b_u->buf_w[pix_w];
+
+ return (255 & (nys_w >> (vut_y << 3)));
+ }
+ }
+}
+
+/* u3r_bytes():
+**
+** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c).
+*/
+void
+u3r_bytes(c3_w a_w,
+ c3_w b_w,
+ c3_y* c_y,
+ u3_atom d)
+{
+ u3_assert(u3_none != d);
+ u3_assert(_(u3a_is_atom(d)));
+
+ if ( _(u3a_is_cat(d)) ) {
+ c3_w e_w = d >> (c3_min(a_w, 4) << 3);
+ c3_w m_w = c3_min(b_w, 4);
+ memcpy(c_y, (c3_y*)&e_w, m_w);
+ if ( b_w > 4 ) {
+ memset(c_y + 4, 0, b_w - 4);
+ }
+ }
+ else {
+ u3a_atom* d_u = u3a_to_ptr(d);
+ c3_w n_w = d_u->len_w << 2;
+ c3_y* x_y = (c3_y*)d_u->buf_w + a_w;
+
+ if ( a_w >= n_w ) {
+ memset(c_y, 0, b_w);
+ }
+ else {
+ c3_w z_w = c3_min(b_w, n_w - a_w);
+ memcpy(c_y, x_y, z_w);
+ if ( b_w > n_w - a_w ) {
+ memset(c_y + z_w, 0, b_w + a_w - n_w);
+ }
+ }
+ }
+}
+
+/* u3r_bytes_fit():
+**
+** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage
+*/
+c3_w
+u3r_bytes_fit(c3_w len_w, c3_y *buf_y, u3_atom a)
+{
+ c3_w met_w = u3r_met(3, a);
+ if ( met_w <= len_w ) {
+ u3r_bytes(0, len_w, buf_y, a);
+ return 0;
+ }
+ else {
+ return len_w - met_w;
+ }
+}
+
+/* u3r_bytes_alloc():
+**
+** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation.
+*/
+c3_y*
+u3r_bytes_alloc(c3_w a_w,
+ c3_w len_w,
+ u3_atom b)
+{
+ c3_y* b_y = u3a_malloc(len_w);
+ u3r_bytes(a_w, a_w + len_w, b_y, b);
+ return b_y;
+}
+
+/* u3r_bytes_all():
+**
+** Allocate and return a new byte array with all the bytes of (a),
+** storing the length in (len_w).
+*/
+c3_y*
+u3r_bytes_all(c3_w* len_w, u3_atom a)
+{
+ c3_w met_w = *len_w = u3r_met(3, a);
+ return u3r_bytes_alloc(0, met_w, a);
+}
+
+/* u3r_mp():
+**
+** Copy (b) into (a_mp).
+*/
+void
+u3r_mp(mpz_t a_mp,
+ u3_atom b)
+{
+ u3_assert(u3_none != b);
+ u3_assert(_(u3a_is_atom(b)));
+
+ if ( _(u3a_is_cat(b)) ) {
+ mpz_init_set_ui(a_mp, b);
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+ c3_w len_w = b_u->len_w;
+ c3_d bit_d = (c3_d)len_w << 5;
+
+ // avoid reallocation on import, if possible
+ //
+ mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX));
+ mpz_import(a_mp, len_w, -1, sizeof(c3_w), 0, 0, b_u->buf_w);
+ }
+}
+
+/* u3r_short():
+**
+** Return short (a_w) of (b).
+*/
+c3_s
+u3r_short(c3_w a_w,
+ u3_atom b)
+{
+ u3_assert( u3_none != b );
+ u3_assert( c3y == u3a_is_atom(b) );
+
+ if ( c3y == u3a_is_cat(b) ) {
+ switch ( a_w ) {
+ case 0: return b & 0xffff;
+ case 1: return b >> 16;
+ default: return 0;
+ }
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+ c3_w nix_w = a_w >> 1;
+
+ if ( nix_w >= b_u->len_w ) {
+ return 0;
+ }
+ else {
+ c3_w wor_w = b_u->buf_w[nix_w];
+
+ return ( a_w & 1 ) ? (wor_w >> 16) : (wor_w & 0xffff);
+ }
+ }
+}
+
+/* u3r_word():
+**
+** Return word (a_w) of (b).
+*/
+c3_w
+u3r_word(c3_w a_w,
+ u3_atom b)
+{
+ u3_assert(u3_none != b);
+ u3_assert(_(u3a_is_atom(b)));
+
+ if ( _(u3a_is_cat(b)) ) {
+ if ( a_w > 0 ) {
+ return 0;
+ }
+ else return b;
+ }
+ else {
+ u3a_atom* b_u = u3a_to_ptr(b);
+
+ if ( a_w >= b_u->len_w ) {
+ return 0;
+ }
+ else return b_u->buf_w[a_w];
+ }
+}
+
+/* u3r_word_fit():
+**
+** Fill (out_w) with (a) if it fits, returning success.
+*/
+c3_t
+u3r_word_fit(c3_w *out_w, u3_atom a)
+{
+ if ( u3r_met(5, a) > 1 ) {
+ return 0;
+ }
+ else {
+ *out_w = u3r_word(0, a);
+ return 1;
+ }
+}
+
+/* u3r_chub():
+**
+** Return double-word (a_w) of (b).
+*/
+c3_d
+u3r_chub(c3_w a_w,
+ u3_atom b)
+{
+ c3_w wlo_w = u3r_word(a_w * 2, b);
+ c3_w whi_w = u3r_word(1 + (a_w * 2), b);
+
+ return (((uint64_t)whi_w) << 32ULL) | ((uint64_t)wlo_w);
+}
+
+/* u3r_words():
+**
+** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c).
+*/
+void
+u3r_words(c3_w a_w,
+ c3_w b_w,
+ c3_w* c_w,
+ u3_atom d)
+{
+ u3_assert(u3_none != d);
+ u3_assert(_(u3a_is_atom(d)));
+
+ if ( b_w == 0 ) {
+ return;
+ }
+ if ( _(u3a_is_cat(d)) ) {
+ if ( a_w == 0 ) {
+ *c_w = d;
+ memset((c3_y*)(c_w + 1), 0, (b_w - 1) << 2);
+ }
+ else {
+ memset((c3_y*)c_w, 0, b_w << 2);
+ }
+ }
+ else {
+ u3a_atom* d_u = u3a_to_ptr(d);
+ if ( a_w >= d_u->len_w ) {
+ memset((c3_y*)c_w, 0, b_w << 2);
+ }
+ else {
+ c3_w z_w = c3_min(b_w, d_u->len_w - a_w);
+ c3_w* x_w = d_u->buf_w + a_w;
+ memcpy((c3_y*)c_w, (c3_y*)x_w, z_w << 2);
+ if ( b_w > d_u->len_w - a_w ) {
+ memset((c3_y*)(c_w + z_w), 0, (b_w + a_w - d_u->len_w) << 2);
+ }
+ }
+ }
+}
+
+/* u3r_chubs():
+**
+** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c).
+*/
+void
+u3r_chubs(c3_w a_w,
+ c3_w b_w,
+ c3_d* c_d,
+ u3_atom d)
+{
+ /* XX: assumes little-endian
+ */
+ u3r_words(a_w * 2, b_w * 2, (c3_w *)c_d, d);
+}
+
+/* u3r_safe_byte(): validate and retrieve byte.
+*/
+c3_o
+u3r_safe_byte(u3_noun dat, c3_y* out_y)
+{
+ if ( (c3n == u3a_is_atom(dat))
+ || (1 < u3r_met(3, dat)) )
+ {
+ return c3n;
+ }
+
+ *out_y = u3r_byte(0, dat);
+ return c3y;
+}
+
+/* u3r_safe_word(): validate and retrieve word.
+*/
+c3_o
+u3r_safe_word(u3_noun dat, c3_w* out_w)
+{
+ if ( (c3n == u3a_is_atom(dat))
+ || (1 < u3r_met(5, dat)) )
+ {
+ return c3n;
+ }
+
+ *out_w = u3r_word(0, dat);
+ return c3y;
+}
+
+/* u3r_safe_chub(): validate and retrieve chub.
+*/
+c3_o
+u3r_safe_chub(u3_noun dat, c3_d* out_d)
+{
+ if ( (c3n == u3a_is_atom(dat))
+ || (1 < u3r_met(6, dat)) )
+ {
+ return c3n;
+ }
+
+ *out_d = u3r_chub(0, dat);
+ return c3y;
+}
+
+/* u3r_chop_bits():
+**
+** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g`
+**
+** NB: [dst_w] must have space for [bit_g + wid_d] bits
+*/
+void
+u3r_chop_bits(c3_g bif_g,
+ c3_d wid_d,
+ c3_g bit_g,
+ c3_w* dst_w,
+ const c3_w* src_w)
+{
+ c3_y fib_y = 32 - bif_g;
+ c3_y tib_y = 32 - bit_g;
+
+ // we need to chop words
+ //
+ if ( wid_d >= tib_y ) {
+ // align *dst_w
+ //
+ if ( bit_g ) {
+ c3_w low_w = src_w[0] >> bif_g;
+
+ if ( bif_g > bit_g ) {
+ low_w ^= src_w[1] << fib_y;
+ }
+
+ *dst_w++ ^= low_w << bit_g;
+
+ wid_d -= tib_y;
+ bif_g += tib_y;
+ src_w += !!(bif_g >> 5);
+ bif_g &= 31;
+ fib_y = 32 - bif_g;
+ }
+
+ {
+ size_t i_i, byt_i = wid_d >> 5;
+
+ if ( !bif_g ) {
+ for ( i_i = 0; i_i < byt_i; i_i++ ) {
+ dst_w[i_i] ^= src_w[i_i];
+ }
+ }
+ else {
+ for ( i_i = 0; i_i < byt_i; i_i++ ) {
+ dst_w[i_i] ^= (src_w[i_i] >> bif_g) ^ (src_w[i_i + 1] << fib_y);
+ }
+ }
+
+ src_w += byt_i;
+ dst_w += byt_i;
+ wid_d &= 31;
+ bit_g = 0;
+ }
+ }
+
+ // we need to chop (more) bits
+ //
+ if ( wid_d ) {
+ c3_w hig_w = src_w[0] >> bif_g;
+
+ if ( wid_d > fib_y ) {
+ hig_w ^= src_w[1] << fib_y;
+ }
+
+ *dst_w ^= (hig_w & (((c3_d)1 << wid_d) - 1)) << bit_g;
+ }
+}
+
+/* u3r_chop_words():
+**
+** Into the bloq space of `met`, from position `fum` for a
+** span of `wid`, to position `tou`, XOR from `src_w`
+** into `dst_w`.
+**
+** NB: [dst_w] must have space for [tou_w + wid_w] bloqs
+*/
+void
+u3r_chop_words(c3_g met_g,
+ c3_w fum_w,
+ c3_w wid_w,
+ c3_w tou_w,
+ c3_w* dst_w,
+ c3_w len_w,
+ const c3_w* src_w)
+{
+ // operate on words
+ //
+ if ( met_g >= 5 ) {
+ size_t i_i, wid_i;
+
+ {
+ c3_g hut_g = met_g - 5;
+ size_t fum_i = (size_t)fum_w << hut_g;
+ size_t tou_i = (size_t)tou_w << hut_g;
+ size_t tot_i;
+
+ wid_i = (size_t)wid_w << hut_g;
+ tot_i = fum_i + wid_i;
+
+ // since [dst_w] must have space for (tou_w + wid_w) bloqs,
+ // neither conversion can overflow
+ //
+ if ( (fum_i >> hut_g != fum_w) || (tot_i - wid_i != fum_i) ) {
+ u3m_bail(c3__fail);
+ return;
+ }
+ else if ( fum_i >= len_w ) {
+ return;
+ }
+
+ if ( tot_i > len_w ) {
+ wid_i -= tot_i - len_w;
+ }
+
+ src_w += fum_i;
+ dst_w += tou_i;
+ }
+
+ for ( i_i = 0; i_i < wid_i; i_i++ ) {
+ dst_w[i_i] ^= src_w[i_i];
+ }
+ }
+ // operate on bits
+ //
+ else {
+ c3_d wid_d = (c3_d)wid_w << met_g;
+ c3_g bif_g, bit_g;
+
+ {
+ c3_d len_d = (c3_d)len_w << 5;
+ c3_d fum_d = (c3_d)fum_w << met_g;
+ c3_d tou_d = (c3_d)tou_w << met_g;
+ c3_d tot_d = fum_d + wid_d;
+
+ // see above
+ //
+ if ( (fum_d >> met_g != fum_w) || (tot_d - wid_d != fum_d) ) {
+ u3m_bail(c3__fail);
+ return;
+ }
+ else if ( fum_d > len_d ) {
+ return;
+ }
+
+ if ( tot_d > len_d ) {
+ wid_d -= tot_d - len_d;
+ }
+
+ src_w += fum_d >> 5;
+ dst_w += tou_d >> 5;
+ bif_g = fum_d & 31;
+ bit_g = tou_d & 31;
+ }
+
+ u3r_chop_bits(bif_g, wid_d, bit_g, dst_w, src_w);
+ }
+}
+
+/* u3r_chop():
+**
+** Into the bloq space of `met`, from position `fum` for a
+** span of `wid`, to position `tou`, XOR from atom `src`
+** into `dst_w`.
+**
+** NB: [dst_w] must have space for [tou_w + wid_w] bloqs
+*/
+void
+u3r_chop(c3_g met_g,
+ c3_w fum_w,
+ c3_w wid_w,
+ c3_w tou_w,
+ c3_w* dst_w,
+ u3_atom src)
+{
+ c3_w* src_w;
+ c3_w len_w;
+
+ if ( _(u3a_is_cat(src)) ) {
+ len_w = src ? 1 : 0;
+ src_w = &src;
+ }
+ else {
+ u3a_atom* src_u = u3a_to_ptr(src);
+
+ u3_assert(u3_none != src);
+ u3_assert(_(u3a_is_atom(src)));
+
+ len_w = src_u->len_w;
+ src_w = src_u->buf_w;
+ }
+
+ u3r_chop_words(met_g, fum_w, wid_w, tou_w, dst_w, len_w, src_w);
+}
+
+/* u3r_string(): `a` as malloced C string.
+*/
+c3_c*
+u3r_string(u3_atom a)
+{
+ c3_w met_w = u3r_met(3, a);
+ c3_c* str_c = c3_malloc(met_w + 1);
+
+ u3r_bytes(0, met_w, (c3_y*)str_c, a);
+ str_c[met_w] = 0;
+ return str_c;
+}
+
+/* u3r_tape(): `a`, a list of bytes, as malloced C string.
+*/
+c3_y*
+u3r_tape(u3_noun a)
+{
+ u3_noun b;
+ c3_w i_w;
+ c3_y *a_y;
+
+ for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) )
+ ;
+ a_y = c3_malloc(i_w + 1);
+
+ for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) ) {
+ a_y[i_w] = u3a_h(b);
+ }
+ a_y[i_w] = 0;
+
+ return a_y;
+}
+
+/* u3r_mug_both(): Join two mugs.
+*/
+c3_l
+u3r_mug_both(c3_l lef_l, c3_l rit_l)
+{
+ c3_y len_y = 4 + ((c3_bits_word(rit_l) + 0x7) >> 3);
+ c3_w syd_w = 0xdeadbeef;
+ c3_w i_w = 0;
+ c3_y buf_y[8];
+
+ buf_y[0] = lef_l & 0xff;
+ buf_y[1] = (lef_l >> 8) & 0xff;
+ buf_y[2] = (lef_l >> 16) & 0xff;
+ buf_y[3] = (lef_l >> 24) & 0xff;
+ buf_y[4] = rit_l & 0xff;
+ buf_y[5] = (rit_l >> 8) & 0xff;
+ buf_y[6] = (rit_l >> 16) & 0xff;
+ buf_y[7] = (rit_l >> 24) & 0xff;
+
+ while ( i_w < 8 ) {
+ c3_w haz_w;
+ c3_l ham_l;
+
+ MurmurHash3_x86_32(buf_y, len_y, syd_w, &haz_w);
+ ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff);
+
+ if ( 0 == ham_l ) {
+ syd_w++; i_w++;
+ }
+ else {
+ return ham_l;
+ }
+ }
+
+ return 0xfffe;
+}
+
+/* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first.
+*/
+c3_l
+u3r_mug_bytes(const c3_y *buf_y,
+ c3_w len_w)
+{
+ c3_w syd_w = 0xcafebabe;
+ c3_w i_w = 0;
+
+ while ( i_w < 8 ) {
+ c3_w haz_w;
+ c3_l ham_l;
+
+ MurmurHash3_x86_32(buf_y, len_w, syd_w, &haz_w);
+ ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff);
+
+ if ( 0 == ham_l ) {
+ syd_w++; i_w++;
+ }
+ else {
+ return ham_l;
+ }
+ }
+
+ return 0x7fff;
+}
+
+/* u3r_mug_c(): Compute the mug of `a`, LSB first.
+*/
+c3_l
+u3r_mug_c(const c3_c* a_c)
+{
+ return u3r_mug_bytes((c3_y*)a_c, strlen(a_c));
+}
+
+/* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`.
+*/
+c3_l
+u3r_mug_cell(u3_noun hed,
+ u3_noun tel)
+{
+ c3_w lus_w = u3r_mug(hed);
+ c3_w biq_w = u3r_mug(tel);
+
+ return u3r_mug_both(lus_w, biq_w);
+}
+
+/* u3r_mug_chub(): Compute the mug of `num`, LSW first.
+*/
+c3_l
+u3r_mug_chub(c3_d num_d)
+{
+ c3_w buf_w[2];
+
+ buf_w[0] = (c3_w)(num_d & 0xffffffffULL);
+ buf_w[1] = (c3_w)(num_d >> 32);
+
+ return u3r_mug_words(buf_w, 2);
+}
+
+/* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words.
+*/
+c3_l
+u3r_mug_words(const c3_w* key_w, c3_w len_w)
+{
+ c3_w byt_w;
+
+ // ignore trailing zeros
+ //
+ while ( len_w && !key_w[len_w - 1] ) {
+ len_w--;
+ }
+
+ // calculate byte-width a la u3r_met(3, ...)
+ //
+ if ( !len_w ) {
+ byt_w = 0;
+ }
+ else {
+ c3_w gal_w = len_w - 1;
+ c3_w daz_w = key_w[gal_w];
+
+ byt_w = (gal_w << 2) + ((c3_bits_word(daz_w) + 7) >> 3);
+ }
+
+ // XX: assumes little-endian
+ //
+ return u3r_mug_bytes((c3_y*)key_w, byt_w);
+}
+
+/* _cr_mug: stack frame for recording cell traversal
+** !mug == head-frame
+*/
+typedef struct {
+ c3_l mug_l;
+ u3_cell cel;
+} _cr_mugf;
+
+/* _cr_mug_next(): advance mug calculation, pushing cells onto the stack.
+*/
+static inline c3_l
+_cr_mug_next(u3a_pile* pil_u, u3_noun veb)
+{
+ while ( 1 ) {
+ // veb is a direct atom, mug is not memoized
+ //
+ if ( c3y == u3a_is_cat(veb) ) {
+ return (c3_l)u3r_mug_words(&veb, 1);
+ }
+ // veb is indirect, a pointer into the loom
+ //
+ else {
+ u3a_noun* veb_u = u3a_to_ptr(veb);
+
+ // veb has already been mugged, return memoized value
+ //
+ // XX add debug assertion that mug is 31-bit?
+ //
+ if ( veb_u->mug_w ) {
+ return (c3_l)veb_u->mug_w;
+ }
+ // veb is an indirect atom, mug its bytes and memoize
+ //
+ else if ( c3y == u3a_is_atom(veb) ) {
+ u3a_atom* vat_u = (u3a_atom*)veb_u;
+ c3_l mug_l = u3r_mug_words(vat_u->buf_w, vat_u->len_w);
+ vat_u->mug_w = mug_l;
+ return mug_l;
+ }
+ // veb is a cell, push a stack frame to mark head-recursion
+ // and read the head
+ //
+ else {
+ u3a_cell* cel_u = (u3a_cell*)veb_u;
+ _cr_mugf* fam_u = u3a_push(pil_u);
+
+ fam_u->mug_l = 0;
+ fam_u->cel = veb;
+
+ veb = cel_u->hed;
+ continue;
+ }
+ }
+ }
+}
+
+/* u3r_mug(): statefully mug a noun with 31-bit murmur3.
+*/
+c3_l
+u3r_mug(u3_noun veb)
+{
+ u3a_pile pil_u;
+ _cr_mugf* fam_u;
+ c3_l mug_l;
+
+ // sanity check
+ //
+ u3_assert( u3_none != veb );
+
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // commence mugging
+ //
+ mug_l = _cr_mug_next(&pil_u, veb);
+
+ // process cell results
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // head-frame: stash mug and continue into the tail
+ //
+ if ( !fam_u->mug_l ) {
+ u3a_cell* cel_u = u3a_to_ptr(fam_u->cel);
+
+ fam_u->mug_l = mug_l;
+ mug_l = _cr_mug_next(&pil_u, cel_u->tel);
+ fam_u = u3a_peek(&pil_u);
+ }
+ // tail-frame: calculate/memoize cell mug and pop the stack
+ //
+ else {
+ u3a_cell* cel_u = u3a_to_ptr(fam_u->cel);
+
+ mug_l = u3r_mug_both(fam_u->mug_l, mug_l);
+ cel_u->mug_w = mug_l;
+ fam_u = u3a_pop(&pil_u);
+ }
+ }
+ while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ return mug_l;
+}
+
+/* u3r_skip():
+**
+** Extract a constant from a formula, ignoring
+** safe/static hints, doing no computation.
+*/
+u3_weak
+u3r_skip(u3_noun fol)
+{
+ while ( c3y == u3du(fol) ) {
+ switch ( u3h(fol) ) {
+ default: return u3_none;
+ case 1: return u3t(fol);
+ case 11: {
+ u3_noun arg = u3t(fol),
+ hod = u3h(arg);
+
+ if ( (c3y == u3du(hod)) && (u3_none == u3r_skip(u3t(hod))) ) {
+ return u3_none;
+ }
+ fol = u3t(arg);
+ }
+ }
+ }
+ return u3_none;
+}
+
+/* u3r_safe():
+**
+** Returns yes if the formula won't crash
+** and has no hints, returning constant result
+** if possible. *out is undefined if the return
+** is c3n
+*/
+c3_o
+u3r_safe(u3_noun fol, u3_weak* out)
+{
+ u3_noun h_fol, t_fol;
+ c3_o saf_o;
+
+ if ( c3n == u3r_cell(fol, &h_fol, &t_fol) ) {
+ return c3n;
+ }
+ switch ( h_fol ) {
+ default: return c3n;
+ case 0:
+ *out = u3_none;
+ return __(1 == t_fol);
+
+ case 1:
+ *out = t_fol;
+ return c3y;
+
+ case 3: {
+ u3_weak o;
+ saf_o = u3r_safe(t_fol, &o);
+ if ( _(saf_o) ) {
+ *out = (u3_none == o) ? u3_none : u3du(o);
+ }
+ return saf_o;
+ }
+
+ case 5: {
+ u3_noun p, q;
+ u3_weak o1, o2;
+ saf_o = c3a(u3r_cell(t_fol, &p, &q),
+ c3a(u3r_safe(p, &o1), u3r_safe(q, &o2)));
+
+ if ( _(saf_o) ) {
+ *out = (u3_none == o1) ? u3_none
+ : (u3_none == o2) ? u3_none
+ : u3r_sing(o1, o2);
+ }
+ return saf_o;
+ }
+
+ case 6: {
+ u3_noun p, q, r;
+ u3_weak o;
+ saf_o = c3a(u3r_trel(t_fol, &p, &q, &r), u3r_safe(p, &o));
+
+ if ( _(saf_o) ) {
+ switch ( o ) {
+ case c3y: return u3r_safe(q, out);
+ case c3n: return u3r_safe(r, out);
+ default: return c3n;
+ }
+ }
+ else {
+ return c3n;
+ }
+ }
+
+ case 7:
+ case 8: {
+ u3_noun p, q;
+ u3_weak o;
+ return c3a(u3r_cell(t_fol, &p, &q),
+ c3a(u3r_safe(p, &o), u3r_safe(q, out)));
+ }
+ }
+}
diff --git a/vere/pkg/noun/retrieve.h b/vere/pkg/noun/retrieve.h
new file mode 100644
index 0000000..c02c008
--- /dev/null
+++ b/vere/pkg/noun/retrieve.h
@@ -0,0 +1,547 @@
+/// @file
+
+#ifndef U3_RETRIEVE_H
+#define U3_RETRIEVE_H
+
+#include "c3/c3.h"
+#include "allocate.h"
+#include "error.h"
+#include "gmp.h"
+#include "types.h"
+
+ /** u3r_*: read without ever crashing.
+ **/
+
+ /* u3r_cell(): factor (a) as a cell (b c).
+ */
+ inline c3_o
+ u3r_cell(u3_noun a, u3_noun* b, u3_noun* c)
+ {
+ u3a_cell* cel_u;
+
+ u3_assert(u3_none != a);
+
+ if ( c3y == u3a_is_cell(a) ) {
+ cel_u = u3a_to_ptr(a);
+ if ( b ) *b = cel_u->hed;
+ if ( c ) *c = cel_u->tel;
+ return c3y;
+ }
+ else {
+ return c3n;
+ }
+ }
+
+ /* u3r_trel(): factor (a) as a trel (b c d).
+ */
+ inline c3_o
+ u3r_trel(u3_noun a, u3_noun *b, u3_noun *c, u3_noun *d)
+ {
+ u3_noun guf;
+
+ if ( (c3y == u3r_cell(a, b, &guf)) &&
+ (c3y == u3r_cell(guf, c, d)) ) {
+ return c3y;
+ }
+ else {
+ return c3n;
+ }
+ }
+
+ /* u3r_qual(): factor (a) as a qual (b c d e).
+ */
+ inline c3_o
+ u3r_qual(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e)
+ {
+ u3_noun guf;
+
+ if ( (c3y == u3r_cell(a, b, &guf)) &&
+ (c3y == u3r_trel(guf, c, d, e)) ) {
+ return c3y;
+ }
+ else return c3n;
+ }
+
+ /* u3r_quil(): factor (a) as a quil (b c d e f).
+ */
+ inline c3_o
+ u3r_quil(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f)
+ {
+ u3_noun guf;
+
+ if ( (c3y == u3r_cell(a, b, &guf)) &&
+ (c3y == u3r_qual(guf, c, d, e, f)) ) {
+ return c3y;
+ }
+ else return c3n;
+ }
+
+ /* u3r_hext(): factor (a) as a hext (b c d e f g)
+ */
+ inline c3_o
+ u3r_hext(u3_noun a,
+ u3_noun* b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f,
+ u3_noun* g)
+ {
+ u3_noun guf;
+
+ if ( (c3y == u3r_cell(a, b, &guf)) &&
+ (c3y == u3r_quil(guf, c, d, e, f, g)) ) {
+ return c3y;
+ }
+ else return c3n;
+ }
+
+ /* u3r_at(): fragment `a` of `b`, or u3_none.
+ */
+ u3_weak
+ u3r_at(u3_atom a, u3_weak b);
+
+ /* u3r_mean():
+ **
+ ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates.
+ ** Axes must be sorted in tree order.
+ */
+ c3_o
+ u3r_vmean(u3_noun a, va_list ap);
+ c3_o
+ u3r_mean(u3_noun a, ...);
+
+ /* u3r_mug_both(): Join two mugs.
+ */
+ c3_l
+ u3r_mug_both(c3_w lef_w, c3_w rit_w);
+
+ /* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first.
+ */
+ c3_l
+ u3r_mug_bytes(const c3_y *buf_y,
+ c3_w len_w);
+
+ /* u3r_mug_c(): Compute the mug of `a`, LSB first.
+ */
+ c3_l
+ u3r_mug_c(const c3_c *a_c);
+
+ /* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`.
+ */
+ c3_l
+ u3r_mug_cell(u3_noun hed,
+ u3_noun tel);
+
+ /* u3r_mug_chub(): Compute the mug of `num`, LSW first.
+ */
+ c3_l
+ u3r_mug_chub(c3_d num_d);
+
+ /* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words.
+ */
+ c3_l
+ u3r_mug_words(const c3_w* key_w, c3_w len_w);
+
+ /* u3r_mug(): statefully mug a noun with 31-bit murmur3.
+ */
+ c3_l
+ u3r_mug(u3_noun veb);
+
+ /* u3r_fing():
+ **
+ ** Yes iff (a) and (b) are the same copy of the same noun.
+ ** (Ie, by pointer equality - u3r_sing with false negatives.)
+ */
+ c3_o
+ u3r_fing(u3_noun a,
+ u3_noun b);
+
+ /* u3r_fing_cell():
+ **
+ ** Yes iff `[p q]` and `b` are the same copy of the same noun.
+ */
+ c3_o
+ u3r_fing_cell(u3_noun p,
+ u3_noun q,
+ u3_noun b);
+
+ /* u3r_fing_mixt():
+ **
+ ** Yes iff `[p q]` and `b` are the same copy of the same noun.
+ */
+ c3_o
+ u3r_fing_mixt(const c3_c* p_c,
+ u3_noun q,
+ u3_noun b);
+
+ /* u3r_fing_trel():
+ **
+ ** Yes iff `[p q r]` and `b` are the same copy of the same noun.
+ */
+ c3_o
+ u3r_fing_trel(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun b);
+
+ /* u3r_fing_qual():
+ **
+ ** Yes iff `[p q r s]` and `b` are the same copy of the same noun.
+ */
+ c3_o
+ u3r_fing_qual(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun s,
+ u3_noun b);
+
+ /* u3r_sing(): noun value equality.
+ **
+ ** Unifies noun pointers on inner roads.
+ */
+ c3_o
+ u3r_sing(u3_noun a, u3_noun b);
+
+ /* u3r_sing_c(): cord/C-string value equivalence.
+ */
+ c3_o
+ u3r_sing_c(const c3_c* a_c,
+ u3_noun b);
+
+ /* u3r_sing_cell():
+ **
+ ** Yes iff `[p q]` and `b` are the same noun.
+ */
+ c3_o
+ u3r_sing_cell(u3_noun p,
+ u3_noun q,
+ u3_noun b);
+
+ /* u3r_sing_mixt():
+ **
+ ** Yes iff `[p q]` and `b` are the same noun.
+ */
+ c3_o
+ u3r_sing_mixt(const c3_c* p_c,
+ u3_noun q,
+ u3_noun b);
+
+ /* u3r_sing_trel():
+ **
+ ** Yes iff `[p q r]` and `b` are the same noun.
+ */
+ c3_o
+ u3r_sing_trel(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun b);
+
+ /* u3r_sing_qual():
+ **
+ ** Yes iff `[p q r s]` and `b` are the same noun.
+ */
+ c3_o
+ u3r_sing_qual(u3_noun p,
+ u3_noun q,
+ u3_noun r,
+ u3_noun s,
+ u3_noun b);
+
+ /* u3r_nord():
+ **
+ ** Return 0, 1 or 2 if `a` is below, equal to, or above `b`.
+ */
+ u3_atom
+ u3r_nord(u3_noun a,
+ u3_noun b);
+
+ /* u3r_mold():
+ **
+ ** Divide `a` as a mold `[b.[p q] c]`.
+ */
+ c3_o
+ u3r_mold(u3_noun a,
+ u3_noun* b,
+ u3_noun* c);
+
+ /* u3r_bite(): retrieve/default $bloq and $step from $bite.
+ */
+ c3_o
+ u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step);
+
+ /* u3r_p():
+ **
+ ** & [0] if [a] is of the form [b *c].
+ */
+ c3_o
+ u3r_p(u3_noun a,
+ u3_noun b,
+ u3_noun* c);
+
+ /* u3r_bush():
+ **
+ ** Factor [a] as a bush [b.[p q] c].
+ */
+ c3_o
+ u3r_bush(u3_noun a,
+ u3_noun* b,
+ u3_noun* c);
+
+ /* u3r_pq():
+ **
+ ** & [0] if [a] is of the form [b *c d].
+ */
+ c3_o
+ u3r_pq(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d);
+
+ /* u3r_pqr():
+ **
+ ** & [0] if [a] is of the form [b *c *d *e].
+ */
+ c3_o
+ u3r_pqr(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e);
+
+ /* u3r_pqrs():
+ **
+ ** & [0] if [a] is of the form [b *c *d *e *f].
+ */
+ c3_o
+ u3r_pqrs(u3_noun a,
+ u3_noun b,
+ u3_noun* c,
+ u3_noun* d,
+ u3_noun* e,
+ u3_noun* f);
+
+ /* u3r_met():
+ **
+ ** Return the size of (b) in bits, rounded up to
+ ** (1 << a_y).
+ **
+ ** For example, (a_y == 3) returns the size in bytes.
+ ** NB: (a_y) must be < 37.
+ */
+ c3_w
+ u3r_met(c3_y a_y,
+ u3_atom b);
+
+ /* u3r_bit():
+ **
+ ** Return bit (a_w) of (b).
+ */
+ c3_b
+ u3r_bit(c3_w a_w,
+ u3_atom b);
+
+ /* u3r_byte():
+ **
+ ** Return byte (a_w) of (b).
+ */
+ c3_y
+ u3r_byte(c3_w a_w,
+ u3_atom b);
+
+ /* u3r_bytes():
+ **
+ ** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c).
+ */
+ void
+ u3r_bytes(c3_w a_w,
+ c3_w b_w,
+ c3_y* c_y,
+ u3_atom d);
+
+ /* u3r_bytes_fit():
+ **
+ ** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage.
+ */
+ c3_w
+ u3r_bytes_fit(c3_w len_w,
+ c3_y* buf_y,
+ u3_atom a);
+
+ /* u3r_bytes_alloc():
+ **
+ ** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation.
+ */
+ c3_y*
+ u3r_bytes_alloc(c3_w a_w,
+ c3_w len_w,
+ u3_atom b);
+
+ /* u3r_bytes_all():
+ **
+ ** Allocate and return a new byte array with all the bytes of (a),
+ ** storing the length in (len_w).
+ */
+ c3_y*
+ u3r_bytes_all(c3_w* len_w,
+ u3_atom a);
+
+ /* u3r_chop_bits():
+ **
+ ** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g`
+ **
+ ** NB: [dst_w] must have space for [bit_g + wid_d] bits
+ */
+ void
+ u3r_chop_bits(c3_g bif_g,
+ c3_d wid_d,
+ c3_g bit_g,
+ c3_w* dst_w,
+ const c3_w* src_w);
+
+ /* u3r_chop_words():
+ **
+ ** Into the bloq space of `met`, from position `fum` for a
+ ** span of `wid`, to position `tou`, XOR from `src_w`
+ ** into `dst_w`.
+ **
+ ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs
+ */
+ void
+ u3r_chop_words(c3_g met_g,
+ c3_w fum_w,
+ c3_w wid_w,
+ c3_w tou_w,
+ c3_w* dst_w,
+ c3_w len_w,
+ const c3_w* src_w);
+
+ /* u3r_chop():
+ **
+ ** Into the bloq space of `met`, from position `fum` for a
+ ** span of `wid`, to position `tou`, XOR from atom `src`
+ ** into `dst_w`.
+ **
+ ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs
+ */
+ void
+ u3r_chop(c3_g met_g,
+ c3_w fum_w,
+ c3_w wid_w,
+ c3_w tou_w,
+ c3_w* dst_w,
+ u3_atom src);
+
+ /* u3r_mp():
+ **
+ ** Copy (b) into (a_mp).
+ */
+ void
+ u3r_mp(mpz_t a_mp,
+ u3_atom b);
+
+ /* u3r_short():
+ **
+ ** Return short (a_w) of (b).
+ */
+ c3_s
+ u3r_short(c3_w a_w,
+ u3_atom b);
+
+ /* u3r_word():
+ **
+ ** Return word (a_w) of (b).
+ */
+ c3_w
+ u3r_word(c3_w a_w,
+ u3_atom b);
+
+
+ /* u3r_word_fit():
+ **
+ ** Fill (out_w) with (a) if it fits, returning success.
+ */
+ c3_t
+ u3r_word_fit(c3_w* out_w,
+ u3_atom a);
+
+ /* u3r_chub():
+ **
+ ** Return double-word (a_w) of (b).
+ */
+ c3_d
+ u3r_chub(c3_w a_w,
+ u3_atom b);
+
+ /* u3r_words():
+ **
+ ** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c).
+ */
+ void
+ u3r_words(c3_w a_w,
+ c3_w b_w,
+ c3_w* c_w,
+ u3_atom d);
+
+ /* u3r_chubs():
+ **
+ ** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c).
+ */
+ void
+ u3r_chubs(c3_w a_w,
+ c3_w b_w,
+ c3_d* c_d,
+ u3_atom d);
+
+ /* u3r_safe_byte(): validate and retrieve byte.
+ */
+ c3_o
+ u3r_safe_byte(u3_noun dat, c3_y* out_y);
+
+ /* u3r_safe_word(): validate and retrieve word.
+ */
+ c3_o
+ u3r_safe_word(u3_noun dat, c3_w* out_w);
+
+ /* u3r_safe_chub(): validate and retrieve chub.
+ */
+ c3_o
+ u3r_safe_chub(u3_noun dat, c3_d* out_d);
+
+ /* u3r_string(): `a`, a text atom, as malloced C string.
+ */
+ c3_c*
+ u3r_string(u3_atom a);
+
+ /* u3r_tape(): `a`, a list of bytes, as malloced C string.
+ */
+ c3_y*
+ u3r_tape(u3_noun a);
+
+ /* u3r_skip():
+ **
+ ** Extract a constant from a formula, ignoring
+ ** safe/static hints, doing no computation.
+ */
+ u3_weak
+ u3r_skip(u3_noun fol);
+
+ /* u3r_safe():
+ **
+ ** Returns yes if the formula won't crash
+ ** and has no hints, returning constant result
+ ** if possible
+ */
+ c3_o
+ u3r_safe(u3_noun fol, u3_weak* out);
+
+#endif /* ifndef U3_RETRIEVE_H */
diff --git a/vere/pkg/noun/retrieve_tests.c b/vere/pkg/noun/retrieve_tests.c
new file mode 100644
index 0000000..7ba7fa5
--- /dev/null
+++ b/vere/pkg/noun/retrieve_tests.c
@@ -0,0 +1,247 @@
+/// @file
+
+#include "noun.h"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_init(1 << 20);
+ u3m_pave(c3y);
+}
+
+/* _test_mug(): spot check u3r_mug hashes.
+*/
+static c3_i
+_test_mug(void)
+{
+ c3_i ret_i = 1;
+
+ if ( 0x4d441035 != u3r_mug_c("Hello, world!") ) {
+ fprintf(stderr, "fail (a)\r\n");
+ ret_i = 0;
+ }
+
+ {
+ u3_noun a = u3i_string("Hello, world!");
+
+ if ( 0x4d441035 != u3r_mug(a) ) {
+ fprintf(stderr, "fail (b)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(a);
+ }
+
+ {
+ c3_y byt_y[1];
+
+ if ( 0x79ff04e8 != u3r_mug_bytes(0, 0) ) {
+ fprintf(stderr, "fail (c) (0)\r\n");
+ ret_i = 0;
+ }
+
+ byt_y[0] = 1;
+
+ if ( 0x715c2a60 != u3r_mug_bytes(byt_y, 1) ) {
+ fprintf(stderr, "fail (c) (1)\r\n");
+ ret_i = 0;
+ }
+
+ byt_y[0] = 2;
+
+ if ( 0x718b9468 != u3r_mug_bytes(byt_y, 1) ) {
+ fprintf(stderr, "fail (c) (2)\r\n");
+ ret_i = 0;
+ }
+ }
+
+ if ( 0x3a811aec != u3r_mug_both(0x715c2a60, u3r_mug_cell(2, 3)) ) {
+ fprintf(stderr, "fail (d)\r\n");
+ ret_i = 0;
+ }
+
+
+ {
+ if ( 0x192f5588 != u3r_mug_cell(0, 0) ) {
+ fprintf(stderr, "fail (e) (1)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x6b32ec46 != u3r_mug_cell(1, 1) ) {
+ fprintf(stderr, "fail (e) (2)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x2effe10 != u3r_mug_cell(2, 2) ) {
+ fprintf(stderr, "fail (e) (3)\r\n");
+ ret_i = 0;
+ }
+ }
+
+ {
+ u3_noun a = u3i_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+ if ( 0x64dfda5c != u3r_mug(a) ) {
+ fprintf(stderr, "fail (f)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(a);
+ }
+
+ {
+ u3_noun a = u3qc_bex(32);
+
+ if ( 0x7cefb7f != u3r_mug_cell(0, a) ) {
+ fprintf(stderr, "fail (g)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(a);
+ }
+
+ {
+ u3_noun a = u3ka_dec(u3qc_bex(128));
+
+ if ( 0x2aa06bfc != u3r_mug_cell(a, 1) ) {
+ fprintf(stderr, "fail (h)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(a);
+ }
+
+ {
+ // stick some zero bytes in a string
+ //
+ u3_noun str = u3kc_lsh(3, 1,
+ u3kc_mix(u3qc_bex(212),
+ u3i_string("abcdefjhijklmnopqrstuvwxyz")));
+
+ c3_w byt_w = u3r_met(3, str);
+ c3_w wor_w = u3r_met(5, str);
+ c3_y* str_y = c3_malloc(byt_w);
+ c3_w* str_w = c3_malloc(4 * wor_w);
+ c3_d str_d = 0;
+
+ u3r_bytes(0, byt_w, str_y, str);
+ u3r_words(0, wor_w, str_w, str);
+
+ str_d |= str_w[0];
+ str_d |= ((c3_d)str_w[1] << 32ULL);
+
+ if ( 0x34d08717 != u3r_mug(str) ) {
+ fprintf(stderr, "fail (i) (1) \r\n");
+ ret_i = 0;
+ }
+ if ( 0x34d08717 != u3r_mug_bytes(str_y, byt_w) ) {
+ fprintf(stderr, "fail (i) (2)\r\n");
+ ret_i = 0;
+ }
+ if ( 0x34d08717 != u3r_mug_words(str_w, wor_w) ) {
+ fprintf(stderr, "fail (i) (3)\r\n");
+ ret_i = 0;
+ }
+ if ( u3r_mug_words(str_w, 2) != u3r_mug_chub(str_d) ) {
+ fprintf(stderr, "fail (i) (4)\r\n");
+ ret_i = 0;
+ }
+
+ c3_free(str_y);
+ c3_free(str_w);
+ u3z(str);
+ }
+
+ {
+ c3_w som_w[4] = { 0, 0, 0, 1 };
+ u3_noun som = u3i_words(4, som_w);
+
+ if ( 0x519bd45c != u3r_mug(som) ) {
+ fprintf(stderr, "fail (j) (1)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x519bd45c != u3r_mug_words(som_w, 4) ) {
+ fprintf(stderr, "fail (j) (2)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(som);
+ }
+
+ {
+ c3_w som_w[4] = { 0, 1, 0, 1 };
+ u3_noun som = u3i_words(4, som_w);
+
+ if ( 0x540eb8a9 != u3r_mug(som) ) {
+ fprintf(stderr, "fail (k) (1)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x540eb8a9 != u3r_mug_words(som_w, 4) ) {
+ fprintf(stderr, "fail (k) (2)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(som);
+ }
+
+ {
+ c3_w som_w[4] = { 1, 1, 0, 1 };
+ u3_noun som = u3i_words(4, som_w);
+
+ if ( 0x319d28f9 != u3r_mug(som) ) {
+ fprintf(stderr, "fail (l) (1)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x319d28f9 != u3r_mug_words(som_w, 4) ) {
+ fprintf(stderr, "fail (l) (2)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(som);
+ }
+
+ {
+ c3_w som_w[4] = { 0, 0, 0, 0xffff };
+ u3_noun som = u3i_words(4, som_w);
+
+ if ( 0x5230a260 != u3r_mug(som) ) {
+ fprintf(stderr, "fail (m) (1)\r\n");
+ ret_i = 0;
+ }
+
+ if ( 0x5230a260 != u3r_mug_words(som_w, 4) ) {
+ fprintf(stderr, "fail (m) (2)\r\n");
+ ret_i = 0;
+ }
+
+ u3z(som);
+ }
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_mug() ) {
+ fprintf(stderr, "test_mug: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test_mug: ok\n");
+
+ return 0;
+}
diff --git a/vere/pkg/noun/serial.c b/vere/pkg/noun/serial.c
new file mode 100644
index 0000000..5dd6f59
--- /dev/null
+++ b/vere/pkg/noun/serial.c
@@ -0,0 +1,1456 @@
+/// @file
+
+#include "serial.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "retrieve.h"
+#include "serial.h"
+#include "ur/ur.h"
+#include "vortex.h"
+#include "xtract.h"
+
+const c3_y u3s_dit_y[64] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ '-', '~'
+};
+
+/* _cs_jam_buf: struct for tracking the fibonacci-allocated jam of a noun
+*/
+struct _cs_jam_fib {
+ u3i_slab* sab_u;
+ u3p(u3h_root) har_p;
+ c3_w a_w;
+ c3_w b_w;
+ c3_w bit_w;
+};
+
+/* _cs_jam_fib_grow(): reallocate buffer with fibonacci growth
+*/
+static inline void
+_cs_jam_fib_grow(struct _cs_jam_fib* fib_u, c3_w mor_w)
+{
+ c3_w wan_w = fib_u->bit_w + mor_w;
+
+ // check for c3_w overflow
+ //
+ if ( wan_w < mor_w ) {
+ u3m_bail(c3__fail);
+ return;
+ }
+
+ if ( wan_w > fib_u->a_w ) {
+ c3_w c_w = 0;
+
+ // fibonacci growth
+ //
+ while ( c_w < wan_w ) {
+ c_w = fib_u->a_w + fib_u->b_w;
+ fib_u->b_w = fib_u->a_w;
+ fib_u->a_w = c_w;
+ }
+
+ u3i_slab_grow(fib_u->sab_u, 0, c_w);
+ }
+}
+
+/* _cs_jam_fib_chop(): chop [met_w] bits of [a] into [fib_u]
+*/
+static inline void
+_cs_jam_fib_chop(struct _cs_jam_fib* fib_u, c3_w met_w, u3_noun a)
+{
+ c3_w bit_w = fib_u->bit_w;
+ _cs_jam_fib_grow(fib_u, met_w);
+ fib_u->bit_w += met_w;
+
+ {
+ c3_w* buf_w = fib_u->sab_u->buf_w;
+ u3r_chop(0, 0, met_w, bit_w, buf_w, a);
+ }
+}
+
+/* _cs_jam_fib_mat(): length-prefixed encode (mat) [a] into [fib_u]
+*/
+static void
+_cs_jam_fib_mat(struct _cs_jam_fib* fib_u, u3_noun a)
+{
+ if ( 0 == a ) {
+ _cs_jam_fib_chop(fib_u, 1, 1);
+ }
+ else {
+ c3_w a_w = u3r_met(0, a);
+ c3_w b_w = c3_bits_word(a_w);
+ c3_w bit_w = fib_u->bit_w;
+
+ // amortize overflow checks and reallocation
+ //
+ {
+ c3_w met_w = a_w + (2 * b_w);
+
+ if ( a_w > (UINT32_MAX - 64) ) {
+ u3m_bail(c3__fail);
+ return;
+ }
+
+ _cs_jam_fib_grow(fib_u, met_w);
+ fib_u->bit_w += met_w;
+ }
+
+ {
+ c3_w src_w[2];
+ c3_w* buf_w = fib_u->sab_u->buf_w;
+
+ // _cs_jam_fib_chop(fib_u, b_w+1, 1 << b_w);
+ //
+ {
+ c3_d dat_d = (c3_d)1 << b_w;
+ src_w[0] = (c3_w)dat_d;
+ src_w[1] = dat_d >> 32;
+
+ u3r_chop_words(0, 0, b_w + 1, bit_w, buf_w, 2, src_w);
+ bit_w += b_w + 1;
+ }
+
+ // _cs_jam_fib_chop(fib_u, b_w-1, a_w);
+ //
+ {
+ src_w[0] = a_w;
+ u3r_chop_words(0, 0, b_w - 1, bit_w, buf_w, 1, src_w);
+ bit_w += b_w - 1;
+ }
+
+ // _cs_jam_fib_chop(fib_u, a_w, a);
+ //
+ u3r_chop(0, 0, a_w, bit_w, buf_w, a);
+ }
+ }
+}
+
+/* _cs_jam_fib_atom_cb(): encode atom or backref
+*/
+static void
+_cs_jam_fib_atom_cb(u3_atom a, void* ptr_v)
+{
+ struct _cs_jam_fib* fib_u = ptr_v;
+ u3_weak b = u3h_git(fib_u->har_p, a);
+
+ // if [a] has no backref, encode atom and put cursor into [har_p]
+ //
+ if ( u3_none == b ) {
+ u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w)));
+ _cs_jam_fib_chop(fib_u, 1, 0);
+ _cs_jam_fib_mat(fib_u, a);
+ }
+ else {
+ c3_w a_w = u3r_met(0, a);
+ c3_w b_w = u3r_met(0, b);
+
+ // if [a] is smaller than the backref, encode atom
+ //
+ if ( a_w <= b_w ) {
+ _cs_jam_fib_chop(fib_u, 1, 0);
+ _cs_jam_fib_mat(fib_u, a);
+ }
+ // otherwise, encode backref
+ //
+ else {
+ _cs_jam_fib_chop(fib_u, 2, 3);
+ _cs_jam_fib_mat(fib_u, b);
+ }
+ }
+}
+
+/* _cs_jam_fib_cell_cb(): encode cell or backref
+*/
+static c3_o
+_cs_jam_fib_cell_cb(u3_noun a, void* ptr_v)
+{
+ struct _cs_jam_fib* fib_u = ptr_v;
+ u3_weak b = u3h_git(fib_u->har_p, a);
+
+ // if [a] has no backref, encode cell and put cursor into [har_p]
+ //
+ if ( u3_none == b ) {
+ u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w)));
+ _cs_jam_fib_chop(fib_u, 2, 1);
+ return c3y;
+ }
+ // otherwise, encode backref and shortcircuit traversal
+ //
+ else {
+ _cs_jam_fib_chop(fib_u, 2, 3);
+ _cs_jam_fib_mat(fib_u, b);
+ return c3n;
+ }
+}
+
+/* u3s_jam_fib(): jam without atom allocation.
+**
+** returns atom-suitable words, and *bit_w will have
+** the length (in bits). return should be freed with u3a_wfree().
+*/
+c3_w
+u3s_jam_fib(u3i_slab* sab_u, u3_noun a)
+{
+ struct _cs_jam_fib fib_u;
+ fib_u.har_p = u3h_new();
+ fib_u.sab_u = sab_u;
+
+ // fib(12) is small enough to be reasonably fast to allocate.
+ // fib(11) is needed to get fib(13).
+ //
+ //
+ fib_u.a_w = ur_fib12;
+ fib_u.b_w = ur_fib11;
+ fib_u.bit_w = 0;
+ u3i_slab_init(sab_u, 0, fib_u.a_w);
+
+ u3a_walk_fore(a, &fib_u, _cs_jam_fib_atom_cb, _cs_jam_fib_cell_cb);
+
+ u3h_free(fib_u.har_p);
+ return fib_u.bit_w;
+}
+
+typedef struct _jam_xeno_s {
+ u3p(u3h_root) har_p;
+ ur_bsw_t rit_u;
+} _jam_xeno_t;
+
+/* _cs_coin_chub(): shortcircuit u3i_chubs().
+*/
+static inline u3_atom
+_cs_coin_chub(c3_d a_d)
+{
+ return ( 0x7fffffffULL >= a_d ) ? a_d : u3i_chubs(1, &a_d);
+}
+
+/* _cs_jam_xeno_atom(): encode in/direct atom in bitstream.
+*/
+static inline void
+_cs_jam_bsw_atom(ur_bsw_t* rit_u, c3_w met_w, u3_atom a)
+{
+ if ( c3y == u3a_is_cat(a) ) {
+ // XX need a ur_bsw_atom32()
+ //
+ ur_bsw_atom64(rit_u, (c3_y)met_w, (c3_d)a);
+ }
+ else {
+ u3a_atom* vat_u = u3a_to_ptr(a);
+ // XX assumes little-endian
+ // XX need a ur_bsw_atom_words()
+ //
+ c3_y* byt_y = (c3_y*)vat_u->buf_w;
+ ur_bsw_atom_bytes(rit_u, (c3_d)met_w, byt_y);
+ }
+}
+
+/* _cs_jam_bsw_back(): encode in/direct backref in bitstream.
+*/
+static inline void
+_cs_jam_bsw_back(ur_bsw_t* rit_u, c3_w met_w, u3_atom a)
+{
+ c3_d bak_d = ( c3y == u3a_is_cat(a) )
+ ? (c3_d)a
+ : u3r_chub(0, a);
+
+ // XX need a ur_bsw_back32()
+ //
+ ur_bsw_back64(rit_u, (c3_y)met_w, bak_d);
+}
+
+/* _cs_jam_xeno_atom(): encode atom or backref in bitstream.
+*/
+static void
+_cs_jam_xeno_atom(u3_atom a, void* ptr_v)
+{
+ _jam_xeno_t* jam_u = ptr_v;
+ ur_bsw_t* rit_u = &(jam_u->rit_u);
+ u3_weak bak = u3h_git(jam_u->har_p, a);
+ c3_w met_w = u3r_met(0, a);
+
+ if ( u3_none == bak ) {
+ u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits));
+ _cs_jam_bsw_atom(rit_u, met_w, a);
+ }
+ else {
+ c3_w bak_w = u3r_met(0, bak);
+
+ if ( met_w <= bak_w ) {
+ _cs_jam_bsw_atom(rit_u, met_w, a);
+ }
+ else {
+ _cs_jam_bsw_back(rit_u, bak_w, bak);
+ }
+ }
+}
+
+/* _cs_jam_xeno_cell(): encode cell or backref in bitstream.
+*/
+static c3_o
+_cs_jam_xeno_cell(u3_noun a, void* ptr_v)
+{
+ _jam_xeno_t* jam_u = ptr_v;
+ ur_bsw_t* rit_u = &(jam_u->rit_u);
+ u3_weak bak = u3h_git(jam_u->har_p, a);
+
+ if ( u3_none == bak ) {
+ u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits));
+ ur_bsw_cell(rit_u);
+ return c3y;
+ }
+ else {
+ _cs_jam_bsw_back(rit_u, u3r_met(0, bak), bak);
+ return c3n;
+ }
+}
+
+/* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation.
+*/
+c3_d
+u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y)
+{
+ _jam_xeno_t jam_u = {0};
+ ur_bsw_init(&jam_u.rit_u, ur_fib11, ur_fib12);
+ jam_u.har_p = u3h_new();
+
+ u3a_walk_fore(a, &jam_u, _cs_jam_xeno_atom, _cs_jam_xeno_cell);
+
+ u3h_free(jam_u.har_p);
+ return ur_bsw_done(&jam_u.rit_u, len_d, byt_y);
+}
+
+/* _cs_cue: stack frame for tracking intermediate cell results
+*/
+typedef struct _cs_cue {
+ u3_weak hed; // head of a cell or u3_none
+ u3_atom wid; // bitwidth of [hed] or 0
+ u3_atom cur; // bit-cursor position
+} _cs_cue;
+
+/* _cs_rub: rub, TRANSFER [cur], RETAIN [a]
+*/
+static inline u3_noun
+_cs_rub(u3_atom cur, u3_atom a)
+{
+ u3_noun pro = u3qe_rub(cur, a);
+ u3z(cur);
+ return pro;
+}
+
+/* _cs_cue_next(): advance into [a], reading next value
+** TRANSFER [cur], RETAIN [a]
+*/
+static inline u3_noun
+_cs_cue_next(u3a_pile* pil_u,
+ u3p(u3h_root) har_p,
+ u3_atom cur,
+ u3_atom a,
+ u3_atom* wid)
+{
+ while ( 1 ) {
+ // read tag bit at cur
+ //
+ c3_y tag_y = u3qc_cut(0, cur, 1, a);
+
+ // low bit unset, (1 + cur) points to an atom
+ //
+ // produce atom and the width we read
+ //
+ if ( 0 == tag_y ) {
+ u3_noun bur = _cs_rub(u3i_vint(cur), a);
+ u3_noun pro = u3k(u3t(bur));
+
+ u3h_put(har_p, cur, u3k(pro));
+ *wid = u3qa_inc(u3h(bur));
+
+ u3z(bur);
+ return pro;
+ }
+ else {
+ // read tag bit at (1 + cur)
+ //
+ {
+ u3_noun x = u3qa_inc(cur);
+ tag_y = u3qc_cut(0, x, 1, a);
+ u3z(x);
+ }
+
+ // next bit set, (2 + cur) points to a backref
+ //
+ // produce referenced value and the width we read
+ //
+ if ( 1 == tag_y ) {
+ u3_noun bur = _cs_rub(u3ka_add(2, cur), a);
+ u3_noun pro = u3x_good(u3h_get(har_p, u3t(bur)));
+
+ *wid = u3qa_add(2, u3h(bur));
+
+ u3z(bur);
+ return pro;
+ }
+ // next bit unset, (2 + cur) points to the head of a cell
+ //
+ // push a head-frame onto the road stack and read the head
+ //
+ else {
+ _cs_cue* fam_u = u3a_push(pil_u);
+
+ // NB: fam_u->wid unused in head-frame
+ //
+ fam_u->hed = u3_none;
+ fam_u->cur = cur;
+
+ cur = u3qa_add(2, cur);
+ continue;
+ }
+ }
+ }
+}
+
+u3_noun
+u3s_cue(u3_atom a)
+{
+ // pro: cue'd noun product
+ // wid: bitwidth read to produce [pro]
+ // fam_u: stack frame
+ // har_p: backreference table
+ // pil_u: stack control structure
+ //
+ u3_noun pro;
+ u3_atom wid;
+ _cs_cue* fam_u;
+ u3p(u3h_root) har_p = u3h_new();
+ u3a_pile pil_u;
+
+ // initialize stack control
+ //
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // commence cueing at bit-position 0
+ //
+ pro = _cs_cue_next(&pil_u, har_p, 0, a, &wid);
+
+ // process cell results
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // head-frame: stash [pro] and [wid]; continue into the tail
+ //
+ if ( u3_none == fam_u->hed ) {
+ // NB: fam_u->wid unused in head-frame
+ //
+ fam_u->hed = pro;
+ fam_u->wid = wid;
+
+ // continue reading at the bit-position after [pro]
+ {
+ u3_noun cur = u3ka_add(2, u3qa_add(wid, fam_u->cur));
+ pro = _cs_cue_next(&pil_u, har_p, cur, a, &wid);
+ }
+
+ fam_u = u3a_peek(&pil_u);
+ }
+ // tail-frame: cons cell, recalculate [wid], and pop the stack
+ //
+ else {
+ pro = u3nc(fam_u->hed, pro);
+ u3h_put(har_p, fam_u->cur, u3k(pro));
+ u3z(fam_u->cur);
+ wid = u3ka_add(2, u3ka_add(wid, fam_u->wid));
+ fam_u = u3a_pop(&pil_u);
+ }
+ } while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ u3z(wid);
+ u3h_free(har_p);
+
+ return pro;
+}
+
+/*
+** stack frame for recording head vs tail iteration
+**
+** $? [u3_none bits=@]
+** [hed=* bits=@]
+*/
+typedef struct _cue_frame_s {
+ u3_weak ref;
+ c3_d bit_d;
+} _cue_frame_t;
+
+/* _cs_cue_xeno_next(): read next value from bitstream, dictionary off-loom.
+*/
+static inline ur_cue_res_e
+_cs_cue_xeno_next(u3a_pile* pil_u,
+ ur_bsr_t* red_u,
+ ur_dict32_t* dic_u,
+ u3_noun* out)
+{
+ ur_root_t* rot_u = 0;
+
+ while ( 1 ) {
+ c3_d len_d, bit_d = red_u->bits;
+ ur_cue_tag_e tag_e;
+ ur_cue_res_e res_e;
+
+ if ( ur_cue_good != (res_e = ur_bsr_tag(red_u, &tag_e)) ) {
+ return res_e;
+ }
+
+ switch ( tag_e ) {
+ default: u3_assert(0);
+
+ case ur_jam_cell: {
+ _cue_frame_t* fam_u = u3a_push(pil_u);
+
+ fam_u->ref = u3_none;
+ fam_u->bit_d = bit_d;
+ continue;
+ }
+
+ case ur_jam_back: {
+ if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) {
+ return res_e;
+ }
+ else if ( 62 < len_d ) {
+ return ur_cue_meme;
+ }
+ else {
+ c3_d bak_d = ur_bsr64_any(red_u, len_d);
+ c3_w bak_w;
+
+ if ( !ur_dict32_get(rot_u, dic_u, bak_d, &bak_w) ) {
+ return ur_cue_back;
+ }
+
+ *out = u3k((u3_noun)bak_w);
+ return ur_cue_good;
+ }
+ }
+
+ case ur_jam_atom: {
+ if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) {
+ return res_e;
+ }
+
+ if ( 31 >= len_d ) {
+ *out = (u3_noun)ur_bsr32_any(red_u, len_d);
+ }
+ else {
+ c3_d byt_d = (len_d + 0x7) >> 3;
+ u3i_slab sab_u;
+
+ if ( 0xffffffffULL < byt_d) {
+ return ur_cue_meme;
+ }
+ else {
+ u3i_slab_init(&sab_u, 3, byt_d);
+ ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y);
+ *out = u3i_slab_mint_bytes(&sab_u);
+ }
+ }
+
+ ur_dict32_put(rot_u, dic_u, bit_d, *out);
+ return ur_cue_good;
+ }
+ }
+ }
+}
+
+struct _u3_cue_xeno {
+ ur_dict32_t dic_u;
+};
+
+/* _cs_cue_xeno(): cue on-loom, with off-loom dictionary in handle.
+*/
+static u3_weak
+_cs_cue_xeno(u3_cue_xeno* sil_u,
+ c3_d len_d,
+ const c3_y* byt_y)
+{
+ ur_bsr_t red_u = {0};
+ ur_dict32_t* dic_u = &sil_u->dic_u;
+ u3a_pile pil_u;
+ _cue_frame_t* fam_u;
+ ur_cue_res_e res_e;
+ u3_noun ref;
+
+ // initialize stack control
+ //
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // init bitstream-reader
+ //
+ if ( ur_cue_good != (res_e = ur_bsr_init(&red_u, len_d, byt_y)) ) {
+ return c3n;
+ }
+ // bit-cursor (and backreferences) must fit in 62-bit direct atoms
+ //
+ else if ( 0x7ffffffffffffffULL < len_d ) {
+ return c3n;
+ }
+
+ // advance into stream
+ //
+ res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref);
+
+ // process cell results
+ //
+ if ( (c3n == u3a_pile_done(&pil_u))
+ && (ur_cue_good == res_e) )
+ {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // f is a head-frame; stash result and read the tail from the stream
+ //
+ if ( u3_none == fam_u->ref ) {
+ fam_u->ref = ref;
+ res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref);
+ fam_u = u3a_peek(&pil_u);
+ }
+ // f is a tail-frame; pop the stack and continue
+ //
+ else {
+ ur_root_t* rot_u = 0;
+
+ ref = u3nc(fam_u->ref, ref);
+ ur_dict32_put(rot_u, dic_u, fam_u->bit_d, ref);
+ fam_u = u3a_pop(&pil_u);
+ }
+ }
+ while ( (c3n == u3a_pile_done(&pil_u))
+ && (ur_cue_good == res_e) );
+ }
+
+ if ( ur_cue_good == res_e ) {
+ return ref;
+ }
+ // on failure, unwind the stack and dispose of intermediate nouns
+ //
+ else if ( c3n == u3a_pile_done(&pil_u) ) {
+ do {
+ if ( u3_none != fam_u->ref ) {
+ u3z(fam_u->ref);
+ }
+ fam_u = u3a_pop(&pil_u);
+ }
+ while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ return u3_none;
+}
+
+/* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified.
+*/
+u3_cue_xeno*
+u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d)
+{
+ u3_cue_xeno* sil_u;
+
+ sil_u = c3_calloc(sizeof(*sil_u));
+ ur_dict32_grow((ur_root_t*)0, &sil_u->dic_u, pre_d, siz_d);
+
+ return sil_u;
+}
+
+/* u3s_cue_xeno_init(): initialize a cue_xeno handle.
+*/
+u3_cue_xeno*
+u3s_cue_xeno_init(void)
+{
+ return u3s_cue_xeno_init_with(ur_fib10, ur_fib11);
+}
+
+/* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle.
+*/
+u3_weak
+u3s_cue_xeno_with(u3_cue_xeno* sil_u,
+ c3_d len_d,
+ const c3_y* byt_y)
+{
+ u3_weak som;
+
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ som = _cs_cue_xeno(sil_u, len_d, byt_y);
+ ur_dict32_wipe(&sil_u->dic_u);
+ return som;
+}
+
+/* u3s_cue_xeno_init(): dispose cue_xeno handle.
+*/
+void
+u3s_cue_xeno_done(u3_cue_xeno* sil_u)
+{
+ ur_dict_free((ur_dict_t*)&sil_u->dic_u);
+ c3_free(sil_u);
+}
+
+/* u3s_cue_xeno(): cue on-loom, with off-loom dictionary.
+*/
+u3_weak
+u3s_cue_xeno(c3_d len_d,
+ const c3_y* byt_y)
+{
+ u3_cue_xeno* sil_u;
+ u3_weak som;
+
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ sil_u = u3s_cue_xeno_init();
+ som = _cs_cue_xeno(sil_u, len_d, byt_y);
+ u3s_cue_xeno_done(sil_u);
+ return som;
+}
+
+/* _cs_cue_need(): bail on ur_cue_* read failures.
+*/
+static inline void
+_cs_cue_need(ur_cue_res_e res_e)
+{
+ if ( ur_cue_good == res_e ) {
+ return;
+ }
+ else {
+ c3_m mot_m = (ur_cue_meme == res_e) ? c3__meme : c3__exit;
+ u3m_bail(mot_m);
+ }
+}
+
+/* _cs_cue_get(): u3h_get wrapper handling allocation and refcounts.
+*/
+static inline u3_weak
+_cs_cue_get(u3p(u3h_root) har_p, c3_d key_d)
+{
+ u3_atom key = _cs_coin_chub(key_d);
+ u3_weak pro = u3h_get(har_p, key);
+ u3z(key);
+ return pro;
+}
+
+/* _cs_cue_put(): u3h_put wrapper handling allocation and refcounts.
+*/
+static inline u3_noun
+_cs_cue_put(u3p(u3h_root) har_p, c3_d key_d, u3_noun val)
+{
+ u3_atom key = _cs_coin_chub(key_d);
+ u3h_put(har_p, key, u3k(val));
+ u3z(key);
+ return val;
+}
+
+/* _cs_cue_bytes_next(): read next value from bitstream.
+*/
+static inline u3_noun
+_cs_cue_bytes_next(u3a_pile* pil_u,
+ u3p(u3h_root) har_p,
+ ur_bsr_t* red_u)
+{
+ while ( 1 ) {
+ c3_d len_d, bit_d = red_u->bits;
+ ur_cue_tag_e tag_e;
+
+ _cs_cue_need(ur_bsr_tag(red_u, &tag_e));
+
+ switch ( tag_e ) {
+ default: u3_assert(0);
+
+ case ur_jam_cell: {
+ _cue_frame_t* fam_u = u3a_push(pil_u);
+
+ fam_u->ref = u3_none;
+ fam_u->bit_d = bit_d;
+ continue;
+ }
+
+ case ur_jam_back: {
+ _cs_cue_need(ur_bsr_rub_len(red_u, &len_d));
+
+ if ( 62 < len_d ) {
+ return u3m_bail(c3__meme);
+ }
+ else {
+ c3_d bak_d = ur_bsr64_any(red_u, len_d);
+ u3_weak bak = _cs_cue_get(har_p, bak_d);
+ return u3x_good(bak);
+ }
+ }
+
+ case ur_jam_atom: {
+ u3_atom vat;
+
+ _cs_cue_need(ur_bsr_rub_len(red_u, &len_d));
+
+ if ( 31 >= len_d ) {
+ vat = (u3_noun)ur_bsr32_any(red_u, len_d);
+ }
+ else {
+ u3i_slab sab_u;
+ u3i_slab_init(&sab_u, 0, len_d);
+
+ ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y);
+ vat = u3i_slab_mint_bytes(&sab_u);
+ }
+
+ return _cs_cue_put(har_p, bit_d, vat);
+ }
+ }
+ }
+}
+
+/* u3s_cue_bytes(): cue bytes onto the loom.
+*/
+u3_noun
+u3s_cue_bytes(c3_d len_d, const c3_y* byt_y)
+{
+ ur_bsr_t red_u = {0};
+ u3a_pile pil_u;
+ _cue_frame_t* fam_u;
+ u3p(u3h_root) har_p;
+ u3_noun ref;
+
+ // initialize stack control
+ //
+ u3a_pile_prep(&pil_u, sizeof(*fam_u));
+
+ // initialize a hash table for dereferencing backrefs
+ //
+ har_p = u3h_new();
+
+ // init bitstream-reader
+ //
+ _cs_cue_need(ur_bsr_init(&red_u, len_d, byt_y));
+
+ // bit-cursor (and backreferences) must fit in 62-bit direct atoms
+ //
+ if ( 0x7ffffffffffffffULL < len_d ) {
+ return u3m_bail(c3__meme);
+ }
+
+ // advance into stream
+ //
+ ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u);
+
+ // process cell results
+ //
+ if ( c3n == u3a_pile_done(&pil_u) ) {
+ fam_u = u3a_peek(&pil_u);
+
+ do {
+ // f is a head-frame; stash result and read the tail from the stream
+ //
+ if ( u3_none == fam_u->ref ) {
+ fam_u->ref = ref;
+ ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u);
+ fam_u = u3a_peek(&pil_u);
+ }
+ // f is a tail-frame; pop the stack and continue
+ //
+ else {
+ ref = u3nc(fam_u->ref, ref);
+ _cs_cue_put(har_p, fam_u->bit_d, ref);
+ fam_u = u3a_pop(&pil_u);
+ }
+ }
+ while ( c3n == u3a_pile_done(&pil_u) );
+ }
+
+ u3h_free(har_p);
+
+ return ref;
+}
+
+/* u3s_cue_atom(): cue atom.
+*/
+u3_noun
+u3s_cue_atom(u3_atom a)
+{
+ c3_w len_w = u3r_met(3, a);
+ 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;
+ }
+
+ return u3s_cue_bytes((c3_d)len_w, byt_y);
+}
+
+/* _cs_etch_ud_size(): output length in @ud for given mpz_t.
+*/
+static inline size_t
+_cs_etch_ud_size(mpz_t a_mp)
+{
+ size_t len_i = mpz_sizeinbase(a_mp, 10);
+ return len_i + (len_i / 3); // separators
+}
+
+/* _cs_etch_ud_bytes(): atom to @ud impl.
+*/
+static size_t
+_cs_etch_ud_bytes(mpz_t a_mp, size_t len_i, c3_y* hun_y)
+{
+ c3_y* buf_y = hun_y + (len_i - 1);
+ mpz_t b_mp;
+ c3_w b_w;
+
+ mpz_init2(b_mp, 10);
+
+ if ( !mpz_size(a_mp) ) {
+ *buf_y-- = '0';
+ }
+ else {
+ while ( 1 ) {
+ b_w = mpz_tdiv_qr_ui(a_mp, b_mp, a_mp, 1000);
+ u3_assert( mpz_get_ui(b_mp) == b_w ); // XX
+
+ if ( !mpz_size(a_mp) ) {
+ while ( b_w ) {
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ }
+ break;
+ }
+
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ *buf_y-- = '0' + (b_w % 10);
+ *buf_y-- = '.';
+ }
+ }
+
+ buf_y++;
+
+ u3_assert( buf_y >= hun_y ); // XX
+
+ // mpz_sizeinbase may overestimate by 1
+ //
+ {
+ size_t dif_i = buf_y - hun_y;
+
+ if ( dif_i ) {
+ len_i -= dif_i;
+ memmove(hun_y, buf_y, len_i);
+ memset(hun_y + len_i, 0, dif_i);
+ }
+ }
+
+ mpz_clear(b_mp);
+
+ return len_i;
+}
+
+/* u3s_etch_ud_smol(): c3_d to @ud
+**
+** =(26 (met 3 (scot %ud (dec (bex 64)))))
+*/
+c3_y*
+u3s_etch_ud_smol(c3_d a_d, c3_y hun_y[26])
+{
+ c3_y* buf_y = hun_y + 25;
+ c3_w b_w;
+
+ if ( !a_d ) {
+ *buf_y-- = '0';
+ }
+ else {
+ while ( 1 ) {
+ b_w = a_d % 1000;
+ a_d /= 1000;
+
+ if ( !a_d ) {
+ while ( b_w ) {
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ }
+ break;
+ }
+
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ *buf_y-- = '0' + (b_w % 10);
+ b_w /= 10;
+ *buf_y-- = '0' + (b_w % 10);
+ *buf_y-- = '.';
+ }
+ }
+
+ return buf_y + 1;
+}
+
+/* u3s_etch_ud(): atom to @ud.
+*/
+u3_atom
+u3s_etch_ud(u3_atom a)
+{
+ c3_d a_d;
+
+ if ( c3y == u3r_safe_chub(a, &a_d) ) {
+ c3_y hun_y[26];
+ c3_y* buf_y = u3s_etch_ud_smol(a_d, hun_y);
+ c3_w dif_w = (c3_p)buf_y - (c3_p)hun_y;
+ return u3i_bytes(26 - dif_w, buf_y);
+ }
+
+ u3i_slab sab_u;
+ size_t len_i;
+ mpz_t a_mp;
+ u3r_mp(a_mp, a);
+
+ len_i = _cs_etch_ud_size(a_mp);
+ u3i_slab_bare(&sab_u, 3, len_i);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ _cs_etch_ud_bytes(a_mp, len_i, sab_u.buf_y);
+
+ mpz_clear(a_mp);
+ return u3i_slab_mint_bytes(&sab_u);
+}
+
+/* u3s_etch_ud_c(): atom to @ud, as a malloc'd c string.
+*/
+size_t
+u3s_etch_ud_c(u3_atom a, c3_c** out_c)
+{
+ c3_d a_d;
+ size_t len_i;
+ c3_y* buf_y;
+
+ if ( c3y == u3r_safe_chub(a, &a_d) ) {
+ c3_y hun_y[26];
+
+ buf_y = u3s_etch_ud_smol(a_d, hun_y);
+ len_i = 26 - ((c3_p)buf_y - (c3_p)hun_y);
+
+ *out_c = c3_malloc(len_i + 1);
+ (*out_c)[len_i] = 0;
+ memcpy(*out_c, buf_y, len_i);
+
+ return len_i;
+ }
+
+ mpz_t a_mp;
+ u3r_mp(a_mp, a);
+
+ len_i = _cs_etch_ud_size(a_mp);
+ buf_y = c3_malloc(len_i + 1);
+ buf_y[len_i] = 0;
+
+ len_i = _cs_etch_ud_bytes(a_mp, len_i, buf_y);
+
+ mpz_clear(a_mp);
+
+ *out_c = (c3_c*)buf_y;
+ return len_i;
+}
+
+/* _cs_etch_ux_bytes(): atom to @ux impl.
+*/
+static void
+_cs_etch_ux_bytes(u3_atom a, c3_w len_w, c3_y* buf_y)
+{
+ c3_w i_w;
+ c3_s inp_s;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ inp_s = u3r_short(i_w, a);
+
+ *buf_y-- = u3s_dit_y[(inp_s >> 0) & 0xf];
+ *buf_y-- = u3s_dit_y[(inp_s >> 4) & 0xf];
+ *buf_y-- = u3s_dit_y[(inp_s >> 8) & 0xf];
+ *buf_y-- = u3s_dit_y[(inp_s >> 12) & 0xf];
+ *buf_y-- = '.';
+ }
+
+ inp_s = u3r_short(len_w, a);
+
+ while ( inp_s ) {
+ *buf_y-- = u3s_dit_y[inp_s & 0xf];
+ inp_s >>= 4;
+ }
+
+ *buf_y-- = 'x';
+ *buf_y = '0';
+}
+
+/* u3s_etch_ux(): atom to @ux.
+*/
+u3_atom
+u3s_etch_ux(u3_atom a)
+{
+ if ( u3_blip == a ) {
+ return c3_s3('0', 'x', '0');
+ }
+
+ c3_w sep_w = u3r_met(4, a) - 1; // number of separators
+ c3_w las_w = u3r_met(2, u3r_short(sep_w, a)); // digits before separator
+ c3_w len_w = 2 + las_w + (sep_w * 5); // output bytes
+ u3i_slab sab_u;
+ u3i_slab_bare(&sab_u, 3, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ _cs_etch_ux_bytes(a, sep_w, sab_u.buf_y + len_w - 1);
+
+ return u3i_slab_moot_bytes(&sab_u);
+}
+
+/* u3s_etch_ux_c(): atom to @ux, as a malloc'd c string.
+*/
+size_t
+u3s_etch_ux_c(u3_atom a, c3_c** out_c)
+{
+ if ( u3_blip == a ) {
+ *out_c = strdup("0x0");
+ return 3;
+ }
+
+ c3_y* buf_y;
+ c3_w sep_w = u3r_met(4, a) - 1;
+ c3_w las_w = u3r_met(2, u3r_short(sep_w, a));
+ size_t len_i = 2 + las_w + (sep_w * 5);
+
+ buf_y = c3_malloc(1 + len_i);
+ buf_y[len_i] = 0;
+ _cs_etch_ux_bytes(a, sep_w, buf_y + len_i - 1);
+
+ *out_c = (c3_c*)buf_y;
+ return len_i;
+}
+
+// uint div+ceil non-zero
+//
+#define _divc_nz(x, y) (((x) + ((y) - 1)) / (y))
+
+/* _cs_etch_uv_size(): output length in @uv (and aligned bits).
+*/
+static inline size_t
+_cs_etch_uv_size(u3_atom a, c3_w* out_w)
+{
+ c3_w met_w = u3r_met(0, a);
+ c3_w sep_w = _divc_nz(met_w, 25) - 1; // number of separators
+ c3_w max_w = sep_w * 25;
+ c3_w end_w = 0;
+ u3r_chop(0, max_w, 25, 0, &end_w, a);
+
+ c3_w bit_w = c3_bits_word(end_w);
+ c3_w las_w = _divc_nz(bit_w, 5); // digits before separator
+
+ *out_w = max_w;
+ return 2 + las_w + (sep_w * 6);
+}
+
+
+/* _cs_etch_uv_bytes(): atom to @uv impl.
+*/
+static void
+_cs_etch_uv_bytes(u3_atom a, c3_w max_w, c3_y* buf_y)
+{
+ c3_w i_w;
+ c3_w inp_w;
+
+ for ( i_w = 0; i_w < max_w; i_w += 25 ) {
+ inp_w = 0;
+ u3r_chop(0, i_w, 25, 0, &inp_w, a);
+
+ *buf_y-- = u3s_dit_y[(inp_w >> 0) & 0x1f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 5) & 0x1f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 10) & 0x1f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 15) & 0x1f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 20) & 0x1f];
+ *buf_y-- = '.';
+ }
+
+ inp_w = 0;
+ u3r_chop(0, max_w, 25, 0, &inp_w, a);
+
+ while ( inp_w ) {
+ *buf_y-- = u3s_dit_y[inp_w & 0x1f];
+ inp_w >>= 5;
+ }
+
+ *buf_y-- = 'v';
+ *buf_y = '0';
+}
+
+/* u3s_etch_uv(): atom to @uv.
+*/
+u3_atom
+u3s_etch_uv(u3_atom a)
+{
+ if ( u3_blip == a ) {
+ return c3_s3('0', 'v', '0');
+ }
+
+ u3i_slab sab_u;
+ c3_w max_w;
+ size_t len_i = _cs_etch_uv_size(a, &max_w);
+
+ u3i_slab_bare(&sab_u, 3, len_i);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ _cs_etch_uv_bytes(a, max_w, sab_u.buf_y + len_i - 1);
+
+ return u3i_slab_moot_bytes(&sab_u);
+}
+
+/* u3s_etch_uv_c(): atom to @uv, as a malloc'd c string.
+*/
+size_t
+u3s_etch_uv_c(u3_atom a, c3_c** out_c)
+{
+ if ( u3_blip == a ) {
+ *out_c = strdup("0v0");
+ return 3;
+ }
+
+ c3_y* buf_y;
+ c3_w max_w;
+ size_t len_i = _cs_etch_uv_size(a, &max_w);
+
+ buf_y = c3_malloc(1 + len_i);
+ buf_y[len_i] = 0;
+ _cs_etch_uv_bytes(a, max_w, buf_y + len_i - 1);
+
+ *out_c = (c3_c*)buf_y;
+ return len_i;
+}
+
+/* _cs_etch_uw_size(): output length in @uw (and aligned bits).
+*/
+static inline size_t
+_cs_etch_uw_size(u3_atom a, c3_w* out_w)
+{
+ c3_w met_w = u3r_met(0, a);
+ c3_w sep_w = _divc_nz(met_w, 30) - 1; // number of separators
+ c3_w max_w = sep_w * 30;
+ c3_w end_w = 0;
+ u3r_chop(0, max_w, 30, 0, &end_w, a);
+
+ c3_w bit_w = c3_bits_word(end_w);
+ c3_w las_w = _divc_nz(bit_w, 6); // digits before separator
+
+ *out_w = max_w;
+ return 2 + las_w + (sep_w * 6);
+}
+
+/* _cs_etch_uw_bytes(): atom to @uw impl.
+*/
+static void
+_cs_etch_uw_bytes(u3_atom a, c3_w max_w, c3_y* buf_y)
+{
+ c3_w i_w;
+ c3_w inp_w;
+
+ for ( i_w = 0; i_w < max_w; i_w += 30 ) {
+ inp_w = 0;
+ u3r_chop(0, i_w, 30, 0, &inp_w, a);
+
+ *buf_y-- = u3s_dit_y[(inp_w >> 0) & 0x3f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 6) & 0x3f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 12) & 0x3f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 18) & 0x3f];
+ *buf_y-- = u3s_dit_y[(inp_w >> 24) & 0x3f];
+ *buf_y-- = '.';
+ }
+
+ inp_w = 0;
+ u3r_chop(0, max_w, 30, 0, &inp_w, a);
+
+ while ( inp_w ) {
+ *buf_y-- = u3s_dit_y[inp_w & 0x3f];
+ inp_w >>= 6;
+ }
+
+ *buf_y-- = 'w';
+ *buf_y = '0';
+}
+
+/* u3s_etch_uw(): atom to @uw.
+*/
+u3_atom
+u3s_etch_uw(u3_atom a)
+{
+ if ( u3_blip == a ) {
+ return c3_s3('0', 'w', '0');
+ }
+
+ u3i_slab sab_u;
+ c3_w max_w;
+ size_t len_i = _cs_etch_uw_size(a, &max_w);
+
+ u3i_slab_bare(&sab_u, 3, len_i);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ _cs_etch_uw_bytes(a, max_w, sab_u.buf_y + len_i - 1);
+
+ return u3i_slab_moot_bytes(&sab_u);
+}
+
+/* u3s_etch_uw_c(): atom to @uw, as a malloc'd c string.
+*/
+size_t
+u3s_etch_uw_c(u3_atom a, c3_c** out_c)
+{
+ if ( u3_blip == a ) {
+ *out_c = strdup("0w0");
+ return 3;
+ }
+
+ c3_y* buf_y;
+ c3_w max_w;
+ size_t len_i = _cs_etch_uw_size(a, &max_w);
+
+ buf_y = c3_malloc(1 + len_i);
+ buf_y[len_i] = 0;
+ _cs_etch_uw_bytes(a, max_w, buf_y + len_i - 1);
+
+ *out_c = (c3_c*)buf_y;
+ return len_i;
+}
+
+#undef _divc_nz
+
+#define DIGIT(a) ( ((a) >= '0') && ((a) <= '9') )
+#define BLOCK(a) ( ('.' == (a)[0]) \
+ && DIGIT(a[1]) \
+ && DIGIT(a[2]) \
+ && DIGIT(a[3]) )
+
+/* u3s_sift_ud_bytes: parse @ud
+*/
+u3_weak
+u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y)
+{
+ c3_y num_y = len_w % 4; // leading digits length
+ c3_s val_s = 0; // leading digits value
+
+ // +ape:ag: just 0
+ //
+ if ( !len_w ) return u3_none;
+ if ( '0' == *byt_y ) return ( 1 == len_w ) ? (u3_noun)0 : u3_none;
+
+ // +ted:ab: leading nonzero (checked above), plus up to 2 digits
+ //
+#define NEXT() do { \
+ if ( !DIGIT(*byt_y) ) return u3_none; \
+ val_s *= 10; \
+ val_s += *byt_y++ - '0'; \
+ } while (0)
+
+ switch ( num_y ) {
+ case 3: NEXT();
+ case 2: NEXT();
+ case 1: NEXT(); break;
+ case 0: return u3_none;
+ }
+
+#undef NEXT
+
+ len_w -= num_y;
+
+ // +tid:ab: dot-prefixed 3-digit blocks
+ //
+ // avoid gmp allocation if possible
+ // - 19 decimal digits fit in 64 bits
+ // - 18 digits is 24 bytes with separators
+ //
+ if ( ((1 == num_y) && (24 >= len_w))
+ || (20 >= len_w) )
+ {
+ c3_d val_d = val_s;
+
+ while ( len_w ) {
+ if ( !BLOCK(byt_y) ) return u3_none;
+
+ byt_y++;
+
+ val_d *= 10;
+ val_d += *byt_y++ - '0';
+ val_d *= 10;
+ val_d += *byt_y++ - '0';
+ val_d *= 10;
+ val_d += *byt_y++ - '0';
+
+ len_w -= 4;
+ }
+
+ return u3i_chub(val_d);
+ }
+
+ {
+ // avoid gmp realloc if possible
+ //
+ mpz_t a_mp;
+ {
+ c3_d bit_d = (c3_d)(len_w / 4) * 10;
+ mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX));
+ mpz_set_ui(a_mp, val_s);
+ }
+
+ while ( len_w ) {
+ if ( !BLOCK(byt_y) ) {
+ mpz_clear(a_mp);
+ return u3_none;
+ }
+
+ byt_y++;
+
+ val_s = *byt_y++ - '0';
+ val_s *= 10;
+ val_s += *byt_y++ - '0';
+ val_s *= 10;
+ val_s += *byt_y++ - '0';
+
+ mpz_mul_ui(a_mp, a_mp, 1000);
+ mpz_add_ui(a_mp, a_mp, val_s);
+
+ len_w -= 4;
+ }
+
+ return u3i_mp(a_mp);
+ }
+}
+
+#undef BLOCK
+#undef DIGIT
+
+/* u3s_sift_ud: parse @ud.
+*/
+u3_weak
+u3s_sift_ud(u3_atom a)
+{
+ c3_w len_w = u3r_met(3, a);
+ 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;
+ }
+
+ return u3s_sift_ud_bytes(len_w, byt_y);
+}
diff --git a/vere/pkg/noun/serial.h b/vere/pkg/noun/serial.h
new file mode 100644
index 0000000..d7dd5a8
--- /dev/null
+++ b/vere/pkg/noun/serial.h
@@ -0,0 +1,137 @@
+/// @file
+
+#ifndef U3_SERIAL_H
+#define U3_SERIAL_H
+
+#include "c3/c3.h"
+#include "imprison.h"
+#include "types.h"
+ /* constants
+ */
+ /* u3_dit_y: digit table for @ux/@uv/@uw.
+ */
+ extern const c3_y u3s_dit_y[64];
+
+ /* opaque handles
+ */
+ /* u3_cue_xeno: handle for cue-ing with an off-loom dictionary.
+ */
+ typedef struct _u3_cue_xeno u3_cue_xeno;
+
+ /* Noun serialization. All noun arguments RETAINED.
+ */
+
+ /* u3s_jam_fib(): jam without atom allocation.
+ **
+ ** returns atom-suitable words, and *bit_w will have
+ ** the length (in bits). return should be freed with u3a_wfree().
+ */
+ c3_w
+ u3s_jam_fib(u3i_slab* sab_u, u3_noun a);
+
+ /* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation.
+ */
+ c3_d
+ u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y);
+
+ /* u3s_cue(): cue [a]
+ */
+ u3_noun
+ u3s_cue(u3_atom a);
+
+ /* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified.
+ */
+ u3_cue_xeno*
+ u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d);
+
+ /* u3s_cue_xeno_init(): initialize a cue_xeno handle.
+ */
+ u3_cue_xeno*
+ u3s_cue_xeno_init(void);
+
+ /* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle.
+ */
+ u3_weak
+ u3s_cue_xeno_with(u3_cue_xeno* sil_u,
+ c3_d len_d,
+ const c3_y* byt_y);
+
+ /* u3s_cue_xeno_init(): dispose cue_xeno handle.
+ */
+ void
+ u3s_cue_xeno_done(u3_cue_xeno* sil_u);
+
+ /* u3s_cue_xeno(): cue on-loom, with off-loom dictionary.
+ */
+ u3_weak
+ u3s_cue_xeno(c3_d len_d,
+ const c3_y* byt_y);
+
+ /* u3s_cue_bytes(): cue bytes onto the loom.
+ */
+ u3_noun
+ u3s_cue_bytes(c3_d len_d, const c3_y* byt_y);
+
+ /* u3s_cue_atom(): cue atom.
+ */
+ u3_noun
+ u3s_cue_atom(u3_atom a);
+
+ /* u3s_etch_ud_smol(): c3_d to @ud
+ **
+ ** =(26 (met 3 (scot %ud (dec (bex 64)))))
+ */
+ c3_y*
+ u3s_etch_ud_smol(c3_d a_d, c3_y hun_y[26]);
+
+ /* u3s_etch_ud(): atom to @ud.
+ */
+ u3_atom
+ u3s_etch_ud(u3_atom a);
+
+ /* u3s_etch_ud_c(): atom to @ud, as a malloc'd c string.
+ */
+ size_t
+ u3s_etch_ud_c(u3_atom a, c3_c** out_c);
+
+ /* u3s_etch_ux(): atom to @ux.
+ */
+ u3_atom
+ u3s_etch_ux(u3_atom a);
+
+ /* u3s_etch_ux_c(): atom to @ux, as a malloc'd c string.
+ */
+ size_t
+ u3s_etch_ux_c(u3_atom a, c3_c** out_c);
+
+ /* u3s_etch_uv(): atom to @uv.
+ */
+ u3_atom
+ u3s_etch_uv(u3_atom a);
+
+ /* u3s_etch_uv_c(): atom to @uv, as a malloc'd c string.
+ */
+ size_t
+ u3s_etch_uv_c(u3_atom a, c3_c** out_c);
+
+ /* u3s_etch_uw(): atom to @uw.
+ */
+ u3_atom
+ u3s_etch_uw(u3_atom a);
+
+ /* u3s_etch_uw_c(): atom to @uw, as a malloc'd c string.
+ */
+ size_t
+ u3s_etch_uw_c(u3_atom a, c3_c** out_c);
+
+ /* u3s_sift_ud_bytes: parse @ud.
+ */
+ u3_weak
+ u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y);
+
+ /* u3s_sift_ud: parse @ud.
+ */
+ u3_weak
+ u3s_sift_ud(u3_atom a);
+
+#endif /* ifndef U3_SERIAL_H */
diff --git a/vere/pkg/noun/serial_tests.c b/vere/pkg/noun/serial_tests.c
new file mode 100644
index 0000000..5f1caf7
--- /dev/null
+++ b/vere/pkg/noun/serial_tests.c
@@ -0,0 +1,264 @@
+/// @file
+
+#include "noun.h"
+
+/* _setup(): prepare for tests.
+*/
+static void
+_setup(void)
+{
+ u3m_boot_lite(1 << 24);
+}
+
+static void
+_byte_print(c3_d out_d,
+ c3_y* out_y,
+ c3_w len_w,
+ const c3_y* byt_y)
+{
+ c3_d i_d;
+
+ fprintf(stderr, " actual: { ");
+ for ( i_d = 0; i_d < out_d; i_d++ ) {
+ fprintf(stderr, "0x%x, ", out_y[i_d]);
+ }
+ fprintf(stderr, "}\r\n");
+ fprintf(stderr, " expect: { ");
+ for ( i_d = 0; i_d < len_w; i_d++ ) {
+ fprintf(stderr, "0x%x, ", byt_y[i_d]);
+ }
+ fprintf(stderr, "}\r\n");
+}
+
+static c3_i
+_test_jam_spec(const c3_c* cap_c,
+ u3_noun ref,
+ c3_w len_w,
+ const c3_y* byt_y)
+{
+ c3_i ret_i = 1;
+ c3_d out_d;
+ c3_y* out_y;
+
+ {
+ u3s_jam_xeno(ref, &out_d, &out_y);
+
+ if ( 0 != memcmp(out_y, byt_y, len_w) ) {
+ fprintf(stderr, "\033[31mjam xeno %s fail\033[0m\r\n", cap_c);
+ _byte_print(out_d, out_y, len_w, byt_y);
+ ret_i = 0;
+ }
+
+ free(out_y);
+ }
+
+ {
+ u3i_slab sab_u;
+ c3_w bit_w = u3s_jam_fib(&sab_u, ref);
+
+ out_d = ((c3_d)bit_w + 0x7) >> 3;
+ // XX assumes little-endian
+ //
+ out_y = sab_u.buf_y;
+
+ if ( 0 != memcmp(out_y, byt_y, len_w) ) {
+ fprintf(stderr, "\033[31mjam fib %s fail\033[0m\r\n", cap_c);
+ _byte_print(out_d, out_y, len_w, byt_y);
+ ret_i = 0;
+ }
+
+ u3i_slab_free(&sab_u);
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_cue_spec(const c3_c* cap_c,
+ u3_noun ref,
+ c3_w len_w,
+ const c3_y* byt_y)
+{
+ c3_i ret_i = 1;
+
+ {
+ u3_noun pro = u3m_soft(0, u3s_cue_atom, u3i_bytes(len_w, byt_y));
+ u3_noun tag, out;
+
+ u3x_cell(pro, &tag, &out);
+
+ if ( u3_blip != tag ) {
+ fprintf(stderr, "\033[31mcue %s fail 1\033[0m\r\n", cap_c);
+ ret_i = 0;
+ }
+ else if ( c3n == u3r_sing(ref, out) ) {
+ fprintf(stderr, "\033[31mcue %s fail 2\033[0m\r\n", cap_c);
+ u3m_p("ref", ref);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(pro);
+ }
+
+ {
+ u3_noun out;
+
+ if ( u3_none == (out = u3s_cue_xeno(len_w, byt_y)) ) {
+ fprintf(stderr, "\033[31mcue %s fail 3\033[0m\r\n", cap_c);
+ ret_i = 0;
+ }
+ else if ( c3n == u3r_sing(ref, out) ) {
+ fprintf(stderr, "\033[31mcue %s fail 4\033[0m\r\n", cap_c);
+ u3m_p("ref", ref);
+ u3m_p("out", out);
+ ret_i = 0;
+ }
+
+ u3z(out);
+ }
+
+ return ret_i;
+}
+
+static c3_i
+_test_jam_roundtrip(void)
+{
+ c3_i ret_i = 1;
+
+# define TEST_CASE(a, b) \
+ const c3_c* cap_c = a; \
+ u3_noun ref = b; \
+ ret_i &= _test_jam_spec(cap_c, ref, sizeof(res_y), res_y); \
+ ret_i &= _test_cue_spec(cap_c, ref, sizeof(res_y), res_y); \
+ u3z(ref);
+
+ {
+ c3_y res_y[1] = { 0x2 };
+ TEST_CASE("0", 0);
+ }
+
+ {
+ c3_y res_y[1] = { 0xc };
+ TEST_CASE("1", 1);
+ }
+
+ {
+ c3_y res_y[1] = { 0x48 };
+ TEST_CASE("2", 2);
+ }
+
+ {
+ c3_y res_y[6] = { 0xc0, 0x37, 0xb, 0x9b, 0xa3, 0x3 };
+ TEST_CASE("%fast", c3__fast);
+ }
+
+ {
+ c3_y res_y[6] = { 0xc0, 0x37, 0xab, 0x63, 0x63, 0x3 };
+ TEST_CASE("%full", c3__full);
+ }
+
+ {
+ c3_y res_y[1] = { 0x29 };
+ TEST_CASE("[0 0]", u3nc(0, 0));
+ }
+
+ {
+ c3_y res_y[2] = { 0x31, 0x3 };
+ TEST_CASE("[1 1]", u3nc(1, 1));
+ }
+
+ {
+ c3_y res_y[2] = { 0x31, 0x12 };
+ TEST_CASE("[1 2]", u3nc(1, 2));
+ }
+
+ {
+ c3_y res_y[2] = { 0x21, 0xd1 };
+ TEST_CASE("[2 3]", u3nc(2, 3));
+ }
+
+ {
+ c3_y res_y[11] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0xe, 0x7c, 0xb3, 0x3a, 0x36, 0x36 };
+ TEST_CASE("[%fast %full]", u3nc(c3__fast, c3__full));
+ }
+
+ {
+ c3_y res_y[2] = { 0x71, 0xcc };
+ TEST_CASE("[1 1 1]", u3nc(1, u3nc(1, 1)));
+ }
+
+ {
+ c3_y res_y[3] = { 0x71, 0x48, 0x34 };
+ TEST_CASE("[1 2 3]", u3nt(1, 2, 3));
+ }
+
+ {
+ c3_y res_y[12] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0x1e, 0xf0, 0xcd, 0xea, 0xd8, 0xd8, 0x93 };
+ TEST_CASE("[%fast %full %fast]", u3nc(c3__fast, u3nc(c3__full, c3__fast)));
+ }
+
+ {
+ c3_y res_y[3] = { 0xc5, 0x48, 0x34 };
+ TEST_CASE("[[1 2] 3]", u3nc(u3nc(1, 2), 3));
+ }
+
+ {
+ c3_y res_y[5] = { 0xc5, 0xc8, 0x26, 0x27, 0x1 };
+ TEST_CASE("[[1 2] [1 2] 1 2]", u3nt(u3nc(1, 2), u3nc(1, 2), u3nc(1, 2)));
+ }
+
+ {
+ c3_y res_y[6] = { 0xa5, 0x35, 0x19, 0xf3, 0x18, 0x5 };
+ TEST_CASE("[[0 0] [[0 0] 1 1] 1 1]", u3nc(u3nc(0, 0), u3nc(u3nc(u3nc(0, 0), u3nc(1, 1)), u3nc(1, 1))));
+ }
+
+ {
+ c3_y res_y[14] = { 0x15, 0x17, 0xb2, 0xd0, 0x85, 0x59, 0xb8, 0x61, 0x87, 0x5f, 0x10, 0x54, 0x55, 0x5 };
+ TEST_CASE("deep", u3nc(u3nc(u3nc(1, u3nc(u3nc(2, u3nc(u3nc(3, u3nc(u3nc(4, u3nc(u3nt(5, 6, u3nc(7, u3nc(u3nc(8, 0), 0))), 0)), 0)), 0)), 0)), 0), 0));
+ }
+
+ {
+ c3_y inp_y[33] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+ c3_y res_y[35] = { 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 };
+ TEST_CASE("wide", u3i_bytes(sizeof(inp_y), inp_y));
+ }
+
+ {
+ c3_y inp_y[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xa8, 0xab, 0x60, 0xef, 0x2d, 0xd, 0x0, 0x0, 0x80 };
+ c3_y res_y[19] = { 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x50, 0x57, 0xc1, 0xde, 0x5b, 0x1a, 0x0, 0x0, 0x0, 0x1 };
+ TEST_CASE("date", u3i_bytes(sizeof(inp_y), inp_y));
+ }
+
+ {
+ u3_noun a = u3i_string("abcdefjhijklmnopqrstuvwxyz");
+ c3_y res_y[32] = {
+ 0x1, 0xf8, 0xc, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x53, 0x43, 0x4b,
+ 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, 0x83, 0x8b, 0x93, 0x9b, 0xa3,
+ 0xab, 0xb3, 0xbb, 0xc3, 0xcb, 0xd3, 0x87, 0xc, 0x3d, 0x9
+ };
+ TEST_CASE("alpha", u3nq(u3k(a), 2, 3, a));
+ }
+
+ return ret_i;
+}
+
+/* main(): run all test cases.
+*/
+int
+main(int argc, char* argv[])
+{
+ _setup();
+
+ if ( !_test_jam_roundtrip() ) {
+ fprintf(stderr, "test jam: failed\r\n");
+ exit(1);
+ }
+
+ // GC
+ //
+ u3m_grab(u3_none);
+
+ fprintf(stderr, "test jam: ok\r\n");
+ return 0;
+}
diff --git a/vere/pkg/noun/ship.c b/vere/pkg/noun/ship.c
new file mode 100644
index 0000000..6aebff7
--- /dev/null
+++ b/vere/pkg/noun/ship.c
@@ -0,0 +1,109 @@
+#include "c3/c3.h"
+#include "types.h"
+#include "imprison.h"
+#include "retrieve.h"
+#include "vortex.h"
+#include "ship.h"
+
+static inline void
+_s_chub_to_bytes(c3_y byt_y[8], c3_d num_d)
+{
+ byt_y[0] = num_d & 0xff;
+ byt_y[1] = (num_d >> 8) & 0xff;
+ byt_y[2] = (num_d >> 16) & 0xff;
+ byt_y[3] = (num_d >> 24) & 0xff;
+ byt_y[4] = (num_d >> 32) & 0xff;
+ byt_y[5] = (num_d >> 40) & 0xff;
+ byt_y[6] = (num_d >> 48) & 0xff;
+ byt_y[7] = (num_d >> 56) & 0xff;
+}
+
+static inline c3_d
+_s_bytes_to_chub(c3_y byt_y[8])
+{
+ return (c3_d)byt_y[0]
+ | (c3_d)byt_y[1] << 8
+ | (c3_d)byt_y[2] << 16
+ | (c3_d)byt_y[3] << 24
+ | (c3_d)byt_y[4] << 32
+ | (c3_d)byt_y[5] << 40
+ | (c3_d)byt_y[6] << 48
+ | (c3_d)byt_y[7] << 56;
+}
+
+void
+u3_ship_to_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y)
+{
+ c3_y sip_y[16] = {0};
+
+ _s_chub_to_bytes(sip_y, who_u[0]);
+ _s_chub_to_bytes(sip_y + 8, who_u[1]);
+
+ memcpy(buf_y, sip_y, c3_min(16, len_y));
+}
+
+void
+u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y)
+{
+ c3_y sip_y[16] = {0};
+ memcpy(sip_y, buf_y, c3_min(16, len_y));
+
+ who_u[0] = _s_bytes_to_chub(sip_y);
+ who_u[1] = _s_bytes_to_chub(sip_y + 8);
+}
+
+u3_atom
+u3_ship_to_noun(u3_ship who_u)
+{
+ return u3i_chubs(2, who_u);
+}
+
+c3_c*
+u3_ship_to_string(u3_ship who_u)
+{
+ u3_noun ser = u3dc("scot", c3__p, u3_ship_to_noun(who_u));
+ c3_c* who_c = u3r_string(ser);
+ u3z(ser);
+ return who_c;
+}
+
+void
+u3_ship_of_noun(u3_ship who_u, u3_noun who)
+{
+ u3r_chubs(0, 2, who_u, who);
+}
+
+c3_o
+u3_ships_equal(u3_ship sip_u, u3_ship sap_u)
+{
+ return __((sip_u[0] == sap_u[0]) && (sip_u[1] == sap_u[1]));
+}
+
+void
+u3_ship_copy(u3_ship des_u, u3_ship src_u)
+{
+ des_u[0] = src_u[0];
+ des_u[1] = src_u[1];
+}
+
+c3_l
+u3_ship_rank(u3_ship who_u)
+{
+ if ( who_u[1] ) return c3__pawn;
+ else if ( who_u[0] >> 32 ) return c3__earl;
+ else if ( who_u[0] >> 16 ) return c3__duke;
+ else if ( who_u[0] >> 8 ) return c3__king;
+ else return c3__czar;
+}
+
+c3_y
+u3_ship_czar(u3_ship who_u) { return who_u[0] & 0xFF; }
+
+c3_s
+u3_ship_king(u3_ship who_u) { return who_u[0] & 0xffff; }
+
+c3_w
+u3_ship_duke(u3_ship who_u) { return who_u[0] & 0xffffffff; }
+
+c3_d
+u3_ship_earl(u3_ship who_u) { return who_u[0]; }
diff --git a/vere/pkg/noun/ship.h b/vere/pkg/noun/ship.h
new file mode 100644
index 0000000..8104c42
--- /dev/null
+++ b/vere/pkg/noun/ship.h
@@ -0,0 +1,57 @@
+#ifndef U3_SHIP_H
+#define U3_SHIP_H
+
+#include "c3/c3.h"
+#include "types.h"
+
+typedef c3_d u3_ship[2];
+
+void
+u3_ship_to_bytes(c3_d sip_d[2], c3_y len_y, c3_y* buf_y);
+
+void
+u3_ship_of_bytes(u3_ship who_u, c3_y len_y, c3_y* buf_y);
+
+u3_atom
+u3_ship_to_noun(u3_ship who_u);
+
+void
+u3_ship_of_noun(u3_ship who_u, u3_noun who);
+
+c3_c*
+u3_ship_to_string(u3_ship who_u);
+
+c3_o
+u3_ships_equal(u3_ship sip_u, u3_ship sap_u);
+
+c3_l
+u3_ship_rank(u3_ship who_u);
+
+void
+u3_ship_copy(u3_ship des_u, u3_ship src_u);
+
+/**
+* Returns a ship's galaxy byte prefix.
+*/
+c3_y
+u3_ship_czar(u3_ship who_u);
+
+/**
+* Returns a ship's star prefix.
+*/
+c3_s
+u3_ship_king(u3_ship who_u);
+
+/**
+* Returns a ship's planet prefix.
+*/
+c3_w
+u3_ship_duke(u3_ship who_u);
+
+/**
+* Returns a ship's moon prefix.
+*/
+c3_d
+u3_ship_earl(u3_ship who_u);
+
+#endif /* ifndef U3_SHIP_H */
diff --git a/vere/pkg/noun/trace.c b/vere/pkg/noun/trace.c
new file mode 100644
index 0000000..8ddbf2e
--- /dev/null
+++ b/vere/pkg/noun/trace.c
@@ -0,0 +1,1242 @@
+/// @file
+
+#include "trace.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+
+#include "allocate.h"
+#include "imprison.h"
+#include "jets/k.h"
+#include "log.h"
+#include "manage.h"
+#include "options.h"
+#include "retrieve.h"
+#include "vortex.h"
+
+/** Global variables.
+**/
+u3t_spin *stk_u;
+u3t_trace u3t_Trace;
+
+static c3_o _ct_lop_o;
+
+/// Nock PID.
+static c3_ws _nock_pid_i = 0;
+
+/// JSON trace file.
+static FILE* _file_u = NULL;
+
+/// Trace counter. Tracks the number of entries written to the JSON trace file.
+static c3_w _trace_cnt_w = 0;
+
+/// File counter. Tracks the number of times u3t_trace_close() has been called.
+static c3_w _file_cnt_w = 0;
+
+/* u3t_push(): push on trace stack.
+*/
+void
+u3t_push(u3_noun mon)
+{
+ u3R->bug.tax = u3nc(mon, u3R->bug.tax);
+}
+
+/* u3t_mean(): push `[%mean roc]` on trace stack.
+*/
+void
+u3t_mean(u3_noun roc)
+{
+ u3R->bug.tax = u3nc(u3nc(c3__mean, roc), u3R->bug.tax);
+}
+
+/* u3t_drop(): drop from meaning stack.
+*/
+void
+u3t_drop(void)
+{
+ u3_assert(_(u3du(u3R->bug.tax)));
+ {
+ u3_noun tax = u3R->bug.tax;
+
+ u3R->bug.tax = u3k(u3t(tax));
+ u3z(tax);
+ }
+}
+
+/* u3t_slog(): print directly.
+*/
+void
+u3t_slog(u3_noun hod)
+{
+ if ( 0 != u3C.slog_f ) {
+ u3C.slog_f(hod);
+ }
+ else {
+ u3z(hod);
+ }
+}
+
+/* u3t_heck(): profile point.
+*/
+void
+u3t_heck(u3_atom cog)
+{
+#if 0
+ u3R->pro.cel_d++;
+#else
+ c3_w len_w = u3r_met(3, cog);
+ c3_c* str_c = alloca(1 + len_w);
+
+ u3r_bytes(0, len_w, (c3_y *)str_c, cog);
+ str_c[len_w] = 0;
+
+ // Profile sampling, because it allocates on the home road,
+ // only works on when we're not at home.
+ //
+ if ( &(u3H->rod_u) != u3R ) {
+ u3a_road* rod_u;
+
+ rod_u = u3R;
+ u3R = &(u3H->rod_u);
+ {
+ if ( 0 == u3R->pro.day ) {
+ u3R->pro.day = u3do("doss", 0);
+ }
+ u3R->pro.day = u3dc("pi-heck", u3i_string(str_c), u3R->pro.day);
+ }
+ u3R = rod_u;
+ }
+#endif
+}
+
+#if 0
+static void
+_ct_sane(u3_noun lab)
+{
+ if ( u3_nul != lab ) {
+ u3_assert(c3y == u3du(lab));
+ u3_assert(c3y == u3ud(u3h(lab)));
+ _ct_sane(u3t(lab));
+ }
+}
+#endif
+
+#if 1
+/* _t_samp_process(): process raw sample data from live road.
+*/
+static u3_noun
+_t_samp_process(u3_road* rod_u)
+{
+ u3_noun pef = u3_nul; // (list (pair path (map path ,@ud)))
+ u3_noun muf = u3_nul; // (map path ,@ud)
+ c3_w len_w = 0;
+
+ // Accumulate a label/map stack which collapses recursive segments.
+ //
+ while ( rod_u ) {
+ u3_noun don = rod_u->pro.don;
+
+ while ( u3_nul != don ) {
+ // Get surface allocated label
+ //
+ // u3_noun lab = u3nc(u3i_string("foobar"), 0);
+ u3_noun laj = u3h(don),
+ lab = u3a_take(laj);
+ u3a_wash(laj);
+
+ // Add the label to the traced label stack, trimming recursion.
+ //
+ {
+ u3_noun old;
+
+ if ( u3_none == (old = u3kdb_get(u3k(muf), u3k(lab))) ) {
+ muf = u3kdb_put(muf, u3k(lab), len_w);
+ pef = u3nc(u3nc(lab, u3k(muf)), pef);
+ len_w += 1;
+ }
+ else {
+ if ( !_(u3a_is_cat(old)) ) {
+ u3m_bail(c3__fail);
+ }
+
+ u3z(muf);
+ while ( len_w > (old + 1) ) {
+ u3_noun t_pef = u3k(u3t(pef));
+
+ len_w -= 1;
+ u3z(pef);
+ pef = t_pef;
+ }
+ muf = u3k(u3t(u3h(pef)));
+ u3z(lab);
+ }
+ }
+ don = u3t(don);
+ }
+ rod_u = u3tn(u3_road, rod_u->par_p);
+ }
+ u3z(muf);
+
+ // Lose the maps and save a pure label stack in original order.
+ //
+ {
+ u3_noun pal = u3_nul;
+
+ while ( u3_nul != pef ) {
+ u3_noun h_pef = u3h(pef);
+ u3_noun t_pef = u3k(u3t(pef));
+
+ pal = u3nc(u3k(u3h(h_pef)), pal);
+
+ u3z(pef);
+ pef = t_pef;
+ }
+
+ // u3l_log("sample: stack length %d", u3kb_lent(u3k(pal)));
+ return pal;
+ }
+}
+#endif
+
+/* u3t_samp(): sample.
+*/
+void
+u3t_samp(void)
+{
+ if ( c3y == _ct_lop_o ) {
+ // _ct_lop_o here is a mutex for modifying pro.don. we
+ // do not want to sample in the middle of doing that, as
+ // it can cause memory errors.
+ return;
+ }
+
+ c3_w old_wag = u3C.wag_w;
+ u3C.wag_w &= ~u3o_debug_cpu;
+ u3C.wag_w &= ~u3o_trace;
+
+ // Profile sampling, because it allocates on the home road,
+ // only works on when we're not at home.
+ //
+ if ( &(u3H->rod_u) != u3R ) {
+ c3_l mot_l;
+ u3a_road* rod_u;
+
+ if ( _(u3T.mal_o) ) {
+ mot_l = c3_s3('m','a','l');
+ }
+ else if ( _(u3T.coy_o) ) {
+ mot_l = c3_s3('c','o','y');
+ }
+ else if ( _(u3T.euq_o) ) {
+ mot_l = c3_s3('e','u','q');
+ }
+ else if ( _(u3T.far_o) ) {
+ mot_l = c3_s3('f','a','r');
+ }
+ else if ( _(u3T.noc_o) ) {
+ u3_assert(!_(u3T.glu_o));
+ mot_l = c3_s3('n','o','c');
+ }
+ else if ( _(u3T.glu_o) ) {
+ mot_l = c3_s3('g','l','u');
+ }
+ else {
+ mot_l = c3_s3('f','u','n');
+ }
+
+ rod_u = u3R;
+ u3R = &(u3H->rod_u);
+ {
+ u3_noun lab = _t_samp_process(rod_u);
+
+ u3_assert(u3R == &u3H->rod_u);
+ if ( 0 == u3R->pro.day ) {
+ /* bunt a +doss
+ */
+ u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0);
+ }
+ u3R->pro.day = u3dt("pi-noon", mot_l, lab, u3R->pro.day);
+ }
+ u3R = rod_u;
+ }
+ u3C.wag_w = old_wag;
+}
+
+/* u3t_come(): push on profile stack; return yes if active push. RETAIN.
+*/
+c3_o
+u3t_come(u3_noun lab)
+{
+ if ( (u3_nul == u3R->pro.don) || !_(u3r_sing(lab, u3h(u3R->pro.don))) ) {
+ u3a_gain(lab);
+ _ct_lop_o = c3y;
+ u3R->pro.don = u3nc(lab, u3R->pro.don);
+ _ct_lop_o = c3n;
+ return c3y;
+ }
+ else return c3n;
+}
+
+/* u3t_flee(): pop off profile stack.
+*/
+void
+u3t_flee(void)
+{
+ _ct_lop_o = c3y;
+ u3_noun don = u3R->pro.don;
+ u3R->pro.don = u3k(u3t(don));
+ _ct_lop_o = c3n;
+ u3z(don);
+}
+
+/* u3t_trace_open(): opens a trace file and writes the preamble.
+*/
+void
+u3t_trace_open(const c3_c* dir_c)
+{
+ c3_c fil_c[2048];
+
+ if ( !dir_c ) {
+ return;
+ }
+
+ snprintf(fil_c, 2048, "%s/.urb/put/trace", dir_c);
+
+ struct stat st;
+ if ( (-1 == stat(fil_c, &st))
+ && (-1 == c3_mkdir(fil_c, 0700)) )
+ {
+ fprintf(stderr, "mkdir: %s failed: %s\r\n", fil_c, strerror(errno));
+ return;
+ }
+
+ c3_c lif_c[2056];
+ snprintf(lif_c, 2056, "%s/%d.json", fil_c, _file_cnt_w);
+
+ _file_u = c3_fopen(lif_c, "w");
+ _nock_pid_i = (int)getpid();
+
+ if ( !_file_u ) {
+ fprintf(stderr, "trace open: %s\r\n", strerror(errno));
+ return;
+ }
+
+ fprintf(_file_u, "[ ");
+
+ // We have two "threads", the event processing and the nock stuff.
+ // tid 1 = event processing
+ // tid 2 = nock processing
+ fprintf(_file_u,
+ "{\"name\": \"process_name\", \"ph\": \"M\", \"pid\": %d, \"args\": "
+ "{\"name\": \"urbit\"}},\n",
+ _nock_pid_i);
+ fprintf(_file_u,
+ "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 1, "
+ "\"args\": {\"name\": \"Event Processing\"}},\n",
+ _nock_pid_i);
+ fprintf(_file_u,
+ "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, "
+ "\"tid\": 1, \"args\": {\"sort_index\": 1}},\n",
+ _nock_pid_i);
+ fprintf(_file_u,
+ "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 2, "
+ "\"args\": {\"name\": \"Nock\"}},\n",
+ _nock_pid_i);
+ fprintf(_file_u,
+ "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, "
+ "\"tid\": 2, \"args\": {\"sort_index\": 2}},\n",
+ _nock_pid_i);
+ _trace_cnt_w = 5;
+}
+
+/* u3t_trace_close(): closes a trace file. optional.
+*/
+void
+u3t_trace_close(void)
+{
+ if ( !_file_u )
+ return;
+
+ // We don't terminate the JSON because of the file format.
+ fclose(_file_u);
+ _trace_cnt_w = 0;
+ _file_cnt_w++;
+}
+
+/* u3t_trace_time(): microsecond clock
+*/
+c3_d u3t_trace_time(void)
+{
+ struct timeval tim_tv;
+ gettimeofday(&tim_tv, 0);
+ return 1000000ULL * tim_tv.tv_sec + tim_tv.tv_usec;
+}
+
+/* u3t_nock_trace_push(): push a trace onto the trace stack; returns yes if pushed.
+ *
+ * The trace stack is a stack of [path time-entered].
+ */
+c3_o
+u3t_nock_trace_push(u3_noun lab)
+{
+ if ( !_file_u )
+ return c3n;
+
+ if ( (u3_nul == u3R->pro.trace) ||
+ !_(u3r_sing(lab, u3h(u3h(u3R->pro.trace)))) ) {
+ u3a_gain(lab);
+ c3_d time = u3t_trace_time();
+ u3R->pro.trace = u3nc(u3nc(lab, u3i_chubs(1, &time)), u3R->pro.trace);
+ return c3y;
+ }
+ else {
+ return c3n;
+ }
+}
+
+/* u3t_nock_trace_pop(): pops a trace from the trace stack.
+ *
+ * When we remove the trace from the stack, we check to see if the sample is
+ * large enough to process, as we'll otherwise keep track of individual +add
+ * calls. If it is, we write it out to the tracefile.
+ */
+void
+u3t_nock_trace_pop(void)
+{
+ if ( !_file_u )
+ return;
+
+ u3_noun trace = u3R->pro.trace;
+ u3R->pro.trace = u3k(u3t(trace));
+
+ u3_noun item = u3h(trace);
+ u3_noun lab = u3h(item);
+ c3_d start_time = u3r_chub(0, u3t(item));
+
+ // 33microseconds (a 30th of a millisecond).
+ c3_d duration = u3t_trace_time() - start_time;
+ if (duration > 33) {
+ c3_c* name = u3m_pretty_path(lab);
+
+ fprintf(_file_u,
+ "{\"cat\": \"nock\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, "
+ "\"tid\": 2, \"ts\": %" PRIu64 ", \"dur\": %" PRIu64 "}, \n",
+ name,
+ 'X',
+ _nock_pid_i,
+ start_time,
+ duration);
+
+ c3_free(name);
+ _trace_cnt_w++;
+ }
+
+ u3z(trace);
+}
+
+/* u3t_event_trace(): dumps a simple event from outside nock.
+*/
+void
+u3t_event_trace(const c3_c* name, c3_c type)
+{
+ if ( !_file_u )
+ return;
+
+ fprintf(_file_u,
+ "{\"cat\": \"event\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, "
+ "\"tid\": 1, \"ts\": %" PRIu64 ", \"id\": \"0x100\"}, \n",
+ name,
+ type,
+ _nock_pid_i,
+ u3t_trace_time());
+ _trace_cnt_w++;
+}
+
+/* u3t_print_steps: print step counter.
+*/
+void
+u3t_print_steps(FILE* fil_u, c3_c* cap_c, c3_d sep_d)
+{
+ u3_assert( 0 != fil_u );
+
+ c3_w gib_w = (sep_d / 1000000000ULL);
+ c3_w mib_w = (sep_d % 1000000000ULL) / 1000000ULL;
+ c3_w kib_w = (sep_d % 1000000ULL) / 1000ULL;
+ c3_w bib_w = (sep_d % 1000ULL);
+
+ // XX prints to stderr since it's called on shutdown, daemon may be gone
+ //
+ if ( sep_d ) {
+ if ( gib_w ) {
+ fprintf(fil_u, "%s: G/%d.%03d.%03d.%03d\r\n",
+ cap_c, gib_w, mib_w, kib_w, bib_w);
+ }
+ else if ( mib_w ) {
+ fprintf(fil_u, "%s: M/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w);
+ }
+ else if ( kib_w ) {
+ fprintf(fil_u, "%s: K/%d.%03d\r\n", cap_c, kib_w, bib_w);
+ }
+ else if ( bib_w ) {
+ fprintf(fil_u, "%s: %d\r\n", cap_c, bib_w);
+ }
+ }
+}
+
+/* u3t_damp(): print and clear profile data.
+*/
+void
+u3t_damp(FILE* fil_u)
+{
+ u3_assert( 0 != fil_u );
+
+ if ( 0 != u3R->pro.day ) {
+ u3_noun wol = u3do("pi-tell", u3R->pro.day);
+
+ // XX prints to stderr since it's called on shutdown, daemon may be gone
+ //
+ {
+ u3_noun low = wol;
+
+ while ( u3_nul != low ) {
+ c3_c* str_c = (c3_c*)u3r_tape(u3h(low));
+ fputs(str_c, fil_u);
+ fputs("\r\n", fil_u);
+
+ c3_free(str_c);
+ low = u3t(low);
+ }
+
+ u3z(wol);
+ }
+
+ /* bunt a +doss
+ */
+ u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0);
+ }
+
+ u3t_print_steps(fil_u, "nocks", u3R->pro.nox_d);
+ u3t_print_steps(fil_u, "cells", u3R->pro.cel_d);
+
+ u3R->pro.nox_d = 0;
+ u3R->pro.cel_d = 0;
+}
+
+/* _ct_sigaction(): profile sigaction callback.
+*/
+void _ct_sigaction(c3_i x_i)
+{
+ u3t_samp();
+}
+
+/* u3t_init(): initialize tracing layer.
+*/
+void
+u3t_init(void)
+{
+ u3T.noc_o = c3n;
+ u3T.glu_o = c3n;
+ u3T.mal_o = c3n;
+ u3T.far_o = c3n;
+ u3T.coy_o = c3n;
+ u3T.euq_o = c3n;
+}
+
+c3_w
+u3t_trace_cnt(void)
+{
+ return _trace_cnt_w;
+}
+
+c3_w
+u3t_file_cnt(void)
+{
+ return _file_cnt_w;
+}
+
+/* u3t_boot(): turn sampling on.
+*/
+void
+u3t_boot(void)
+{
+#ifndef U3_OS_windows
+ if ( u3C.wag_w & u3o_debug_cpu ) {
+ _ct_lop_o = c3n;
+#if defined(U3_OS_PROF)
+ // skip profiling if we don't yet have an arvo kernel
+ //
+ if ( 0 == u3A->roc ) {
+ return;
+ }
+
+ // Register _ct_sigaction to be called on `SIGPROF`.
+ {
+ struct sigaction sig_s = {{0}};
+ sig_s.sa_handler = _ct_sigaction;
+ sigemptyset(&(sig_s.sa_mask));
+ sigaction(SIGPROF, &sig_s, 0);
+ }
+
+ // Unblock `SIGPROF` for this thread (we will block it again when `u3t_boff` is called).
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGPROF);
+ if ( 0 != pthread_sigmask(SIG_UNBLOCK, &set, NULL) ) {
+ u3l_log("trace: thread mask SIGPROF: %s", strerror(errno));
+ }
+ }
+
+ // Ask for SIGPROF to be sent every 10ms.
+ {
+ struct itimerval itm_v = {{0}};
+ itm_v.it_interval.tv_usec = 10000;
+ itm_v.it_value = itm_v.it_interval;
+ setitimer(ITIMER_PROF, &itm_v, 0);
+ }
+#endif
+ }
+#endif
+}
+
+/* u3t_boff(): turn profile sampling off.
+*/
+void
+u3t_boff(void)
+{
+#ifndef U3_OS_windows
+ if ( u3C.wag_w & u3o_debug_cpu ) {
+#if defined(U3_OS_PROF)
+ // Mask SIGPROF signals in this thread (and this is the only
+ // thread that unblocked them).
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGPROF);
+ if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) {
+ u3l_log("trace: thread mask SIGPROF: %s", strerror(errno));
+ }
+ }
+
+ // Disable the SIGPROF timer.
+ {
+ struct itimerval itm_v = {{0}};
+ setitimer(ITIMER_PROF, &itm_v, 0);
+ }
+
+ // Ignore SIGPROF signals.
+ {
+ struct sigaction sig_s = {{0}};
+ sigemptyset(&(sig_s.sa_mask));
+ sig_s.sa_handler = SIG_IGN;
+ sigaction(SIGPROF, &sig_s, 0);
+ }
+#endif
+ }
+#endif
+}
+
+
+/* u3t_slog_cap(): slog a tank with a caption with
+** a given priority c3_l (assumed 0-3).
+*/
+void
+u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan)
+{
+ u3t_slog(
+ u3nc(
+ pri_l,
+ u3nt(
+ c3__rose,
+ u3nt(u3nt(':', ' ', u3_nul), u3_nul, u3_nul),
+ u3nt(cap, tan, u3_nul)
+ )
+ )
+ );
+}
+
+
+/* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax
+** flop the order into start-to-end, render, and slog each item
+** until done.
+*/
+void
+u3t_slog_trace(c3_l pri_l, u3_noun tax)
+{
+ // render the stack
+ // Note: ton is a reference to a data struct
+ // we have just allocated
+ // lit is used as a moving cursor pointer through
+ // that allocated struct
+ // once we finish lit will be null, but ton will still
+ // point to the whole valid allocated data structure
+ // and thus we can free it safely at the end of the func
+ // to clean up after ourselves.
+ // Note: flop reverses the stack trace list 'tax'
+ u3_noun ton = u3dc("mook", 2, u3kb_flop(tax));
+ u3_noun lit = u3t(ton);
+
+ // print the stack one stack item at a time
+ while ( u3_nul != lit ) {
+ u3t_slog(u3nc(pri_l, u3k(u3h(lit)) ));
+ lit = u3t(lit);
+ }
+
+ u3z(ton);
+}
+
+
+/* u3t_slog_nara(): slog only the deepest road's trace with
+** c3_l priority pri
+*/
+void
+u3t_slog_nara(c3_l pri_l)
+{
+ u3_noun tax = u3k(u3R->bug.tax);
+ u3t_slog_trace(pri_l, tax);
+}
+
+
+/* u3t_slog_hela(): join all roads' traces together into one tax
+** and pass it to slog_trace along with the given c3_l priority pri_l
+*/
+void
+u3t_slog_hela(c3_l pri_l)
+{
+ // rod_u protects us from mutating the global state
+ u3_road* rod_u = u3R;
+
+ // inits to the the current road's trace
+ u3_noun tax = u3k(rod_u->bug.tax);
+
+ // while there is a parent road ref ...
+ while ( &(u3H->rod_u) != rod_u ) {
+ // ... point at the next road and append its stack to tax
+ rod_u = u3tn(u3_road, rod_u->par_p);
+ tax = u3kb_weld(tax, u3k(rod_u->bug.tax));
+ }
+
+ u3t_slog_trace(pri_l, tax);
+}
+
+/* _ct_roundf(): truncate a float to precision equivalent to %.2f */
+static float
+_ct_roundf(float per_f)
+{
+ // scale the percentage so that all siginificant digits
+ // would be retained when truncted to an int, then add 0.5
+ // to account for rounding without using round or roundf
+ float big_f = (per_f*10000)+0.5;
+ // truncate to int
+ c3_w big_w = (c3_w) big_f;
+ // convert to float and scale down such that
+ // our last two digits are right of the decimal
+ float tuc_f = (float) big_w/100.0;
+ return tuc_f;
+}
+
+/* _ct_meme_percent(): convert two ints into a percentage */
+static float
+_ct_meme_percent(c3_w lit_w, c3_w big_w)
+{
+ // get the percentage of our inputs as a float
+ float raw_f = (float) lit_w/big_w;
+ return _ct_roundf(raw_f);
+}
+
+/* _ct_all_heap_size(): return the size in bytes of ALL space on the Loom
+** over all roads, currently in use as heap.
+*/
+static c3_w
+_ct_all_heap_size(u3_road* r) {
+ if (r == &(u3H->rod_u)) {
+ return u3a_heap(r)*4;
+ } else {
+ // recurse
+ return (u3a_heap(r)*4) + _ct_all_heap_size(u3tn(u3_road, r->par_p));
+ }
+}
+
+/* These two structs, bar_item and bar_info, store the mutable data
+** to normalize measured Loom usage values into ints that will fit
+** into a fixed width ascii bar chart.
+*/
+struct
+bar_item {
+ // index
+ c3_w dex_w;
+ // lower bound
+ c3_w low_w;
+ // original value
+ float ori_f;
+ // difference
+ float dif_f;
+};
+
+struct
+bar_info {
+ struct bar_item s[6];
+};
+
+/* _ct_boost_small(): we want zero to be zero,
+** anything between zero and one to be one,
+** and all else to be whatever it is.
+*/
+static float
+_ct_boost_small(float num_f)
+{
+ return
+ 0.0 >= num_f ? 0.0:
+ 1.0 > num_f ? 1.0:
+ num_f;
+}
+
+/* _ct_global_difference(): each low_w represents the normalized integer value
+ * of its loom item, and ideally the sum of all loom low_w
+ * values should be 100. This function reports how far from
+ * the ideal bar_u is.
+*/
+static c3_ws
+_ct_global_difference(struct bar_info bar_u)
+{
+ c3_w low_w = 0;
+ for (c3_w i=0; i < 6; i++) {
+ low_w += bar_u.s[i].low_w;
+ }
+ return 100 - low_w;
+}
+
+/* _ct_compute_roundoff_error(): for each loom item in bar_u
+** compute the current difference between the int
+** size and the original float size.
+*/
+static struct bar_info
+_ct_compute_roundoff_error(struct bar_info bar_u)
+{
+ for (c3_w i=0; i < 6; i++) {
+ bar_u.s[i].dif_f = bar_u.s[i].ori_f - bar_u.s[i].low_w;
+ }
+ return bar_u;
+}
+
+/* _ct_sort_by_roundoff_error(): sort loom items from most mis-sized to least */
+static struct bar_info
+_ct_sort_by_roundoff_error(struct bar_info bar_u)
+{
+ struct bar_item tem_u;
+ for (c3_w i=1; i < 6; i++) {
+ for (c3_w j=0; j < 6-i; j++) {
+ if (bar_u.s[j+1].dif_f > bar_u.s[j].dif_f) {
+ tem_u = bar_u.s[j];
+ bar_u.s[j] = bar_u.s[j+1];
+ bar_u.s[j+1] = tem_u;
+ }
+ }
+ }
+ return bar_u;
+}
+
+/* _ct_sort_by_index(): sort loom items into loom order */
+static struct bar_info
+_ct_sort_by_index(struct bar_info bar_u)
+{
+ struct bar_item tem_u;
+ for (c3_w i=1; i < 6; i++) {
+ for (c3_w j=0; j < 6-i; j++) {
+ if (bar_u.s[j+1].dex_w < bar_u.s[j].dex_w) {
+ tem_u = bar_u.s[j];
+ bar_u.s[j] = bar_u.s[j+1];
+ bar_u.s[j+1] = tem_u;
+ }
+ }
+ }
+ return bar_u;
+}
+
+/* _ct_reduce_error(): reduce error by one int step
+ * making oversized things a bit smaller
+ * and undersized things a bit bigger
+*/
+static struct bar_info
+_ct_reduce_error(struct bar_info bar_u, c3_ws dif_s)
+{
+ for (c3_w i=0; i < 6; i++) {
+ if (bar_u.s[i].low_w == 0) continue;
+ if (bar_u.s[i].low_w == 1) continue;
+ if (dif_s > 0) {
+ bar_u.s[i].low_w++;
+ dif_s--;
+ }
+ if (dif_s < 0) {
+ bar_u.s[i].low_w--;
+ dif_s++;
+ }
+ }
+ return bar_u;
+}
+
+/* _ct_report_bargraph(): render all six raw loom elements into a fixed-size ascii bargraph */
+static void
+_ct_report_bargraph(
+ c3_c bar_c[105], float hip_f, float hep_f, float fre_f, float pen_f, float tak_f, float tik_f
+)
+{
+ float in[6];
+ in[0] = _ct_boost_small(hip_f);
+ in[1] = _ct_boost_small(hep_f);
+ in[2] = _ct_boost_small(fre_f);
+ in[3] = _ct_boost_small(pen_f);
+ in[4] = _ct_boost_small(tak_f);
+ in[5] = _ct_boost_small(tik_f);
+
+ // init the list of structs
+ struct bar_info bar_u;
+ for (c3_w i=0; i < 6; i++) {
+ bar_u.s[i].dex_w = i;
+ bar_u.s[i].ori_f = in[i];
+ bar_u.s[i].low_w = (c3_w) bar_u.s[i].ori_f;
+ }
+
+ // repeatedly adjust for roundoff error
+ // until it is elemenated or we go 100 cycles
+ c3_ws dif_s = 0;
+ for (c3_w x=0; x<100; x++) {
+ bar_u = _ct_compute_roundoff_error(bar_u);
+ dif_s = _ct_global_difference(bar_u);
+ if (dif_s == 0) break;
+ bar_u = _ct_sort_by_roundoff_error(bar_u);
+ bar_u = _ct_reduce_error(bar_u, dif_s);
+ }
+ bar_u = _ct_sort_by_index(bar_u);
+
+ for (c3_w x=1; x<104; x++) {
+ bar_c[x] = ' ';
+ }
+ bar_c[0] = '[';
+
+ // create our bar chart
+ const c3_c sym_c[6] = "=-%#+~";
+ c3_w x = 0, y = 0;
+ for (c3_w i=0; i < 6; i++) {
+ x++;
+ for (c3_w j=0; j < bar_u.s[i].low_w; j++) {
+ bar_c[x+j] = sym_c[i];
+ y = x+j;
+ }
+ if (y > 0) x = y;
+ }
+ bar_c[101] = ']';
+ bar_c[102] = 0;
+}
+
+/* _ct_size_prefix(): return the correct metric scalar prifix for a given int */
+static c3_c
+_ct_size_prefix(c3_d num_d)
+{
+ return
+ (num_d / 1000000000) ? 'G':
+ (num_d % 1000000000) / 1000000 ? 'M':
+ (num_d % 1000000) / 1000 ? 'K':
+ (num_d % 1000) ? ' ':
+ 'X';
+}
+
+/* _ct_report_string(): convert a int into a string, adding a metric scale prefix letter*/
+static void
+_ct_report_string(c3_c rep_c[32], c3_d num_d)
+{
+ memset(rep_c, ' ', 31);
+
+ // add the G/M/K prefix
+ rep_c[24] = _ct_size_prefix(num_d);
+ // consume wor_w into a string one base-10 digit at a time
+ // including dot formatting
+ c3_w i = 0, j = 0;
+ while (num_d > 0) {
+ if (j == 3) {
+ rep_c[22-i] = '.';
+ i++;
+ j = 0;
+ } else {
+ rep_c[22-i] = (num_d%10)+'0';
+ num_d /= 10;
+ i++;
+ j++;
+ }
+ }
+}
+
+/* _ct_etch_road_depth(): return a the current road depth as a fixed size string */
+static void
+ _ct_etch_road_depth(c3_c rep_c[32], u3_road* r, c3_w num_w) {
+ if (r == &(u3H->rod_u)) {
+ _ct_report_string(rep_c, num_w);
+ // this will be incorrectly indented, so we fix that here
+ c3_w i = 14;
+ while (i > 0) {
+ rep_c[i] = rep_c[i+16];
+ rep_c[i+16] = ' ';
+ i--;
+ }
+ } else {
+ _ct_etch_road_depth(rep_c, u3tn(u3_road, r->par_p), ++num_w);
+ }
+}
+
+/* _ct_etch_memory(): create a single line report of a given captioned item
+ * with a percentage of space used and the bytes used
+ * scaled by a metric scaling postfix (ie MB, GB, etc)
+*/
+static void
+_ct_etch_memory(c3_c rep_c[32], float per_f, c3_w num_w)
+{
+ // create the basic report string
+ _ct_report_string(rep_c, num_w);
+ // add the Bytes postfix to the size report
+ rep_c[25] = 'B';
+
+ // add the space-percentage into the report
+ rep_c[2] = '0', rep_c[3] = '.', rep_c[4] = '0', rep_c[5] = '0';
+ c3_w per_i = (c3_w) (per_f*100);
+ c3_w i = 0;
+ while (per_i > 0 && i < 6) {
+ if (i != 2) {
+ rep_c[5-i] = (per_i%10)+'0';
+ per_i /= 10;
+ }
+ i++;
+ }
+ // add the percent sign
+ rep_c[6] = '%';
+}
+
+/* _ct_etch_steps(): create a single line report of a given captioned item
+** scaled by a metric scaling postfix, but unitless.
+*/
+static void
+_ct_etch_steps(c3_c rep_c[32], c3_d sep_d)
+{
+ _ct_report_string(rep_c, sep_d);
+}
+
+/* u3t_etch_meme(): report memory stats at call time */
+u3_noun
+u3t_etch_meme(c3_l mod_l)
+{
+ u3a_road* lum_r;
+ lum_r = &(u3H->rod_u);
+ // this will need to switch to c3_d when we go to a 64 loom
+ c3_w top_w = u3a_full(lum_r)*4,
+ ful_w = u3a_full(u3R)*4,
+ fre_w = u3a_idle(u3R)*4,
+ tak_w = u3a_temp(u3R)*4,
+ hap_w = u3a_heap(u3R)*4,
+ pen_w = u3a_open(u3R)*4;
+
+ c3_w imu_w = top_w-ful_w;
+ c3_w hep_w = hap_w-fre_w;
+
+
+ float hep_f = _ct_meme_percent(hep_w, top_w),
+ fre_f = _ct_meme_percent(fre_w, top_w),
+ pen_f = _ct_meme_percent(pen_w, top_w),
+ tak_f = _ct_meme_percent(tak_w, top_w);
+ float ful_f = hep_f + fre_f + pen_f + tak_f;
+
+ c3_w hip_w = _ct_all_heap_size(u3R) - hap_w;
+ c3_w tik_w = imu_w - hip_w;
+ float hip_f = _ct_meme_percent(hip_w, top_w),
+ tik_f = _ct_meme_percent(tik_w, top_w);
+
+#ifdef U3_CPU_DEBUG
+ /* iff we are using CPU_DEBUG env var
+ ** we can report more facts:
+ ** max_w: max allocated on the current road (not global, not including child roads)
+ ** cel_d: max cells allocated in current road (inc closed kids, but not parents)
+ ** nox_d: nock steps performed in current road
+ */
+ c3_w max_w = (u3R->all.max_w*4)+imu_w;
+ float max_f = _ct_meme_percent(max_w, top_w);
+ c3_d cel_d = u3R->pro.cel_d;
+ c3_d nox_d = u3R->pro.nox_d;
+ // iff we have a max_f we will render it into the bar graph
+ // in other words iff we have max_f it will always replace something
+ c3_w inc_w = (max_f > hip_f+1.0) ? (c3_w) max_f+0.5 : (c3_w) hip_f+1.5;
+#endif
+
+ // warn if any sanity checks have failed
+ if (100.01 < (hip_f + hep_f + fre_f + pen_f + tak_f + tik_f))
+ u3t_slog_cap(2, u3i_string("warning"), u3i_string("loom sums over 100.01%"));
+ if ( 99.99 > (hip_f + hep_f + fre_f + pen_f + tak_f + tik_f))
+ u3t_slog_cap(2, u3i_string("warning"), u3i_string("loom sums under 99.99%"));
+
+ c3_c bar_c[105];
+ bar_c[0] = 0;
+ _ct_report_bargraph(bar_c, hip_f, hep_f, fre_f, pen_f, tak_f, tik_f);
+
+ c3_w dol = (c3_w) _ct_roundf(hip_f/100);
+ bar_c[dol] = '$';
+#ifdef U3_CPU_DEBUG
+ if (max_f > 0.0) {
+ bar_c[inc_w] = '|';
+ }
+#endif
+
+ c3_c dir_n[8];
+ dir_n[0] = 0;
+ if ( u3a_is_north(u3R) == c3y ) {
+ strcat(dir_n, " North");
+ } else {
+ strcat(dir_n, " South");
+ }
+
+ if (mod_l == 0) {
+ return u3i_string(bar_c);
+ }
+ else {
+ c3_c rep_c[32];
+ rep_c[31] = 0;
+ c3_c str_c[1024];
+ str_c[0] = 0;
+ // each report line is at most 54 chars long
+ strcat(str_c, "Legend | Report:");
+
+ strcat(str_c, "\n loom: "); _ct_etch_memory(rep_c, 100.0, top_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n road: "); _ct_etch_memory(rep_c, ful_f, ful_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n");
+ strcat(str_c, "\n = immutable heap: "); _ct_etch_memory(rep_c, hip_f, hip_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n - solid heap: "); _ct_etch_memory(rep_c, hep_f, hep_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n % freed heap: "); _ct_etch_memory(rep_c, fre_f, fre_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n # open space: "); _ct_etch_memory(rep_c, pen_f, pen_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n + stack: "); _ct_etch_memory(rep_c, tak_f, tak_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n ~ immutable stack: "); _ct_etch_memory(rep_c, tik_f, tik_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n");
+ strcat(str_c, "\n $ allocation frame: "); _ct_etch_memory(rep_c, hip_f, hip_w); strcat(str_c, rep_c);
+#ifdef U3_CPU_DEBUG
+ strcat(str_c, "\n | road max memory: "); _ct_etch_memory(rep_c, max_f, max_w); strcat(str_c, rep_c);
+ strcat(str_c, "\n");
+ strcat(str_c, "\n road cells made: "); _ct_etch_steps(rep_c, cel_d); strcat(str_c, rep_c);
+ strcat(str_c, "\n road nocks made: "); _ct_etch_steps(rep_c, nox_d); strcat(str_c, rep_c);
+#endif
+ strcat(str_c, "\n road direction: "); strcat(str_c, dir_n);
+ strcat(str_c, "\n road depth: "); _ct_etch_road_depth(rep_c, u3R, 1); strcat(str_c, rep_c);
+ strcat(str_c, "\n\nLoom: "); strcat(str_c, bar_c);
+ return u3i_string(str_c);
+ }
+}
+
+/* u3t_sstack_init: initalize a root node on the spin stack
+*/
+void
+u3t_sstack_init()
+{
+#ifndef U3_OS_windows
+ c3_c shm_name[256];
+ snprintf(shm_name, sizeof(shm_name), SLOW_STACK_NAME, getppid());
+ c3_w shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
+ if ( -1 == shm_fd) {
+ perror("shm_open failed");
+ return;
+ }
+
+ if ( -1 == ftruncate(shm_fd, TRACE_PSIZE)) {
+ perror("truncate failed");
+ return;
+ }
+
+ stk_u = mmap(NULL, TRACE_PSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+ if ( MAP_FAILED == stk_u ) {
+ perror("mmap failed");
+ return;
+ }
+
+ stk_u->off_w = 0;
+ stk_u->fow_w = 0;
+ u3t_sstack_push(c3__root);
+#endif
+}
+
+#ifndef U3_OS_windows
+/* u3t_sstack_open: initalize a root node on the spin stack
+ */
+u3t_spin*
+u3t_sstack_open()
+{
+ //Setup spin stack
+ c3_c shm_name[256];
+ snprintf(shm_name, sizeof(shm_name), SLOW_STACK_NAME, getpid());
+ c3_w shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0);
+ if ( -1 == shm_fd) {
+ perror("shm_open failed");
+ return NULL;
+ }
+
+ u3t_spin* stk_u = mmap(NULL, TRACE_PSIZE,
+ PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+ if ( MAP_FAILED == stk_u ) {
+ perror("mmap failed");
+ return NULL;
+ }
+
+ return stk_u;
+}
+#endif
+/* u3t_sstack_exit: shutdown the shared memory for thespin stack
+*/
+void
+u3t_sstack_exit()
+{
+ munmap(stk_u, u3a_page);
+}
+
+/* u3t_sstack_push: push a noun on the spin stack.
+*/
+void
+u3t_sstack_push(u3_noun nam)
+{
+ if ( !stk_u ) {
+ u3z(nam);
+ return;
+ }
+
+ if ( c3n == u3ud(nam) ) {
+ u3z(nam);
+ nam = c3__cell;
+ }
+
+ c3_w met_w = u3r_met(3, nam);
+
+ // Exit if full
+ if ( 0 < stk_u->fow_w ||
+ sizeof(stk_u->dat_y) < stk_u->off_w + met_w + sizeof(c3_w) ) {
+ stk_u->fow_w++;
+ return;
+ }
+
+ u3r_bytes(0, met_w, (c3_y*)(stk_u->dat_y+stk_u->off_w), nam);
+ stk_u->off_w += met_w;
+
+ memcpy(&stk_u->dat_y[stk_u->off_w], &met_w, sizeof(c3_w));
+ stk_u->off_w += sizeof(c3_w);
+ u3z(nam);
+}
+
+/* u3t_sstack_pop: pop a noun from the spin stack.
+*/
+void
+u3t_sstack_pop()
+{
+ if ( !stk_u ) return;
+ if ( 0 < stk_u->fow_w ) {
+ stk_u->fow_w--;
+ } else {
+ c3_w len_w = (c3_w) stk_u->dat_y[stk_u->off_w - sizeof(c3_w)];
+ stk_u->off_w -= (len_w+sizeof(c3_w));
+ }
+}
+
diff --git a/vere/pkg/noun/trace.h b/vere/pkg/noun/trace.h
new file mode 100644
index 0000000..f4e0f2b
--- /dev/null
+++ b/vere/pkg/noun/trace.h
@@ -0,0 +1,230 @@
+/// @file
+
+#ifndef U3_TRACE_H
+#define U3_TRACE_H
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c3/c3.h"
+#include "options.h"
+#include "types.h"
+#include "allocate.h"
+
+#ifdef U3_CPU_DEBUG
+# include "options.h"
+#endif
+
+#define SLOW_STACK_NAME "/spin_stack_page_%d"
+#define TRACE_PSIZE (1U << (u3a_page +2))
+
+ /** Data structures.
+ **/
+ /* u3t_trace: fast execution flags.
+ */
+ typedef struct _u3t_trace {
+ c3_o noc_o; // now executing in nock interpreter
+ c3_o glu_o; // now executing in jet glue
+ c3_o mal_o; // now executing in allocator
+ c3_o far_o; // now executing in fragmentor
+ c3_o coy_o; // now executing in copy
+ c3_o euq_o; // now executing in equal
+ } u3t_trace;
+
+ /* u3t_spin: %spin hint stack
+ */
+ typedef struct {
+ c3_w off_w;
+ c3_w fow_w;
+ c3_y dat_y[TRACE_PSIZE - 2*sizeof(c3_w)];
+ } u3t_spin;
+
+ /** Macros.
+ **/
+# ifdef U3_CPU_DEBUG
+# define u3t_on(var) \
+ (u3T.var = (u3C.wag_w & u3o_debug_cpu) \
+ ? (c3n == u3T.var) ? c3y : (abort(), 0) \
+ : u3T.var)
+# else
+# define u3t_on(var)
+#endif
+
+# ifdef U3_CPU_DEBUG
+# define u3t_off(var) \
+ (u3T.var = (u3C.wag_w & u3o_debug_cpu) \
+ ? (c3y == u3T.var) ? c3n : (abort(), 0) \
+ : u3T.var)
+# else
+# define u3t_off(var)
+#endif
+
+
+ /** Functions.
+ **/
+ /* u3t_init(): initialize tracing layer.
+ */
+ void
+ u3t_init(void);
+
+ /// @return Number of entries written to the JSON trace file.
+ c3_w
+ u3t_trace_cnt(void);
+
+ /// @return Number of times u3t_trace_close() has been called.
+ c3_w
+ u3t_file_cnt(void);
+
+ /* u3t_push(): push on trace stack.
+ */
+ void
+ u3t_push(u3_noun mon);
+
+ /* u3t_mean(): push `[%mean roc]` on trace stack.
+ */
+ void
+ u3t_mean(u3_noun roc);
+
+ /* u3t_drop(): drop from meaning stack.
+ */
+ void
+ u3t_drop(void);
+
+ /* u3t_slog(): print directly.
+ */
+ void
+ u3t_slog(u3_noun hod);
+
+ /* u3t_heck(): profile point.
+ */
+ void
+ u3t_heck(u3_atom cog);
+
+ /* u3t_samp(): sample.
+ */
+ void
+ u3t_samp(void);
+
+ /* u3t_come(): push on profile stack; return yes if active push. RETAIN.
+ */
+ c3_o
+ u3t_come(u3_noun bat);
+
+ /* u3t_flee(): pop off profile stack.
+ */
+ void
+ u3t_flee(void);
+
+ /* u3t_trace_open(): opens the path for writing tracing information.
+ */
+ void
+ u3t_trace_open(const c3_c *dir_c);
+
+ /* u3t_trace_close(): closes the trace file. optional.
+ */
+ void
+ u3t_trace_close(void);
+
+ /* u3t_trace_time(): returns current time since system epoc,
+ * whatever it is per system, in microseconds.
+ */
+ c3_d
+ u3t_trace_time(void);
+
+ /* u3t_nock_trace_push(): pushes a frame onto the trace stack;
+ * return yes if active push.
+ */
+ c3_o
+ u3t_nock_trace_push(u3_noun lab);
+
+ /* u3t_nock_trace_pop(): pop off trace stack.
+ */
+ void
+ u3t_nock_trace_pop(void);
+
+ /* u3t_event_trace(): record a lifecycle event.
+ */
+ void
+ u3t_event_trace(const c3_c* name, c3_c type);
+
+ /* u3t_damp(): print and clear profile data.
+ */
+ void
+ u3t_damp(FILE* fil_u);
+
+ /* u3t_boff(): turn profile sampling off.
+ */
+ void
+ u3t_boff(void);
+
+ /* u3t_boot(): turn sampling on.
+ */
+ void
+ u3t_boot(void);
+
+ /* u3t_slog_cap(): slog a tank with a caption with
+ ** a given priority c3_l (assumed 0-3).
+ */
+ void
+ u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan);
+
+ /* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax
+ ** flop the order into start-to-end, render, and slog each item
+ ** until done.
+ */
+ void
+ u3t_slog_trace(c3_l pri_l, u3_noun tax);
+
+ /* u3t_slog_nara(): slog only the deepest road's trace with
+ ** c3_l priority pri
+ */
+ void
+ u3t_slog_nara(c3_l pri_l);
+
+ /* u3t_slog_hela(): join all roads' traces together into one tax
+ ** and pass it to slog_trace along with the given c3_l priority pri_l
+ */
+ void
+ u3t_slog_hela(c3_l pri_l);
+
+ /* u3t_etch_meme(): report memory stats at call time
+ */
+ u3_noun
+ u3t_etch_meme(c3_l mod_l);
+
+ /* u3t_sstack_init: initalize a root node on the spin stack
+ */
+ void
+ u3t_sstack_init(void);
+
+ /* u3t_sstack_init: initalize a root node on the spin stack
+ */
+ u3t_spin*
+ u3t_sstack_open(void);
+
+ /* u3t_sstack_exit: initalize a root node on the spin stack
+ */
+ void
+ u3t_sstack_exit(void);
+
+ /* u3t_sstack_push: push a noun on the spin stack.
+ */
+ void
+ u3t_sstack_push(u3_noun nam);
+
+ /* u3t_sstack_pop: pop a noun from the spin stack.
+ */
+ void
+ u3t_sstack_pop(void);
+
+
+ /** Globals.
+ **/
+ /// Tracing profiler.
+ extern u3t_trace u3t_Trace;
+ extern u3t_spin* stk_u;
+
+# define u3T u3t_Trace
+
+
+#endif /* ifndef U3_TRACE_H */
diff --git a/vere/pkg/noun/types.h b/vere/pkg/noun/types.h
new file mode 100644
index 0000000..6819eb6
--- /dev/null
+++ b/vere/pkg/noun/types.h
@@ -0,0 +1,64 @@
+/// @file
+///
+/// Various noun types.
+
+#ifndef U3_TYPES_H
+#define U3_TYPES_H
+
+#include "c3/c3.h"
+
+/// Sentinel value for u3_noun types that aren't actually nouns.
+#define u3_none (u3_noun)0xffffffff
+
+/// 0, or `~` in Hoon.
+#define u3_nul 0
+
+/// 0, or `%$` in Hoon.
+#define u3_blip 0
+
+/// Pointer offset into the loom.
+///
+/// Declare variables of this type using u3p() to annotate the type of the
+/// pointee. Ensure that variable names of this type end in `_p`.
+typedef c3_w u3_post;
+#define u3p(type) u3_post
+
+/// Tagged noun pointer.
+///
+/// If bit 31 is 0, the noun is a direct 31-bit atom (also called a "cat").
+/// If bit 31 is 1 and bit 30 is 0, an indirect atom (also called a "pug").
+/// If bit 31 is 1 and bit 30 is 1, an indirect cell (also called a "pom").
+///
+/// Bits 0-29 are a word offset (i.e. u3_post) against the loom.
+typedef c3_w u3_noun;
+
+/// Optional noun type.
+///
+/// u3_weak is either a valid noun or u3_none.
+typedef u3_noun u3_weak;
+
+/// Atom.
+typedef u3_noun u3_atom;
+
+/// Term (Hoon aura @tas).
+typedef u3_noun u3_term;
+
+/// Cell of the form `[a b]`.
+typedef u3_noun u3_cell;
+
+/// Cell of the form `[a b c]`.
+typedef u3_noun u3_trel;
+
+/// Cell of the form `[a b c d]`.
+typedef u3_noun u3_qual;
+
+/// Cell of the form `[a b c d e]`.
+typedef u3_noun u3_quin;
+
+/// Unary noun function.
+typedef u3_noun (*u3_funk)(u3_noun);
+
+/// Binary noun function.
+typedef u3_noun (*u3_funq)(u3_noun, u3_noun);
+
+#endif /* ifndef U3_TYPES_H */
diff --git a/vere/pkg/noun/urth.c b/vere/pkg/noun/urth.c
new file mode 100644
index 0000000..91b64bb
--- /dev/null
+++ b/vere/pkg/noun/urth.c
@@ -0,0 +1,1042 @@
+/// @file
+
+#include "urth.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "jets.h"
+#include "manage.h"
+#include "options.h"
+#include "retrieve.h"
+#include "serial.h"
+#include "ur/ur.h"
+#include "vortex.h"
+
+/* _cu_atom_to_ref(): allocate indirect atom off-loom.
+*/
+static inline ur_nref
+_cu_atom_to_ref(ur_root_t* rot_u, u3a_atom* vat_u)
+{
+ ur_nref ref;
+ c3_d val_d;
+
+ switch ( vat_u->len_w ) {
+ case 2: {
+ val_d = ((c3_d)vat_u->buf_w[1]) << 32
+ | ((c3_d)vat_u->buf_w[0]);
+ ref = ur_coin64(rot_u, val_d);
+ } break;
+
+ case 1: {
+ val_d = (c3_d)vat_u->buf_w[0];
+ ref = ur_coin64(rot_u, val_d);
+ } break;
+
+ default: {
+ // XX assumes little-endian
+ //
+ c3_y* byt_y = (c3_y*)vat_u->buf_w;
+ c3_d len_d = ((c3_d)vat_u->len_w) << 2;
+
+ u3_assert( len_d );
+
+ // NB: this call will account for any trailing null bytes
+ // caused by an overestimate in [len_d]
+ //
+ ref = ur_coin_bytes(rot_u, len_d, byt_y);
+ } break;
+ }
+
+ return ref;
+}
+
+/* _cu_box_check(): check loom allocation box for relocation pointer.
+*/
+static inline c3_o
+_cu_box_check(u3a_noun* som_u, ur_nref* ref)
+{
+ c3_w* box_w = (void*)som_u;
+
+ if ( 0xffffffff == box_w[0] ) {
+ *ref = ( ((c3_d)box_w[2]) << 32
+ | ((c3_d)box_w[1]) );
+ return c3y;
+ }
+
+ return c3n;
+}
+
+/* _cu_box_stash(): overwrite an allocation box with relocation pointer.
+*/
+static inline void
+_cu_box_stash(u3a_noun* som_u, ur_nref ref)
+{
+ c3_w* box_w = (void*)som_u;
+
+ // overwrite u3a_atom with reallocated reference
+ //
+ box_w[0] = 0xffffffff;
+ box_w[1] = ref & 0xffffffff;
+ box_w[2] = ref >> 32;
+}
+
+/*
+** stack frame for recording head vs tail iteration
+**
+** $? [LOM_HEAD cell=*]
+** [ref=* cell=*]
+*/
+
+#define LOM_HEAD 0xffffffffffffffffULL
+
+typedef struct _cu_frame_s
+{
+ ur_nref ref;
+ u3a_cell* cel_u;
+} _cu_frame;
+
+typedef struct _cu_stack_s
+{
+ c3_w pre_w;
+ c3_w siz_w;
+ c3_w fil_w;
+ _cu_frame* fam_u;
+} _cu_stack;
+
+/* _cu_from_loom_next(): advance off-loom reallocation traversal.
+*/
+static inline ur_nref
+_cu_from_loom_next(_cu_stack* tac_u, ur_root_t* rot_u, u3_noun a)
+{
+ while ( 1 ) {
+ // u3 direct == ur direct
+ //
+ if ( c3y == u3a_is_cat(a) ) {
+ return (ur_nref)a;
+ }
+ else {
+ u3a_noun* som_u = u3a_to_ptr(a);
+ ur_nref ref;
+
+ // check for relocation pointers
+ //
+ if ( c3y == _cu_box_check(som_u, &ref) ) {
+ return ref;
+ }
+ // reallocate indirect atoms, stashing relocation pointers
+ //
+ else if ( c3y == u3a_is_atom(a) ) {
+ ref = _cu_atom_to_ref(rot_u, (u3a_atom*)som_u);
+ _cu_box_stash(som_u, ref);
+ return ref;
+ }
+ else {
+ u3a_cell* cel_u = (u3a_cell*)som_u;
+
+ // reallocate the stack if full
+ //
+ if ( tac_u->fil_w == tac_u->siz_w ) {
+ c3_w nex_w = tac_u->pre_w + tac_u->siz_w; // XX overflow
+ tac_u->fam_u = c3_realloc(tac_u->fam_u, nex_w * sizeof(*tac_u->fam_u));
+ tac_u->pre_w = tac_u->siz_w;
+ tac_u->siz_w = nex_w;
+ }
+
+ // push a head-frame and continue into the head
+ //
+ {
+ _cu_frame* fam_u = &(tac_u->fam_u[tac_u->fil_w++]);
+ fam_u->ref = LOM_HEAD;
+ fam_u->cel_u = cel_u;
+ }
+
+ a = cel_u->hed;
+ continue;
+ }
+ }
+ }
+}
+
+/* _cu_from_loom(): reallocate [a] off loom, in [r].
+*/
+static ur_nref
+_cu_from_loom(ur_root_t* rot_u, u3_noun a)
+{
+ _cu_stack tac_u = {0};
+ ur_nref ref;
+
+ tac_u.pre_w = ur_fib10;
+ tac_u.siz_w = ur_fib11;
+ tac_u.fam_u = c3_malloc(tac_u.siz_w * sizeof(*tac_u.fam_u));
+
+ ref = _cu_from_loom_next(&tac_u, rot_u, a);
+
+ // incorporate reallocated ref, accounting for cells
+ //
+ while ( tac_u.fil_w ) {
+ // peek at the top of the stack
+ //
+ _cu_frame* fam_u = &(tac_u.fam_u[tac_u.fil_w - 1]);
+
+ // [fam_u] is a head-frame; stash ref and continue into the tail
+ //
+ if ( LOM_HEAD == fam_u->ref ) {
+ fam_u->ref = ref;
+ ref = _cu_from_loom_next(&tac_u, rot_u, fam_u->cel_u->tel);
+ }
+ // [fam_u] is a tail-frame; cons refs and pop the stack
+ //
+ else {
+ ref = ur_cons(rot_u, fam_u->ref, ref);
+ _cu_box_stash((u3a_noun*)fam_u->cel_u, ref);
+ tac_u.fil_w--;
+ }
+ }
+
+ c3_free(tac_u.fam_u);
+
+ return ref;
+}
+
+/* _cu_vec: parameters for cold-state hamt walk.
+*/
+typedef struct _cu_vec_s {
+ ur_nvec_t* vec_u;
+ ur_root_t* rot_u;
+} _cu_vec;
+
+/* _cu_hamt_walk(): reallocate key/value pair in hamt walk.
+*/
+static void
+_cu_hamt_walk(u3_noun kev, void* ptr)
+{
+ _cu_vec* dat_u = (_cu_vec*)ptr;
+ ur_nvec_t* vec_u = dat_u->vec_u;
+ ur_root_t* rot_u = dat_u->rot_u;
+
+ vec_u->refs[vec_u->fill++] = _cu_from_loom(rot_u, kev);
+}
+
+/* _cu_all_from_loom(): reallocate essential persistent state off-loom.
+**
+** NB: destroys the loom.
+*/
+static ur_nref
+_cu_all_from_loom(ur_root_t* rot_u, ur_nvec_t* cod_u)
+{
+ ur_nref ken = _cu_from_loom(rot_u, u3A->roc);
+ c3_w cod_w = u3h_wyt(u3R->jed.cod_p);
+ _cu_vec dat_u = { .vec_u = cod_u, .rot_u = rot_u };
+
+ ur_nvec_init(cod_u, cod_w);
+ u3h_walk_with(u3R->jed.cod_p, _cu_hamt_walk, &dat_u);
+
+ return ken;
+}
+
+typedef struct _cu_loom_s {
+ ur_dict32_t map_u; // direct->indirect mapping
+ u3_atom *vat; // indirect atoms
+ u3_noun *cel; // cells
+} _cu_loom;
+
+/* _cu_ref_to_noun(): lookup/allocate [ref] on the loom.
+*/
+static u3_noun
+_cu_ref_to_noun(ur_root_t* rot_u, ur_nref ref, _cu_loom* lom_u)
+{
+ switch ( ur_nref_tag(ref) ) {
+ default: u3_assert(0);
+
+ // all ur indirect atoms have been pre-reallocated on the loom.
+ //
+ case ur_iatom: return lom_u->vat[ur_nref_idx(ref)];
+
+
+ // cells were allocated off-loom in cons-order, and are traversed
+ // in the same order: we've already relocated any one we could need here.
+ //
+ case ur_icell: return lom_u->cel[ur_nref_idx(ref)];
+
+ // u3 direct atoms are 31-bit, while ur direct atoms are 62-bit;
+ // we use a hashtable to deduplicate the non-overlapping space
+ //
+ case ur_direct: {
+ u3_atom vat;
+
+ if ( 0x7fffffffULL >= ref ) {
+ return (u3_atom)ref;
+ }
+ else if ( ur_dict32_get(rot_u, &lom_u->map_u, ref, (c3_w*)&vat) ) {
+ return vat;
+ }
+ else {
+ {
+ c3_w wor_w[2] = { ref & 0xffffffff, ref >> 32 };
+ vat = (c3_w)u3i_words(2, wor_w);
+ }
+
+ ur_dict32_put(0, &lom_u->map_u, ref, (c3_w)vat);
+ return vat;
+ }
+ } break;
+ }
+}
+
+/* _cu_all_to_loom(): reallocate all of [rot_u] on the loom, restore roots.
+** NB: requires all roots to be cells
+** does *not* track refcounts, which must be
+** subsequently reconstructed via tracing.
+*/
+static void
+_cu_all_to_loom(ur_root_t* rot_u, ur_nref ken, ur_nvec_t* cod_u)
+{
+ _cu_loom lom_u = {0};
+ c3_d i_d, fil_d;
+
+ ur_dict32_grow(0, &lom_u.map_u, ur_fib11, ur_fib12);
+
+ // allocate all atoms on the loom.
+ //
+ {
+ c3_d* len_d = rot_u->atoms.lens;
+ c3_y** byt_y = rot_u->atoms.bytes;
+
+ fil_d = rot_u->atoms.fill;
+ lom_u.vat = calloc(fil_d, sizeof(u3_atom));
+
+ for ( i_d = 0; i_d < fil_d; i_d++ ) {
+ lom_u.vat[i_d] = u3i_bytes(len_d[i_d], byt_y[i_d]);
+ }
+ }
+
+ // allocate all cells on the loom.
+ //
+ {
+ ur_nref* hed = rot_u->cells.heads;
+ ur_nref* tal = rot_u->cells.tails;
+ u3_noun cel;
+
+ fil_d = rot_u->cells.fill;
+ lom_u.cel = c3_calloc(fil_d * sizeof(u3_noun));
+
+ for ( i_d = 0; i_d < fil_d; i_d++ ) {
+ cel = u3nc(_cu_ref_to_noun(rot_u, hed[i_d], &lom_u),
+ _cu_ref_to_noun(rot_u, tal[i_d], &lom_u));
+ lom_u.cel[i_d] = cel;
+ u3r_mug(cel);
+ }
+ }
+
+ // restore kernel reference (always a cell)
+ //
+ u3A->roc = lom_u.cel[ur_nref_idx(ken)];
+
+ // restore cold jet state (always cells)
+ //
+ {
+ c3_d max_d = cod_u->fill;
+ c3_d i_d;
+ ur_nref ref;
+ u3_noun kev;
+
+ for ( i_d = 0; i_d < max_d; i_d++) {
+ ref = cod_u->refs[i_d];
+ kev = lom_u.cel[ur_nref_idx(ref)];
+ u3h_put(u3R->jed.cod_p, u3h(kev), u3k(u3t(kev)));
+ u3z(kev);
+ }
+ }
+
+ // dispose of relocation pointers
+ //
+ c3_free(lom_u.cel);
+ c3_free(lom_u.vat);
+ ur_dict_free((ur_dict_t*)&lom_u.map_u);
+}
+
+/* _cu_realloc(): hash-cons roots off-loom, reallocate on loom.
+*/
+static ur_nref
+_cu_realloc(FILE* fil_u, ur_root_t** tor_u, ur_nvec_t* doc_u)
+{
+#ifdef U3_MEMORY_DEBUG
+ u3_assert(0);
+#endif
+
+ // bypassing page tracking as an optimization
+ //
+ // NB: u3m_foul() will mark all as dirty, and
+ // u3e_save() will reinstate protection flags
+ //
+ u3m_foul();
+
+ // stash event number
+ //
+ c3_d eve_d = u3A->eve_d;
+
+ // reallocate kernel and cold jet state
+ //
+ ur_root_t* rot_u = ur_root_init();
+ ur_nvec_t cod_u;
+ ur_nref ken = _cu_all_from_loom(rot_u, &cod_u);
+
+ // print [rot_u] measurements
+ //
+ if ( fil_u ) {
+ ur_root_info(fil_u, rot_u);
+ fprintf(fil_u, "\r\n");
+ }
+
+ // reinitialize loom
+ //
+ // NB: hot jet state is not yet re-established
+ //
+ u3m_pave(c3y);
+
+ // reallocate all nouns on the loom
+ //
+ _cu_all_to_loom(rot_u, ken, &cod_u);
+
+ // allocate new hot jet state
+ //
+ u3j_boot(c3y);
+
+ // establish correct refcounts via tracing
+ //
+ c3_w wag_w = u3C.wag_w;
+ u3C.wag_w |= u3o_debug_ram;
+ u3m_grab(u3_none);
+ u3C.wag_w = wag_w;
+
+ // re-establish warm jet state
+ //
+ u3j_ream();
+
+ // restore event number
+ //
+ u3A->eve_d = eve_d;
+
+ // mark all pages dirty
+ //
+ u3m_foul();
+
+ *tor_u = rot_u;
+ *doc_u = cod_u;
+
+ return ken;
+}
+
+/* u3u_meld(): globally deduplicate memory, returns u3a_open delta.
+*/
+#ifdef U3_MEMORY_DEBUG
+c3_w
+u3u_meld(void)
+{
+ fprintf(stderr, "u3: unable to meld under U3_MEMORY_DEBUG\r\n");
+ return 0;
+}
+#else
+c3_w
+u3u_meld(void)
+{
+ c3_w pre_w = u3a_open(u3R);
+ ur_root_t* rot_u;
+ ur_nvec_t cod_u;
+
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ _cu_realloc(stderr, &rot_u, &cod_u);
+
+ // dispose off-loom structures
+ //
+ ur_nvec_free(&cod_u);
+ ur_root_free(rot_u);
+ return (u3a_open(u3R) - pre_w);
+}
+#endif
+
+/* BEGIN helper functions for u3u_melt
+ -------------------------------------------------------------------
+*/
+/* _cj_warm_tap(): tap war_p to rel
+*/
+static void
+_cj_warm_tap(u3_noun kev, void* wit)
+{
+ u3_noun* rel = wit;
+ *rel = u3nc(u3k(kev), *rel);
+}
+
+static inline u3_weak
+_cu_melt_get(u3p(u3h_root) set_p, u3_noun som)
+{
+ u3_post hav_p = u3h_git(set_p, som);
+
+ if ( u3_none == hav_p ) {
+ return u3_none;
+ }
+
+ // restore tag bits from [som]
+ //
+ return (hav_p >> u3a_vits) | (som & 0xc0000000);
+}
+
+static inline void
+_cu_melt_put(u3p(u3h_root) set_p, u3_noun som)
+{
+ // strip tag bits from [som] to skip refcounts
+ //
+ u3_post hav_p = u3a_to_off(som);
+ u3h_put(set_p, som, hav_p);
+}
+
+static void
+_cu_melt_noun(u3p(u3h_root) set_p, u3_noun* mos)
+{
+ u3_noun som = *mos;
+ u3_weak hav;
+
+ // skip direct atoms
+ //
+ if ( c3y == u3a_is_cat(som) ) {
+ return;
+ }
+
+ // [som] equals [hav], and [hav] is canonical
+ //
+ if ( u3_none != (hav = _cu_melt_get(set_p, som)) ) {
+ if ( hav != som ) {
+ u3z(som);
+ *mos = u3k(hav);
+ }
+ return;
+ }
+
+ // traverse subtrees
+ //
+ if ( c3y == u3a_is_cell(som) ) {
+ u3a_cell *cel_u = u3a_to_ptr(som);
+ _cu_melt_noun(set_p, &cel_u->hed);
+ _cu_melt_noun(set_p, &cel_u->tel);
+ }
+
+ // [som] is canonical
+ //
+ _cu_melt_put(set_p, som);
+}
+
+/* u3u_melt(): globally deduplicate memory and pack in-place.
+*/
+c3_w
+u3u_melt(void)
+{
+ c3_w pre_w = u3a_open(u3R);
+
+ // Verify that we're on the main road.
+ //
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ // Store a cons list of the cold jet registrations in `cod`
+ //
+ u3_noun cod = u3_nul;
+ u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &cod);
+
+ u3m_reclaim(); // refresh the byte-code interpreter.
+
+ u3h_free(u3R->cax.per_p);
+ u3R->cax.per_p = u3h_new_cache(u3C.per_w);
+
+ u3h_free(u3R->jed.cod_p);
+ u3R->jed.cod_p = u3h_new();
+
+ {
+ u3p(u3h_root) set_p = u3h_new(); // temp hashtable
+
+ _cu_melt_noun(set_p, &cod); // melt the jets
+ _cu_melt_noun(set_p, &u3A->roc); // melt the kernel
+
+ u3h_free(set_p); // release the temp hashtable
+ }
+
+ // re-initialize the jets
+ //
+ u3j_boot(c3y);
+
+ // Put the jet registrations back. Loop over cod putting them back into the cold jet
+ // dashboard. Then re-run the garbage collector.
+ //
+ {
+ u3_noun codc = cod;
+
+ while(u3_nul != cod) {
+ u3_noun kev = u3h(cod);
+ u3h_put(u3R->jed.cod_p, u3h(kev), u3k(u3t(kev)));
+ cod = u3t(cod);
+ }
+
+ u3z(codc);
+ }
+
+ // remove free space
+ //
+ u3j_ream();
+ u3m_pack();
+
+ return (u3a_open(u3R) - pre_w);
+}
+
+/* _cu_rock_path(): format rock path.
+*/
+static c3_o
+_cu_rock_path(c3_c* dir_c, c3_d eve_d, c3_c** out_c)
+{
+ c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d);
+ c3_c* nam_c = c3_malloc(nam_w);
+ c3_i ret_i;
+
+ ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d);
+
+ if ( ret_i < 0 ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n",
+ dir_c, eve_d, strerror(errno));
+ c3_free(nam_c);
+ return c3n;
+ }
+ else if ( ret_i >= nam_w ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n",
+ dir_c, eve_d);
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ *out_c = nam_c;
+ return c3y;
+}
+
+/* _cu_rock_path_make(): format rock path, creating directory if necessary..
+*/
+static c3_o
+_cu_rock_path_make(c3_c* dir_c, c3_d eve_d, c3_c** out_c)
+{
+ c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d);
+ c3_c* nam_c = c3_malloc(nam_w);
+ c3_i ret_i;
+
+ // create $pier/.urb/roc, if it doesn't exist
+ //
+ // NB, $pier/.urb is guaranteed to already exist
+ //
+ {
+ ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc", dir_c);
+
+ if ( ret_i < 0 ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n",
+ dir_c, eve_d, strerror(errno));
+ c3_free(nam_c);
+ return c3n;
+ }
+ else if ( ret_i >= nam_w ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n",
+ dir_c, eve_d);
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ if ( c3_mkdir(nam_c, 0700)
+ && (EEXIST != errno) )
+ {
+ fprintf(stderr, "rock: directory create failed (%s, %" PRIu64 "): %s\r\n",
+ dir_c, eve_d, strerror(errno));
+ c3_free(nam_c);
+ return c3n;
+ }
+ }
+
+ ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d);
+
+ if ( ret_i < 0 ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n",
+ dir_c, eve_d, strerror(errno));
+ c3_free(nam_c);
+ return c3n;
+ }
+ else if ( ret_i >= nam_w ) {
+ fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n",
+ dir_c, eve_d);
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ *out_c = nam_c;
+ return c3y;
+}
+
+static c3_o
+_cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y)
+{
+ c3_i fid_i;
+
+ // open rock file, creating the containing directory if necessary
+ //
+ {
+ c3_c* nam_c;
+
+ if ( c3n == _cu_rock_path_make(dir_c, eve_d, &nam_c) ) {
+ return c3n;
+ }
+
+ if ( -1 == (fid_i = c3_open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
+ fprintf(stderr, "rock: c3_open failed (%s, %" PRIu64 "): %s\r\n",
+ dir_c, eve_d, strerror(errno));
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ c3_free(nam_c);
+ }
+
+ // write jam-buffer into [fid_i]
+ //
+ // XX deduplicate with _write() wrapper in term.c
+ //
+ {
+ ssize_t ret_i;
+
+ while ( len_d > 0 ) {
+ c3_w lop_w = 0;
+ // retry interrupt/async errors
+ //
+ do {
+ // abort pathological retry loop
+ //
+ if ( 100 == ++lop_w ) {
+ fprintf(stderr, "rock: write loop: %s\r\n", strerror(errno));
+ close(fid_i);
+ // XX unlink file?
+ //
+ return c3n;
+ }
+
+ ret_i = write(fid_i, byt_y, len_d);
+ }
+ while ( (ret_i < 0)
+ && ( (errno == EINTR)
+ || (errno == EAGAIN)
+ || (errno == EWOULDBLOCK) ));
+
+ // assert on true errors
+ //
+ // NB: can't call u3l_log here or we would re-enter _write()
+ //
+ if ( ret_i < 0 ) {
+ fprintf(stderr, "rock: write failed %s\r\n", strerror(errno));
+ close(fid_i);
+ // XX unlink file?
+ //
+ return c3n;
+ }
+ // continue partial writes
+ //
+ else {
+ len_d -= ret_i;
+ byt_y += ret_i;
+ }
+ }
+ }
+
+ close(fid_i);
+
+ return c3y;
+}
+
+/* u3u_cram(): globably deduplicate memory, and write a rock to disk.
+*/
+#ifdef U3_MEMORY_DEBUG
+c3_o
+u3u_cram(c3_c* dir_c, c3_d eve_d)
+{
+ fprintf(stderr, "u3: unable to cram under U3_MEMORY_DEBUG\r\n");
+ return c3n;
+}
+#else
+c3_o
+u3u_cram(c3_c* dir_c, c3_d eve_d)
+{
+ c3_o ret_o = c3y;
+ c3_d len_d;
+ c3_y* byt_y;
+
+ u3_assert( &(u3H->rod_u) == u3R );
+
+ {
+ ur_root_t* rot_u;
+ ur_nvec_t cod_u;
+ ur_nref ken = _cu_realloc(stderr, &rot_u, &cod_u);
+
+ {
+ ur_nref roc = u3_nul;
+ c3_d max_d = cod_u.fill;
+ c3_d i_d;
+
+ // cons vector of cold jet-state entries onto a list
+ //
+ for ( i_d = 0; i_d < max_d; i_d++) {
+ roc = ur_cons(rot_u, cod_u.refs[i_d], roc);
+ }
+
+ {
+ c3_c* has_c = "hashboard";
+ ur_nref has = ur_coin_bytes(rot_u, strlen(has_c), (c3_y*)has_c);
+ roc = ur_cons(rot_u, has, roc);
+ }
+
+ roc = ur_cons(rot_u, ur_coin64(rot_u, c3__arvo),
+ ur_cons(rot_u, ken, roc));
+
+ ur_jam(rot_u, roc, &len_d, &byt_y);
+ }
+
+ // dispose off-loom structures
+ //
+ ur_nvec_free(&cod_u);
+ ur_root_free(rot_u);
+ }
+
+ // write jam-buffer into pier
+ //
+ if ( c3n == _cu_rock_save(dir_c, eve_d, len_d, byt_y) ) {
+ ret_o = c3n;
+ }
+
+ c3_free(byt_y);
+
+ return ret_o;
+}
+#endif
+
+/* u3u_mmap_read(): open and mmap the file at [pat_c] for reading.
+*/
+c3_o
+u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y)
+{
+ c3_i fid_i;
+ c3_d len_d;
+
+ // open file
+ //
+ if ( -1 == (fid_i = c3_open(pat_c, O_RDONLY, 0644)) ) {
+ fprintf(stderr, "%s: c3_open failed (%s): %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ return c3n;
+ }
+
+ // measure file
+ //
+ {
+ struct stat buf_b;
+
+ if ( -1 == fstat(fid_i, &buf_b) ) {
+ fprintf(stderr, "%s: stat failed (%s): %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ close(fid_i);
+ return c3n;
+ }
+
+ len_d = buf_b.st_size;
+ }
+
+ // mmap file
+ //
+ {
+ void* ptr_v;
+
+ if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ, MAP_SHARED, fid_i, 0)) ) {
+ fprintf(stderr, "%s: mmap failed (%s): %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ close(fid_i);
+ return c3n;
+ }
+
+ *out_d = len_d;
+ *out_y = (c3_y*)ptr_v;
+ }
+
+ // close file
+ //
+ close(fid_i);
+
+ return c3y;
+}
+
+/* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write.
+*/
+c3_o
+u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y)
+{
+ c3_i fid_i;
+
+ // open file
+ //
+ if ( -1 == (fid_i = c3_open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
+ fprintf(stderr, "%s: c3_open failed (%s): %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ return c3n;
+ }
+
+ // grow [fid_i] to [len_w]
+ //
+ // XX build with _FILE_OFFSET_BITS == 64 ?
+ //
+ if ( 0 != ftruncate(fid_i, len_d) ) {
+ fprintf(stderr, "%s: ftruncate grow %s: %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ close(fid_i);
+ return c3n;
+ }
+
+ // mmap file
+ //
+ {
+ void* ptr_v;
+
+ if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ|PROT_WRITE, MAP_SHARED, fid_i, 0)) ) {
+ fprintf(stderr, "%s: mmap failed (%s): %s\r\n",
+ cap_c, pat_c, strerror(errno));
+ close(fid_i);
+ return c3n;
+ }
+
+ *out_y = (c3_y*)ptr_v;
+ }
+
+ // close file
+ //
+ close(fid_i);
+
+ return c3y;
+}
+
+/* u3u_mmap_save(): sync file-backed mmap.
+*/
+c3_o
+u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y)
+{
+ if ( 0 != msync(byt_y, len_d, MS_SYNC) ) {
+ fprintf(stderr, "%s: msync %s: %s\r\n", cap_c, pat_c, strerror(errno));
+ return c3n;
+ }
+
+ return c3y;
+}
+
+/* u3u_munmap(): unmap the region at [byt_y].
+*/
+c3_o
+u3u_munmap(c3_d len_d, c3_y* byt_y)
+{
+ if ( 0 != munmap(byt_y, len_d) ) {
+ return c3n;
+ }
+
+ return c3y;
+}
+
+/* u3u_uncram(): restore persistent state from a rock.
+*/
+c3_o
+u3u_uncram(c3_c* dir_c, c3_d eve_d)
+{
+ c3_c* nam_c;
+ c3_d len_d;
+ c3_y* byt_y;
+
+ // load rock file into buffer
+ //
+ if ( c3n == _cu_rock_path(dir_c, eve_d, &nam_c) ) {
+ fprintf(stderr, "uncram: failed to make rock path (%s, %" PRIu64 ")\r\n",
+ dir_c, eve_d);
+ return c3n;
+ }
+ else if ( c3n == u3u_mmap_read("rock", nam_c, &len_d, &byt_y) ) {
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ // bypassing page tracking as an optimization
+ //
+ // NB: u3m_foul() will mark all as dirty, and
+ // u3e_save() will reinstate protection flags
+ //
+ u3m_foul();
+
+ // reinitialize loom
+ //
+ // NB: hot jet state is not yet re-established
+ //
+ u3m_pave(c3y);
+
+ // cue rock, restore persistent state
+ //
+ // XX errors are fatal, barring a full "u3m_reboot"-type operation.
+ //
+ {
+ // XX tune the initial dictionary size for less reallocation
+ //
+ u3_cue_xeno* sil_u = u3s_cue_xeno_init_with(ur_fib33, ur_fib34);
+ u3_weak ref = u3s_cue_xeno_with(sil_u, len_d, byt_y);
+ u3_noun roc, doc, tag, cod;
+
+ u3s_cue_xeno_done(sil_u);
+
+ if ( u3_none == ref ) {
+ fprintf(stderr, "uncram: failed to cue rock\r\n");
+ c3_free(nam_c);
+ return c3n;
+ }
+ else if ( c3n == u3r_pq(ref, c3__arvo, &roc, &doc)
+ || (c3n == u3r_cell(doc, &tag, &cod))
+ || (c3n == u3r_sing_c("hashboard", tag)) )
+ {
+ fprintf(stderr, "uncram: failed: invalid rock format\r\n");
+ u3z(ref);
+ c3_free(nam_c);
+ return c3n;
+ }
+
+ u3A->roc = u3k(roc);
+ u3j_load(u3k(cod));
+
+ u3z(ref);
+ }
+
+ u3u_munmap(len_d, byt_y);
+
+ // allocate new hot jet state; re-establish warm
+ //
+ u3j_boot(c3y);
+ u3j_ream();
+
+ // restore event number
+ //
+ u3A->eve_d = eve_d;
+
+ // leave rocks on disk
+ //
+ // if ( 0 != c3_unlink(nam_c) ) {
+ // fprintf(stderr, "uncram: failed to delete rock (%s, %" PRIu64 "): %s\r\n",
+ // dir_c, eve_d, strerror(errno));
+ // c3_free(nam_c);
+ // return c3n;
+ // }
+
+ c3_free(nam_c);
+
+ return c3y;
+}
diff --git a/vere/pkg/noun/urth.h b/vere/pkg/noun/urth.h
new file mode 100644
index 0000000..a11b9aa
--- /dev/null
+++ b/vere/pkg/noun/urth.h
@@ -0,0 +1,49 @@
+/// @file
+
+#ifndef U3_URTH_H
+#define U3_URTH_H
+
+#include "c3/c3.h"
+
+ /** Functions.
+ **/
+ /* u3u_meld(): globally deduplicate memory, returns u3a_open delta.
+ */
+ c3_w
+ u3u_meld(void) __attribute__ ((deprecated));
+
+ /* u3u_melt(): globally deduplicate memory and pack in-place.
+ */
+ c3_w
+ u3u_melt(void) __attribute__ ((deprecated));
+
+ /* u3u_cram(): globably deduplicate memory, and write a rock to disk.
+ */
+ c3_o
+ u3u_cram(c3_c* dir_c, c3_d eve_d);
+ /* u3u_uncram(): restore persistent state from a rock.
+ */
+ c3_o
+ u3u_uncram(c3_c* dir_c, c3_d eve_d);
+
+ /* u3u_mmap_read(): open and mmap the file at [pat_c] for reading.
+ */
+ c3_o
+ u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y);
+
+ /* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write.
+ */
+ c3_o
+ u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y);
+
+ /* u3u_mmap_save(): sync file-backed mmap.
+ */
+ c3_o
+ u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y);
+
+ /* u3u_munmap(): unmap the region at [byt_y].
+ */
+ c3_o
+ u3u_munmap(c3_d len_d, c3_y* byt_y);
+
+#endif /* ifndef U3_URTH_H */
diff --git a/vere/pkg/noun/version.h b/vere/pkg/noun/version.h
new file mode 100644
index 0000000..88c6ac4
--- /dev/null
+++ b/vere/pkg/noun/version.h
@@ -0,0 +1,43 @@
+#ifndef U3_VERSION_H
+#define U3_VERSION_H
+
+/* loom layout
+ */
+typedef c3_d u3v_version;
+
+#define U3V_VER1 (u3v_version)1 // 1.0
+#define U3V_VER2 (u3v_version)2 // 2.0: pointer compression
+#define U3V_VER3 (u3v_version)3 // 3.0-rc: persistent memoization
+#define U3V_VER4 (u3v_version)4 // 3.0: bytecode alignment
+#define U3V_VER5 (u3v_version)5 // ?? palloc
+#define U3V_VERLAT U3V_VER5
+
+/* bytecode semantics (within u3v_version)
+ */
+typedef c3_w u3n_version;
+
+#define U3N_VER1 (u3n_version)0 // zero-indexedfor backcompat
+#define U3N_VER2 (u3n_version)1
+#define U3N_VERLAT U3N_VER2
+
+/* snapshot patch format
+ */
+typedef c3_w u3e_version;
+
+#define U3P_VER2 (u3e_version)2 // top-level checksum added
+#define U3P_VERLAT U3P_VER2
+
+/* top-level event log format
+ */
+#define U3D_VER1 1 // <= 2.0
+#define U3D_VER2 2 // migration to 3.0 in-progress
+#define U3D_VER3 3 // 3.0 (epoch system)
+#define U3D_VERLAT U3D_VER3
+
+/* epoch layout
+*/
+#define U3E_VER1 1 // north+south.bin
+#define U3E_VER2 2 // image.bin
+#define U3E_VERLAT U3E_VER2
+
+#endif /* ifndef U3_VERSION_H */
diff --git a/vere/pkg/noun/verstable.h b/vere/pkg/noun/verstable.h
new file mode 100644
index 0000000..e34cff0
--- /dev/null
+++ b/vere/pkg/noun/verstable.h
@@ -0,0 +1,1949 @@
+/*------------------------------------------------- VERSTABLE v2.1.1 ---------------------------------------------------
+
+Verstable is a C99-compatible, open-addressing hash table using quadratic probing and the following additions:
+
+* All keys that hash (i.e. "belong") to the same bucket (their "home bucket") are linked together by an 11-bit integer
+ specifying the quadratic displacement, relative to that bucket, of the next key in the chain.
+
+* If a chain of keys exists for a given bucket, then it always begins at that bucket. To maintain this policy, a 1-bit
+ flag is used to mark whether the key occupying a bucket belongs there. When inserting a new key, if the bucket it
+ belongs to is occupied by a key that does not belong there, then the occupying key is evicted and the new key takes
+ the bucket.
+
+* A 4-bit fragment of each key's hash code is also stored.
+
+* The aforementioned metadata associated with each bucket (the 4-bit hash fragment, the 1-bit flag, and the 11-bit link
+ to the next key in the chain) are stored together in a uint16_t array rather than in the bucket alongside the key and
+ (optionally) the value.
+
+One way to conceptualize this scheme is as a chained hash table in which overflowing keys are stored not in separate
+memory allocations but in otherwise unused buckets. In this regard, it shares similarities with Malte Skarupke's Bytell
+hash table (https://www.youtube.com/watch?v=M2fKMP47slQ) and traditional "coalesced hashing".
+
+Advantages of this scheme include:
+
+* Fast lookups impervious to load factor: If the table contains any key belonging to the lookup key's home bucket, then
+ that bucket contains the first in a traversable chain of all keys belonging to it. Hence, only the home bucket and
+ other buckets containing keys belonging to it are ever probed. Moreover, the stored hash fragments allow skipping most
+ non-matching keys in the chain without accessing the actual buckets array or calling the (potentially expensive) key
+ comparison function.
+
+* Fast insertions: Insertions are faster than they are in other schemes that move keys around (e.g. Robin Hood) because
+ they only move, at most, one existing key.
+
+* Fast, tombstone-free deletions: Deletions, which usually require tombstones in quadratic-probing hash tables, are
+ tombstone-free and only move, at most, one existing key.
+
+* Fast iteration: The separate metadata array allows keys in sparsely populated tables to be found without incurring the
+ frequent cache misses that would result from traversing the buckets array.
+
+Usage example:
+
+ +---------------------------------------------------------+----------------------------------------------------------+
+ | Using the generic macro API (C11 and later): | Using the prefixed functions API (C99 and later): |
+ |---------------------------------------------------------+----------------------------------------------------------+
+ | #include <stdio.h> | #include <stdio.h> |
+ | | |
+ | // Instantiating a set template. | // Instantiating a set template. |
+ | #define NAME int_set | #define NAME int_set |
+ | #define KEY_TY int | #define KEY_TY int |
+ | #include "verstable.h" | #define HASH_FN vt_hash_integer |
+ | | #define CMPR_FN vt_cmpr_integer |
+ | // Instantiating a map template. | #include "verstable.h" |
+ | #define NAME int_int_map | |
+ | #define KEY_TY int | // Instantiating a map template. |
+ | #define VAL_TY int | #define NAME int_int_map |
+ | #include "verstable.h" | #define KEY_TY int |
+ | | #define VAL_TY int |
+ | int main( void ) | #define HASH_FN vt_hash_integer |
+ | { | #define CMPR_FN vt_cmpr_integer |
+ | // Set. | #include "verstable.h" |
+ | | |
+ | int_set our_set; | int main( void ) |
+ | vt_init( &our_set ); | { |
+ | | // Set. |
+ | // Inserting keys. | |
+ | for( int i = 0; i < 10; ++i ) | int_set our_set; |
+ | { | int_set_init( &our_set ); |
+ | int_set_itr itr = vt_insert( &our_set, i ); | |
+ | if( vt_is_end( itr ) ) | // Inserting keys. |
+ | { | for( int i = 0; i < 10; ++i ) |
+ | // Out of memory, so abort. | { |
+ | vt_cleanup( &our_set ); | int_set_itr itr = |
+ | return 1; | int_set_insert( &our_set, i ); |
+ | } | if( int_set_is_end( itr ) ) |
+ | } | { |
+ | | // Out of memory, so abort. |
+ | // Erasing keys. | int_set_cleanup( &our_set ); |
+ | for( int i = 0; i < 10; i += 3 ) | return 1; |
+ | vt_erase( &our_set, i ); | } |
+ | | } |
+ | // Retrieving keys. | |
+ | for( int i = 0; i < 10; ++i ) | // Erasing keys. |
+ | { | for( int i = 0; i < 10; i += 3 ) |
+ | int_set_itr itr = vt_get( &our_set, i ); | int_set_erase( &our_set, i ); |
+ | if( !vt_is_end( itr ) ) | |
+ | printf( "%d ", itr.data->key ); | // Retrieving keys. |
+ | } | for( int i = 0; i < 10; ++i ) |
+ | // Printed: 1 2 4 5 7 8 | { |
+ | | int_set_itr itr = int_set_get( &our_set, i ); |
+ | // Iteration. | if( !int_set_is_end( itr ) ) |
+ | for( | printf( "%d ", itr.data->key ); |
+ | int_set_itr itr = vt_first( &our_set ); | } |
+ | !vt_is_end( itr ); | // Printed: 1 2 4 5 7 8 |
+ | itr = vt_next( itr ) | |
+ | ) | // Iteration. |
+ | printf( "%d ", itr.data->key ); | for( |
+ | // Printed: 2 4 7 1 5 8 | int_set_itr itr = |
+ | | int_set_first( &our_set ); |
+ | vt_cleanup( &our_set ); | !int_set_is_end( itr ); |
+ | | itr = int_set_next( itr ) |
+ | // Map. | ) |
+ | | printf( "%d ", itr.data->key ); |
+ | int_int_map our_map; | // Printed: 2 4 7 1 5 8 |
+ | vt_init( &our_map ); | |
+ | | int_set_cleanup( &our_set ); |
+ | // Inserting keys and values. | |
+ | for( int i = 0; i < 10; ++i ) | // Map. |
+ | { | |
+ | int_int_map_itr itr = | int_int_map our_map; |
+ | vt_insert( &our_map, i, i + 1 ); | int_int_map_init( &our_map ); |
+ | if( vt_is_end( itr ) ) | |
+ | { | // Inserting keys and values. |
+ | // Out of memory, so abort. | for( int i = 0; i < 10; ++i ) |
+ | vt_cleanup( &our_map ); | { |
+ | return 1; | int_int_map_itr itr = |
+ | } | int_int_map_insert( &our_map, i, i + 1 ); |
+ | } | if( int_int_map_is_end( itr ) ) |
+ | | { |
+ | // Erasing keys and values. | // Out of memory, so abort. |
+ | for( int i = 0; i < 10; i += 3 ) | int_int_map_cleanup( &our_map ); |
+ | vt_erase( &our_map, i ); | return 1; |
+ | | } |
+ | // Retrieving keys and values. | } |
+ | for( int i = 0; i < 10; ++i ) | |
+ | { | // Erasing keys and values. |
+ | int_int_map_itr itr = vt_get( &our_map, i ); | for( int i = 0; i < 10; i += 3 ) |
+ | if( !vt_is_end( itr ) ) | int_int_map_erase( &our_map, i ); |
+ | printf( | |
+ | "%d:%d ", | // Retrieving keys and values. |
+ | itr.data->key, | for( int i = 0; i < 10; ++i ) |
+ | itr.data->val | { |
+ | ); | int_int_map_itr itr = |
+ | } | int_int_map_get( &our_map, i ); |
+ | // Printed: 1:2 2:3 4:5 5:6 7:8 8:9 | if( !int_int_map_is_end( itr ) ) |
+ | | printf( |
+ | // Iteration. | "%d:%d ", |
+ | for( | itr.data->key, |
+ | int_int_map_itr itr = vt_first( &our_map ); | itr.data->val |
+ | !vt_is_end( itr ); | ); |
+ | itr = vt_next( itr ) | } |
+ | ) | // Printed: 1:2 2:3 4:5 5:6 7:8 8:9 |
+ | printf( | |
+ | "%d:%d ", | // Iteration. |
+ | itr.data->key, | for( |
+ | itr.data->val | int_int_map_itr itr = |
+ | ); | int_int_map_first( &our_map ); |
+ | // Printed: 2:3 4:5 7:8 1:2 5:6 8:9 | !int_int_map_is_end( itr ); |
+ | | itr = int_int_map_next( itr ) |
+ | vt_cleanup( &our_map ); | ) |
+ | } | printf( |
+ | | "%d:%d ", |
+ | | itr.data->key, |
+ | | itr.data->val |
+ | | ); |
+ | | // Printed: 2:3 4:5 7:8 1:2 5:6 8:9 |
+ | | |
+ | | int_int_map_cleanup( &our_map ); |
+ | | } |
+ | | |
+ +---------------------------------------------------------+----------------------------------------------------------+
+
+API:
+
+ Instantiating a hash table template:
+
+ Create a new hash table type in the following manner:
+
+ #define NAME <your chosen type name>
+ #define KEY_TY <type>
+ #include "verstable.h"
+
+ The NAME macro specifies the name of hash table type that the library will declare, the prefix for the functions
+ associated with it, and the prefix for the associated iterator type.
+
+ The KEY_TY macro specifies the key type.
+
+ In C99, it is also always necessary to define HASH_FN and CMPR_FN (see below) before including the header.
+
+ The following macros may also be defined before including the header:
+
+ #define VAL_TY <type>
+
+ The type of the value associated with each key.
+ If this macro is defined, the hash table acts as a map associating keys with values.
+ Otherwise, it acts as a set containing only keys.
+
+ #define HASH_FN <function name>
+
+ The name of the existing function used to hash each key.
+ The function should have the signature uint64_t ( KEY_TY key ) and return a 64-bit hash code.
+ For best performance, the hash function should provide a high level of entropy across all bits.
+ There are two default hash functions: vt_hash_integer for all integer types up to 64 bits in size, and
+ vt_hash_string for NULL-terminated strings (i.e. char *).
+ When KEY_TY is one of such types and the compiler is in C11 mode or later, HASH_FN may be left undefined, in
+ which case the appropriate default function is inferred from KEY_TY.
+ Otherwise, HASH_FN must be defined.
+
+ #define CMPR_FN <function name>
+
+ The name of the existing function used to compare two keys.
+ The function should have the signature bool ( KEY_TY key_1, KEY_TY key_2 ) and return true if the two keys are
+ equal.
+ There are two default comparison functions: vt_cmpr_integer for all integer types up to 64 bits in size, and
+ vt_cmpr_string for NULL-terminated strings (i.e. char *).
+ As with the default hash functions, in C11 or later the appropriate default comparison function is inferred if
+ KEY_TY is one of such types and CMPR_FN is left undefined.
+ Otherwise, CMPR_FN must be defined.
+
+ #define MAX_LOAD <floating point value>
+
+ The floating-point load factor at which the hash table automatically doubles the size of its internal buckets
+ array.
+ The default is 0.9, i.e. 90%.
+
+ #define KEY_DTOR_FN <function name>
+
+ The name of the existing destructor function, with the signature void ( KEY_TY key ), called on a key when it is
+ erased from the table or replaced by a newly inserted key.
+ The API functions that may call the key destructor are NAME_insert, NAME_erase, NAME_erase_itr, NAME_clear,
+ and NAME_cleanup.
+
+ #define VAL_DTOR_FN <function name>
+
+ The name of the existing destructor function, with the signature void ( VAL_TY val ), called on a value when it
+ is erased from the table or replaced by a newly inserted value.
+ The API functions that may call the value destructor are NAME_insert, NAME_erase, NAME_erase_itr, NAME_clear,
+ and NAME_cleanup.
+
+ #define CTX_TY <type>
+
+ The type of the hash table type's ctx (context) member.
+ This member only exists if CTX_TY was defined.
+ It is intended to be used in conjunction with MALLOC_FN and FREE_FN (see below).
+
+ #define MALLOC_FN <function name>
+
+ The name of the existing function used to allocate memory.
+ If CTX_TY was defined, the signature should be void *( size_t size, CTX_TY *ctx ), where size is the number of
+ bytes to allocate and ctx points to the table's ctx member.
+ Otherwise, the signature should be void *( size_t size ).
+ The default wraps stdlib.h's malloc.
+
+ #define FREE_FN <function name>
+
+ The name of the existing function used to free memory.
+ If CTX_TY was defined, the signature should be void ( void *ptr, size_t size, CTX_TY *ctx ), where ptr points to
+ the memory to free, size is the number of bytes that were allocated, and ctx points to the table's ctx member.
+ Otherwise, the signature should be void ( void *ptr, size_t size ).
+ The default wraps stdlib.h's free.
+
+ #define HEADER_MODE
+ #define IMPLEMENTATION_MODE
+
+ By default, all hash table functions are defined as static inline functions, the intent being that a given hash
+ table template should be instantiated once per translation unit; for best performance, this is the recommended
+ way to use the library.
+ However, it is also possible separate the struct definitions and function declarations from the function
+ definitions such that one implementation can be shared across all translation units (as in a traditional header
+ and source file pair).
+ In that case, instantiate a template wherever it is needed by defining HEADER_MODE, along with only NAME,
+ KEY_TY, and (optionally) VAL_TY, CTX_TY, and header guards, and including the library, e.g.:
+
+ #ifndef INT_INT_MAP_H
+ #define INT_INT_MAP_H
+ #define NAME int_int_map
+ #define KEY_TY int
+ #define VAL_TY int
+ #define HEADER_MODE
+ #include "verstable.h"
+ #endif
+
+ In one source file, define IMPLEMENTATION_MODE, along with NAME, KEY_TY, and any of the aforementioned optional
+ macros, and include the library, e.g.:
+
+ #define NAME int_int_map
+ #define KEY_TY int
+ #define VAL_TY int
+ #define HASH_FN vt_hash_integer // C99.
+ #define CMPR_FN vt_cmpr_integer // C99.
+ #define MAX_LOAD 0.8
+ #define IMPLEMENTATION_MODE
+ #include "verstable.h"
+
+ Including the library automatically undefines all the aforementioned macros after they have been used to instantiate
+ the template.
+
+ Functions:
+
+ The functions associated with a hash table type are all prefixed with the name the user supplied via the NAME macro.
+ In C11 and later, the generic "vt_"-prefixed macros may be used to automatically select the correct version of the
+ specified function based on the arguments.
+
+ void NAME_init( NAME *table )
+ void NAME_init( NAME *table, CTX_TY ctx )
+ // C11 generic macro: vt_init.
+
+ Initializes the table for use.
+ If CTX_TY was defined, ctx sets the table's ctx member.
+
+ bool NAME_init_clone( NAME *table, NAME *source )
+ bool NAME_init_clone( NAME *table, NAME *source, CTX_TY ctx )
+ // C11 generic macro: vt_init_clone.
+
+ Initializes the table as a shallow copy of the specified source table.
+ If CTX_TY was defined, ctx sets the table's ctx member.
+ Returns false in the case of memory allocation failure.
+
+ size_t NAME_size( NAME *table ) // C11 generic macro: vt_size.
+
+ Returns the number of keys currently in the table.
+
+ size_t NAME_bucket_count( NAME *table ) // C11 generic macro: vt_bucket_count.
+
+ Returns the table's current bucket count.
+
+ NAME_itr NAME_insert( NAME *table, KEY_TY key )
+ NAME_itr NAME_insert( NAME *table, KEY_TY key, VAL_TY val )
+ // C11 generic macro: vt_insert.
+
+ Inserts the specified key (and value, if VAL_TY was defined) into the hash table.
+ If the same key already exists, then the new key (and value) replaces the existing key (and value).
+ Returns an iterator to the new key, or an end iterator in the case of memory allocation failure.
+
+ NAME_itr NAME_get_or_insert( NAME *table, KEY_TY key )
+ NAME_itr NAME_get_or_insert( NAME *table, KEY_TY key, VAL_TY val )
+ // C11 generic macro: vt_get_or_insert.
+
+ Inserts the specified key (and value, if VAL_TY was defined) if it does not already exist in the table.
+ Returns an iterator to the new key if it was inserted, or an iterator to the existing key, or an end iterator if
+ the key did not exist but the new key could not be inserted because of memory allocation failure.
+ Determine whether the key was inserted by comparing the table's size before and after the call.
+
+ NAME_itr NAME_get( NAME *table, KEY_TY key ) // C11 generic macro: vt_get.
+
+ Returns a iterator to the specified key, or an end iterator if no such key exists.
+
+ bool NAME_erase( NAME *table, KEY_TY key ) // C11 generic macro: vt_erase.
+
+ Erases the specified key (and associated value, if VAL_TY was defined), if it exists.
+ Returns true if a key was erased.
+
+ NAME_itr NAME_erase_itr( NAME *table, NAME_itr itr ) // C11 generic macro: vt_erase_itr.
+
+ Erases the key (and associated value, if VAL_TY was defined) pointed to by the specified iterator.
+ Returns an iterator to the next key in the table, or an end iterator if the erased key was the last one.
+
+ bool NAME_reserve( NAME *table, size_t size ) // C11 generic macro: vt_reserve.
+
+ Ensures that the bucket count is large enough to support the specified key count (i.e. size) without rehashing.
+ Returns false if unsuccessful due to memory allocation failure.
+
+ bool NAME_shrink( NAME *table ) // C11 generic macro: vt_shrink.
+
+ Shrinks the bucket count to best accommodate the current size.
+ Returns false if unsuccessful due to memory allocation failure.
+
+ NAME_itr NAME_first( NAME *table ) // C11 generic macro: vt_first.
+
+ Returns an iterator to the first key in the table, or an end iterator if the table is empty.
+
+ bool NAME_is_end( NAME *table, NAME_itr itr ) // C11 generic macro: vt_is_end.
+
+ Returns true if the iterator is an end iterator.
+
+ NAME_itr NAME_next( NAME_itr itr ) // C11 generic macro: vt_next.
+
+ Returns an iterator to the key after the one pointed to by the specified iterator, or an end iterator if the
+ specified iterator points to the last key in the table.
+
+ void NAME_clear( NAME *table ) // C11 generic macro: vt_clear.
+
+ Erases all keys (and values, if VAL_TY was defined) in the table.
+
+ void NAME_cleanup( NAME *table ) // C11 generic macro: vt_cleanup.
+
+ Erases all keys (and values, if VAL_TY was defined) in the table, frees all memory associated with it, and
+ initializes it for reuse.
+
+ Iterators:
+
+ Access the key (and value, if VAL_TY was defined) that an iterator points to using the NAME_itr struct's data
+ member:
+
+ itr.data->key
+ itr.data->val
+
+ Functions that may insert new keys (NAME_insert and NAME_get_or_insert), erase keys (NAME_erase and NAME_erase_itr),
+ or reallocate the internal bucket array (NAME_reserve and NAME_shrink) invalidate all exiting iterators.
+ To delete keys during iteration and resume iterating, use the return value of NAME_erase_itr.
+
+Version history:
+
+ 18/06/2024 2.1.1: Fixed a bug affecting iteration on big-endian platforms under MSVC.
+ 27/05/2024 2.1.0: Replaced the Murmur3 mixer with the fast-hash mixer as the default integer hash function.
+ Fixed a bug that could theoretically cause a crash on rehash (triggerable in testing using
+ NAME_shrink with a maximum load factor significantly higher than 1.0).
+ 06/02/2024 2.0.0: Improved custom allocator support by introducing the CTX_TY option and allowing user-supplied free
+ functions to receive the allocation size.
+ Improved documentation.
+ Introduced various optimizations, including storing the buckets-array size mask instead of the
+ bucket count, eliminating empty-table checks, combining the buckets memory and metadata memory into
+ one allocation, and adding branch prediction macros.
+ Fixed a bug that caused a key to be used after destruction during erasure.
+ 12/12/2023 1.0.0: Initial release.
+
+License (MIT):
+
+ Copyright (c) 2023-2024 Jackson L. Allan
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/* Common header section */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+#ifndef VERSTABLE_H
+#define VERSTABLE_H
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+// Two-way concatenation macro.
+#define VT_CAT_( a, b ) a##b
+#define VT_CAT( a, b ) VT_CAT_( a, b )
+
+// Branch optimization macros.
+#ifdef __GNUC__
+#define VT_LIKELY( expression ) __builtin_expect( (bool)( expression ), true )
+#define VT_UNLIKELY( expression ) __builtin_expect( (bool)( expression ), false )
+#else
+#define VT_LIKELY( expression ) ( expression )
+#define VT_UNLIKELY( expression ) ( expression )
+#endif
+
+// Masks for manipulating and extracting data from a bucket's uint16_t metadatum.
+#define VT_EMPTY 0x0000
+#define VT_HASH_FRAG_MASK 0xF000 // 0b1111000000000000.
+#define VT_IN_HOME_BUCKET_MASK 0x0800 // 0b0000100000000000.
+#define VT_DISPLACEMENT_MASK 0x07FF // 0b0000011111111111, also denotes the displacement limit. Set to VT_LOAD to 1.0
+ // to test proper handling of encroachment on the displacement limit during
+ // inserts.
+
+// Extracts a hash fragment from a uint64_t hash code.
+// We take the highest four bits so that keys that map (via modulo) to the same bucket have distinct hash fragments.
+static inline uint16_t vt_hashfrag( uint64_t hash )
+{
+ return ( hash >> 48 ) & VT_HASH_FRAG_MASK;
+}
+
+// Standard quadratic probing formula that guarantees that all buckets are visited when the bucket count is a power of
+// two (at least in theory, because the displacement limit could terminate the search early when the bucket count is
+// high).
+static inline size_t vt_quadratic( uint16_t displacement )
+{
+ return ( (size_t)displacement * displacement + displacement ) / 2;
+}
+
+#define VT_MIN_NONZERO_BUCKET_COUNT 8 // Must be a power of two.
+
+// Function to find the left-most non-zero uint16_t in a uint64_t.
+// This function is used when we scan four buckets at a time while iterating and relies on compiler intrinsics wherever
+// possible.
+
+#if defined( __GNUC__ ) && ULLONG_MAX == 0xFFFFFFFFFFFFFFFF
+
+static inline int vt_first_nonzero_uint16( uint64_t val )
+{
+ const uint16_t endian_checker = 0x0001;
+ if( *(const char *)&endian_checker ) // Little-endian (the compiler will optimize away the check at -O1 and above).
+ return __builtin_ctzll( val ) / 16;
+
+ return __builtin_clzll( val ) / 16;
+}
+
+#elif defined( _MSC_VER ) && ( defined( _M_X64 ) || defined( _M_ARM64 ) )
+
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward64)
+#pragma intrinsic(_BitScanReverse64)
+
+static inline int vt_first_nonzero_uint16( uint64_t val )
+{
+ unsigned long result;
+
+ const uint16_t endian_checker = 0x0001;
+ if( *(const char *)&endian_checker )
+ _BitScanForward64( &result, val );
+ else
+ {
+ _BitScanReverse64( &result, val );
+ result = 63 - result;
+ }
+
+ return result / 16;
+}
+
+#else
+
+static inline int vt_first_nonzero_uint16( uint64_t val )
+{
+ int result = 0;
+
+ uint32_t half;
+ memcpy( &half, &val, sizeof( uint32_t ) );
+ if( !half )
+ result += 2;
+
+ uint16_t quarter;
+ memcpy( &quarter, (char *)&val + result * sizeof( uint16_t ), sizeof( uint16_t ) );
+ if( !quarter )
+ result += 1;
+
+ return result;
+}
+
+#endif
+
+// When the bucket count is zero, setting the metadata pointer to point to a VT_EMPTY placeholder, rather than NULL,
+// allows us to avoid checking for a zero bucket count during insertion and lookup.
+static const uint16_t vt_empty_placeholder_metadatum = VT_EMPTY;
+
+// Default hash and comparison functions.
+
+// Fast-hash, as described by https://jonkagstrom.com/bit-mixer-construction and
+// https://code.google.com/archive/p/fast-hash.
+// In testing, this hash function provided slightly better performance than the Murmur3 mixer.
+static inline uint64_t vt_hash_integer( uint64_t key )
+{
+ key ^= key >> 23;
+ key *= 0x2127599bf4325c37ull;
+ key ^= key >> 47;
+ return key;
+}
+
+// FNV-1a.
+static inline uint64_t vt_hash_string( char *key )
+{
+ uint64_t hash = 0xcbf29ce484222325ull;
+ while( *key )
+ hash = ( (unsigned char)*key++ ^ hash ) * 0x100000001b3ull;
+
+ return hash;
+}
+
+static inline bool vt_cmpr_integer( uint64_t key_1, uint64_t key_2 )
+{
+ return key_1 == key_2;
+}
+
+static inline bool vt_cmpr_string( char *key_1, char *key_2 )
+{
+ return strcmp( key_1, key_2 ) == 0;
+}
+
+// Default allocation and free functions.
+
+static inline void *vt_malloc( size_t size )
+{
+ return malloc( size );
+}
+
+static inline void vt_free( void *ptr, size_t size )
+{
+ (void)size;
+ free( ptr );
+}
+
+static inline void *vt_malloc_with_ctx( size_t size, void *ctx )
+{
+ (void)ctx;
+ return malloc( size );
+}
+
+static inline void vt_free_with_ctx( void *ptr, size_t size, void *ctx )
+{
+ (void)size;
+ (void)ctx;
+ free( ptr );
+}
+
+// The rest of the common header section pertains to the C11 generic macro API.
+// This interface is based on the extendible-_Generic mechanism documented in detail at
+// https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md.
+// In summary, instantiating a template also defines wrappers for the template's types and functions with names in the
+// pattern of vt_table_NNNN and vt_init_NNNN, where NNNN is an automatically generated integer unique to the template
+// instance in the current translation unit.
+// These wrappers plug in to _Generic-based API macros, which use preprocessor magic to automatically generate _Generic
+// slots for every existing template instance.
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined( VT_NO_C11_GENERIC_API )
+
+// Octal counter that supports up to 511 hash table templates.
+#define VT_TEMPLATE_COUNT_D1 0 // Digit 1, i.e. least significant digit.
+#define VT_TEMPLATE_COUNT_D2 0
+#define VT_TEMPLATE_COUNT_D3 0
+
+// Four-way concatenation macro.
+#define VT_CAT_4_( a, b, c, d ) a##b##c##d
+#define VT_CAT_4( a, b, c, d ) VT_CAT_4_( a, b, c, d )
+
+// Provides the current value of the counter as a three-digit octal number preceded by 0.
+#define VT_TEMPLATE_COUNT VT_CAT_4( 0, VT_TEMPLATE_COUNT_D3, VT_TEMPLATE_COUNT_D2, VT_TEMPLATE_COUNT_D1 )
+
+// _Generic-slot generation macros.
+
+#define VT_GENERIC_SLOT( ty, fn, n ) , VT_CAT( ty, n ): VT_CAT( fn, n )
+#define VT_R1_0( ty, fn, d3, d2 )
+#define VT_R1_1( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 0 ) )
+#define VT_R1_2( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 1 ) ) VT_R1_1( ty, fn, d3, d2 )
+#define VT_R1_3( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 2 ) ) VT_R1_2( ty, fn, d3, d2 )
+#define VT_R1_4( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 3 ) ) VT_R1_3( ty, fn, d3, d2 )
+#define VT_R1_5( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 4 ) ) VT_R1_4( ty, fn, d3, d2 )
+#define VT_R1_6( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 5 ) ) VT_R1_5( ty, fn, d3, d2 )
+#define VT_R1_7( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 6 ) ) VT_R1_6( ty, fn, d3, d2 )
+#define VT_R1_8( ty, fn, d3, d2 ) VT_GENERIC_SLOT( ty, fn, VT_CAT_4( 0, d3, d2, 7 ) ) VT_R1_7( ty, fn, d3, d2 )
+#define VT_R2_0( ty, fn, d3 )
+#define VT_R2_1( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 0 )
+#define VT_R2_2( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 1 ) VT_R2_1( ty, fn, d3 )
+#define VT_R2_3( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 2 ) VT_R2_2( ty, fn, d3 )
+#define VT_R2_4( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 3 ) VT_R2_3( ty, fn, d3 )
+#define VT_R2_5( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 4 ) VT_R2_4( ty, fn, d3 )
+#define VT_R2_6( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 5 ) VT_R2_5( ty, fn, d3 )
+#define VT_R2_7( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 6 ) VT_R2_6( ty, fn, d3 )
+#define VT_R2_8( ty, fn, d3 ) VT_R1_8( ty, fn, d3, 7 ) VT_R2_7( ty, fn, d3 )
+#define VT_R3_0( ty, fn )
+#define VT_R3_1( ty, fn ) VT_R2_8( ty, fn, 0 )
+#define VT_R3_2( ty, fn ) VT_R2_8( ty, fn, 1 ) VT_R3_1( ty, fn )
+#define VT_R3_3( ty, fn ) VT_R2_8( ty, fn, 2 ) VT_R3_2( ty, fn )
+#define VT_R3_4( ty, fn ) VT_R2_8( ty, fn, 3 ) VT_R3_3( ty, fn )
+#define VT_R3_5( ty, fn ) VT_R2_8( ty, fn, 4 ) VT_R3_4( ty, fn )
+#define VT_R3_6( ty, fn ) VT_R2_8( ty, fn, 5 ) VT_R3_5( ty, fn )
+#define VT_R3_7( ty, fn ) VT_R2_8( ty, fn, 6 ) VT_R3_6( ty, fn )
+
+#define VT_GENERIC_SLOTS( ty, fn ) \
+VT_CAT( VT_R1_, VT_TEMPLATE_COUNT_D1 )( ty, fn, VT_TEMPLATE_COUNT_D3, VT_TEMPLATE_COUNT_D2 ) \
+VT_CAT( VT_R2_, VT_TEMPLATE_COUNT_D2 )( ty, fn, VT_TEMPLATE_COUNT_D3 ) \
+VT_CAT( VT_R3_, VT_TEMPLATE_COUNT_D3 )( ty, fn ) \
+
+// Actual generic API macros.
+
+// vt_init must be handled as a special case because it could take one or two arguments, depending on whether CTX_TY
+// was defined.
+#define VT_ARG_3( _1, _2, _3, ... ) _3
+#define vt_init( ... ) VT_ARG_3( __VA_ARGS__, vt_init_with_ctx, vt_init_without_ctx, )( __VA_ARGS__ )
+#define vt_init_without_ctx( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_init_ ) )( table )
+#define vt_init_with_ctx( table, ... ) _Generic( *( table ) \
+ VT_GENERIC_SLOTS( vt_table_, vt_init_ ) \
+)( table, __VA_ARGS__ ) \
+
+#define vt_init_clone( table, ... ) _Generic( *( table ) \
+ VT_GENERIC_SLOTS( vt_table_, vt_init_clone_ ) \
+)( table, __VA_ARGS__ ) \
+
+#define vt_size( table )_Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_size_ ) )( table )
+
+#define vt_bucket_count( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_bucket_count_ ) )( table )
+
+#define vt_is_end( itr ) _Generic( itr VT_GENERIC_SLOTS( vt_table_itr_, vt_is_end_ ) )( itr )
+
+#define vt_insert( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_insert_ ) )( table, __VA_ARGS__ )
+
+#define vt_get_or_insert( table, ... ) _Generic( *( table ) \
+ VT_GENERIC_SLOTS( vt_table_, vt_get_or_insert_ ) \
+)( table, __VA_ARGS__ ) \
+
+#define vt_get( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_get_ ) )( table, __VA_ARGS__ )
+
+#define vt_erase( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_erase_ ) )( table, __VA_ARGS__ )
+
+#define vt_next( itr ) _Generic( itr VT_GENERIC_SLOTS( vt_table_itr_, vt_next_ ) )( itr )
+
+#define vt_erase_itr( table, ... ) _Generic( *( table ) \
+ VT_GENERIC_SLOTS( vt_table_, vt_erase_itr_ ) \
+)( table, __VA_ARGS__ ) \
+
+#define vt_reserve( table, ... ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_reserve_ ) )( table, __VA_ARGS__ )
+
+#define vt_shrink( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_shrink_ ) )( table )
+
+#define vt_first( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_first_ ) )( table )
+
+#define vt_clear( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_clear_ ) )( table )
+
+#define vt_cleanup( table ) _Generic( *( table ) VT_GENERIC_SLOTS( vt_table_, vt_cleanup_ ) )( table )
+
+#endif
+
+#endif
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/* Prefixed structs */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+#ifndef IMPLEMENTATION_MODE
+
+typedef struct
+{
+ KEY_TY key;
+ #ifdef VAL_TY
+ VAL_TY val;
+ #endif
+} VT_CAT( NAME, _bucket );
+
+typedef struct
+{
+ VT_CAT( NAME, _bucket ) *data;
+ uint16_t *metadatum;
+ uint16_t *metadata_end; // Iterators carry an internal end pointer so that NAME_is_end does not need the table to be
+ // passed in as an argument.
+ // This also allows for the zero-bucket-count check to occur once in NAME_first, rather than
+ // repeatedly in NAME_is_end.
+ size_t home_bucket; // SIZE_MAX if home bucket is unknown.
+} VT_CAT( NAME, _itr );
+
+typedef struct
+{
+ size_t key_count;
+ size_t buckets_mask; // Rather than storing the bucket count directly, we store the bit mask used to reduce a hash
+ // code or displacement-derived bucket index to the buckets array, i.e. the bucket count minus
+ // one.
+ // Consequently, a zero bucket count (i.e. when .metadata points to the placeholder) constitutes
+ // a special case, represented by all bits unset (i.e. zero).
+ VT_CAT( NAME, _bucket ) *buckets;
+ uint16_t *metadata; // As described above, each metadatum consists of a 4-bit hash-code fragment (X), a 1-bit flag
+ // indicating whether the key in this bucket begins a chain associated with the bucket (Y), and
+ // an 11-bit value indicating the quadratic displacement of the next key in the chain (Z):
+ // XXXXYZZZZZZZZZZZ.
+ #ifdef CTX_TY
+ CTX_TY ctx;
+ #endif
+} NAME;
+
+#endif
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/* Function prototypes */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+#if defined( HEADER_MODE ) || defined( IMPLEMENTATION_MODE )
+#define VT_API_FN_QUALIFIERS
+#else
+#define VT_API_FN_QUALIFIERS static inline
+#endif
+
+#ifndef IMPLEMENTATION_MODE
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _init )(
+ NAME *
+ #ifdef CTX_TY
+ , CTX_TY
+ #endif
+);
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _init_clone )(
+ NAME *,
+ NAME *
+ #ifdef CTX_TY
+ , CTX_TY
+ #endif
+);
+
+VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _size )( NAME * );
+
+VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _bucket_count )( NAME * );
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _is_end )( VT_CAT( NAME, _itr ) );
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert )(
+ NAME *,
+ KEY_TY
+ #ifdef VAL_TY
+ , VAL_TY
+ #endif
+);
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get_or_insert )(
+ NAME *,
+ KEY_TY
+ #ifdef VAL_TY
+ , VAL_TY
+ #endif
+);
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get )(
+ NAME *table,
+ KEY_TY key
+);
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase )( NAME *, KEY_TY );
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _next )( VT_CAT( NAME, _itr ) );
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _reserve )( NAME *, size_t );
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _shrink )( NAME * );
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _first )( NAME * );
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _clear )( NAME * );
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _cleanup )( NAME * );
+
+// Not an API function, but must be prototyped anyway because it is called by the inline NAME_erase_itr below.
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw ) ( NAME *, VT_CAT( NAME, _itr ) );
+
+// Erases the key pointed to by itr and returns an iterator to the next key in the table.
+// This function must be inlined to ensure that the compiler optimizes away the NAME_fast_forward call if the returned
+// iterator is discarded.
+#ifdef __GNUC__
+static inline __attribute__((always_inline))
+#elif defined( _MSC_VER )
+static __forceinline
+#else
+static inline
+#endif
+VT_CAT( NAME, _itr ) VT_CAT( NAME, _erase_itr )( NAME *table, VT_CAT( NAME, _itr ) itr )
+{
+ if( VT_CAT( NAME, _erase_itr_raw )( table, itr ) )
+ return VT_CAT( NAME, _next )( itr );
+
+ return itr;
+}
+
+#endif
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/* Function implementations */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+#ifndef HEADER_MODE
+
+// Default settings.
+
+#ifndef MAX_LOAD
+#define MAX_LOAD 0.9
+#endif
+
+#if !defined( MALLOC ) || !defined( FREE )
+#include <stdlib.h>
+#endif
+
+#ifndef MALLOC_FN
+#ifdef CTX_TY
+#define MALLOC_FN vt_malloc_with_ctx
+#else
+#define MALLOC_FN vt_malloc
+#endif
+#endif
+
+#ifndef FREE_FN
+#ifdef CTX_TY
+#define FREE_FN vt_free_with_ctx
+#else
+#define FREE_FN vt_free
+#endif
+#endif
+
+#ifndef HASH_FN
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#ifdef _MSC_VER // In MSVC, the compound literal in the _Generic triggers a warning about unused local variables at /W4.
+#define HASH_FN \
+_Pragma( "warning( push )" ) \
+_Pragma( "warning( disable: 4189 )" ) \
+_Generic( ( KEY_TY ){ 0 }, char *: vt_hash_string, default: vt_hash_integer ) \
+_Pragma( "warning( pop )" )
+#else
+#define HASH_FN _Generic( ( KEY_TY ){ 0 }, char *: vt_hash_string, default: vt_hash_integer )
+#endif
+#else
+#error Hash function inference is only available in C11 and later. In C99, you need to define HASH_FN manually to \
+vt_hash_integer, vt_hash_string, or your own custom function with the signature uint64_t ( KEY_TY ).
+#endif
+#endif
+
+#ifndef CMPR_FN
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#ifdef _MSC_VER
+#define CMPR_FN \
+_Pragma( "warning( push )" ) \
+_Pragma( "warning( disable: 4189 )" ) \
+_Generic( ( KEY_TY ){ 0 }, char *: vt_cmpr_string, default: vt_cmpr_integer ) \
+_Pragma( "warning( pop )" )
+#else
+#define CMPR_FN _Generic( ( KEY_TY ){ 0 }, char *: vt_cmpr_string, default: vt_cmpr_integer )
+#endif
+#else
+#error Comparison function inference is only available in C11 and later. In C99, you need to define CMPR_FN manually \
+to vt_cmpr_integer, vt_cmpr_string, or your own custom function with the signature bool ( KEY_TY, KEY_TY ).
+#endif
+#endif
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _init )(
+ NAME *table
+ #ifdef CTX_TY
+ , CTX_TY ctx
+ #endif
+)
+{
+ table->key_count = 0;
+ table->buckets_mask = 0x0000000000000000ull;
+ table->buckets = NULL;
+ table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum;
+ #ifdef CTX_TY
+ table->ctx = ctx;
+ #endif
+}
+
+// For efficiency, especially in the case of a small table, the buckets array and metadata share the same dynamic memory
+// allocation:
+// +-----------------------------+-----+----------------+--------+
+// | Buckets | Pad | Metadata | Excess |
+// +-----------------------------+-----+----------------+--------+
+// Any allocated metadata array requires four excess elements to ensure that iteration functions, which read four
+// metadata at a time, never read beyond the end of it.
+// This function returns the offset of the beginning of the metadata, i.e. the size of the buckets array plus the
+// (usually zero) padding.
+// It assumes that the bucket count is not zero.
+static inline size_t VT_CAT( NAME, _metadata_offset )( NAME *table )
+{
+ // Use sizeof, rather than alignof, for C99 compatibility.
+ return ( ( ( table->buckets_mask + 1 ) * sizeof( VT_CAT( NAME, _bucket ) ) + sizeof( uint16_t ) - 1 ) /
+ sizeof( uint16_t ) ) * sizeof( uint16_t );
+}
+
+// Returns the total allocation size, including the buckets array, padding, metadata, and excess metadata.
+// As above, this function assumes that the bucket count is not zero.
+static inline size_t VT_CAT( NAME, _total_alloc_size )( NAME *table )
+{
+ return VT_CAT( NAME, _metadata_offset )( table ) + ( table->buckets_mask + 1 + 4 ) * sizeof( uint16_t );
+}
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _init_clone )(
+ NAME *table,
+ NAME *source
+ #ifdef CTX_TY
+ , CTX_TY ctx
+ #endif
+)
+{
+ table->key_count = source->key_count;
+ table->buckets_mask = source->buckets_mask;
+ #ifdef CTX_TY
+ table->ctx = ctx;
+ #endif
+
+ if( !source->buckets_mask )
+ {
+ table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum;
+ table->buckets = NULL;
+ return true;
+ }
+
+ void *allocation = MALLOC_FN(
+ VT_CAT( NAME, _total_alloc_size )( table )
+ #ifdef CTX_TY
+ , &table->ctx
+ #endif
+ );
+
+ if( VT_UNLIKELY( !allocation ) )
+ return false;
+
+ table->buckets = (VT_CAT( NAME, _bucket ) *)allocation;
+ table->metadata = (uint16_t *)( (unsigned char *)allocation + VT_CAT( NAME, _metadata_offset )( table ) );
+ memcpy( allocation, source->buckets, VT_CAT( NAME, _total_alloc_size )( table ) );
+
+ return true;
+}
+
+VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _size )( NAME *table )
+{
+ return table->key_count;
+}
+
+VT_API_FN_QUALIFIERS size_t VT_CAT( NAME, _bucket_count )( NAME *table )
+{
+ // If the bucket count is zero, buckets_mask will be zero, not the bucket count minus one.
+ // We account for this special case by adding (bool)buckets_mask rather than one.
+ return table->buckets_mask + (bool)table->buckets_mask;
+}
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _is_end )( VT_CAT( NAME, _itr ) itr )
+{
+ return itr.metadatum == itr.metadata_end;
+}
+
+// Finds the earliest empty bucket in which a key belonging to home_bucket can be placed, assuming that home_bucket
+// is already occupied.
+// The reason to begin the search at home_bucket, rather than the end of the existing chain, is that keys deleted from
+// other chains might have freed up buckets that could fall in this chain before the final key.
+// Returns true if an empty bucket within the range of the displacement limit was found, in which case the final two
+// pointer arguments contain the index of the empty bucket and its quadratic displacement from home_bucket.
+static inline bool VT_CAT( NAME, _find_first_empty )(
+ NAME *table,
+ size_t home_bucket,
+ size_t *empty,
+ uint16_t *displacement
+)
+{
+ *displacement = 1;
+ size_t linear_dispacement = 1;
+
+ while( true )
+ {
+ *empty = ( home_bucket + linear_dispacement ) & table->buckets_mask;
+ if( table->metadata[ *empty ] == VT_EMPTY )
+ return true;
+
+ if( VT_UNLIKELY( ++*displacement == VT_DISPLACEMENT_MASK ) )
+ return false;
+
+ linear_dispacement += *displacement;
+ }
+}
+
+// Finds the key in the chain beginning in home_bucket after which to link a new key with displacement_to_empty
+// quadratic displacement and returns the index of the bucket containing that key.
+// Although the new key could simply be linked to the end of the chain, keeping the chain ordered by displacement
+// theoretically improves cache locality during lookups.
+static inline size_t VT_CAT( NAME, _find_insert_location_in_chain )(
+ NAME *table,
+ size_t home_bucket,
+ uint16_t displacement_to_empty
+)
+{
+ size_t candidate = home_bucket;
+ while( true )
+ {
+ uint16_t displacement = table->metadata[ candidate ] & VT_DISPLACEMENT_MASK;
+
+ if( displacement > displacement_to_empty )
+ return candidate;
+
+ candidate = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask;
+ }
+}
+
+// Frees up a bucket occupied by a key not belonging there so that a new key belonging there can be placed there as the
+// beginning of a new chain.
+// This requires:
+// * Finding the previous key in the chain to which the occupying key belongs by rehashing it and then traversing the
+// chain.
+// * Disconnecting the key from the chain.
+// * Finding the appropriate empty bucket to which to move the key.
+// * Moving the key (and value) data to the empty bucket.
+// * Re-linking the key to the chain.
+// Returns true if the eviction succeeded, or false if no empty bucket to which to evict the occupying key could be
+// found within the displacement limit.
+static inline bool VT_CAT( NAME, _evict )( NAME *table, size_t bucket )
+{
+ // Find the previous key in chain.
+ size_t home_bucket = HASH_FN( table->buckets[ bucket ].key ) & table->buckets_mask;
+ size_t prev = home_bucket;
+ while( true )
+ {
+ size_t next = ( home_bucket + vt_quadratic( table->metadata[ prev ] & VT_DISPLACEMENT_MASK ) ) &
+ table->buckets_mask;
+
+ if( next == bucket )
+ break;
+
+ prev = next;
+ }
+
+ // Disconnect the key from chain.
+ table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | ( table->metadata[ bucket ] &
+ VT_DISPLACEMENT_MASK );
+
+ // Find the empty bucket to which to move the key.
+ size_t empty;
+ uint16_t displacement;
+ if( VT_UNLIKELY( !VT_CAT( NAME, _find_first_empty )( table, home_bucket, &empty, &displacement ) ) )
+ return false;
+
+ // Find the key in the chain after which to link the moved key.
+ prev = VT_CAT( NAME, _find_insert_location_in_chain )( table, home_bucket, displacement );
+
+ // Move the key (and value) data.
+ table->buckets[ empty ] = table->buckets[ bucket ];
+
+ // Re-link the key to the chain from its new bucket.
+ table->metadata[ empty ] = ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) | ( table->metadata[ prev ] &
+ VT_DISPLACEMENT_MASK );
+ table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | displacement;
+
+ return true;
+}
+
+// Returns an end iterator, i.e. any iterator for which .metadatum == .metadata_end.
+// This function just cleans up the library code in functions that return an end iterator as a failure indicator.
+static inline VT_CAT( NAME, _itr ) VT_CAT( NAME, _end_itr )( void )
+{
+ VT_CAT( NAME, _itr ) itr = { NULL, NULL, NULL, 0 };
+ return itr;
+}
+
+// Inserts a key, optionally replacing the existing key if it already exists.
+// There are two main cases that must be handled:
+// * If the key's home bucket is empty or occupied by a key that does not belong there, then the key is inserted there,
+// evicting the occupying key if there is one.
+// * Otherwise, the chain of keys beginning at the home bucket is (if unique is false) traversed in search of a matching
+// key.
+// If none is found, then the new key is inserted at the earliest available bucket, per quadratic probing from the
+// home bucket, and then linked to the chain in a manner that maintains its quadratic order.
+// The unique argument tells the function whether to skip searching for the key before inserting it (on rehashing, this
+// step is unnecessary).
+// The replace argument tells the function whether to replace an existing key.
+// If replace is true, the function returns an iterator to the inserted key, or an end iterator if the key was not
+// inserted because of the maximum load factor or displacement limit constraints.
+// If replace is false, then the return value is as described above, except that if the key already exists, the function
+// returns an iterator to the existing key.
+static inline VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert_raw )(
+ NAME *table,
+ KEY_TY key,
+ #ifdef VAL_TY
+ VAL_TY *val,
+ #endif
+ bool unique,
+ bool replace
+)
+{
+ uint64_t hash = HASH_FN( key );
+ uint16_t hashfrag = vt_hashfrag( hash );
+ size_t home_bucket = hash & table->buckets_mask;
+
+ // Case 1: The home bucket is empty or contains a key that doesn't belong there.
+ // This case also implicitly handles the case of a zero bucket count, since home_bucket will be zero and metadata[ 0 ]
+ // will be the empty placeholder.
+ // In that scenario, the zero buckets_mask triggers the below load-factor check.
+ if( !( table->metadata[ home_bucket ] & VT_IN_HOME_BUCKET_MASK ) )
+ {
+ if(
+ // Load-factor check.
+ VT_UNLIKELY( table->key_count + 1 > VT_CAT( NAME, _bucket_count )( table ) * MAX_LOAD ) ||
+ // Vacate the home bucket if it contains a key.
+ ( table->metadata[ home_bucket ] != VT_EMPTY && VT_UNLIKELY( !VT_CAT( NAME, _evict )( table, home_bucket ) ) )
+ )
+ return VT_CAT( NAME, _end_itr )();
+
+ table->buckets[ home_bucket ].key = key;
+ #ifdef VAL_TY
+ table->buckets[ home_bucket ].val = *val;
+ #endif
+ table->metadata[ home_bucket ] = hashfrag | VT_IN_HOME_BUCKET_MASK | VT_DISPLACEMENT_MASK;
+
+ ++table->key_count;
+
+ VT_CAT( NAME, _itr ) itr = {
+ table->buckets + home_bucket,
+ table->metadata + home_bucket,
+ table->metadata + table->buckets_mask + 1, // Iteration stopper (i.e. the first of the four excess metadata).
+ home_bucket
+ };
+ return itr;
+ }
+
+ // Case 2: The home bucket contains the beginning of a chain.
+
+ // Optionally, check the existing chain.
+ if( !unique )
+ {
+ size_t bucket = home_bucket;
+ while( true )
+ {
+ if(
+ ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) == hashfrag &&
+ VT_LIKELY( CMPR_FN( table->buckets[ bucket ].key, key ) )
+ )
+ {
+ if( replace )
+ {
+ #ifdef KEY_DTOR_FN
+ KEY_DTOR_FN( table->buckets[ bucket ].key );
+ #endif
+ table->buckets[ bucket ].key = key;
+
+ #ifdef VAL_TY
+ #ifdef VAL_DTOR_FN
+ VAL_DTOR_FN( table->buckets[ bucket ].val );
+ #endif
+ table->buckets[ bucket ].val = *val;
+ #endif
+ }
+
+ VT_CAT( NAME, _itr ) itr = {
+ table->buckets + bucket,
+ table->metadata + bucket,
+ table->metadata + table->buckets_mask + 1,
+ home_bucket
+ };
+ return itr;
+ }
+
+ uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK;
+ if( displacement == VT_DISPLACEMENT_MASK )
+ break;
+
+ bucket = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask;
+ }
+ }
+
+ size_t empty;
+ uint16_t displacement;
+ if(
+ VT_UNLIKELY(
+ // Load-factor check.
+ table->key_count + 1 > VT_CAT( NAME, _bucket_count )( table ) * MAX_LOAD ||
+ // Find the earliest empty bucket, per quadratic probing.
+ !VT_CAT( NAME, _find_first_empty )( table, home_bucket, &empty, &displacement )
+ )
+ )
+ return VT_CAT( NAME, _end_itr )();
+
+ // Insert the new key (and value) in the empty bucket and link it to the chain.
+
+ size_t prev = VT_CAT( NAME, _find_insert_location_in_chain )( table, home_bucket, displacement );
+
+ table->buckets[ empty ].key = key;
+ #ifdef VAL_TY
+ table->buckets[ empty ].val = *val;
+ #endif
+ table->metadata[ empty ] = hashfrag | ( table->metadata[ prev ] & VT_DISPLACEMENT_MASK );
+ table->metadata[ prev ] = ( table->metadata[ prev ] & ~VT_DISPLACEMENT_MASK ) | displacement;
+
+ ++table->key_count;
+
+ VT_CAT( NAME, _itr ) itr = {
+ table->buckets + empty,
+ table->metadata + empty,
+ table->metadata + table->buckets_mask + 1,
+ home_bucket
+ };
+ return itr;
+}
+
+// Resizes the bucket array.
+// This function assumes that bucket_count is a power of two and large enough to accommodate all keys without violating
+// the maximum load factor.
+// Returns false in the case of allocation failure.
+// As this function is called very rarely in _insert and _get_or_insert, ideally it should not be inlined into those
+// functions.
+// In testing, the no-inline approach showed a performance benefit when inserting existing keys (i.e. replacing).
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes" // Silence warning about combining noinline with static inline.
+__attribute__((noinline)) static inline
+#elif defined( _MSC_VER )
+__declspec(noinline) static inline
+#else
+static inline
+#endif
+bool VT_CAT( NAME, _rehash )( NAME *table, size_t bucket_count )
+{
+ // The attempt to resize the bucket array and rehash the keys must occur inside a loop that incrementally doubles the
+ // target bucket count because a failure could theoretically occur at any load factor due to the displacement limit.
+ while( true )
+ {
+ NAME new_table = {
+ 0,
+ bucket_count - 1,
+ NULL,
+ NULL
+ #ifdef CTX_TY
+ , table->ctx
+ #endif
+ };
+
+ void *allocation = MALLOC_FN(
+ VT_CAT( NAME, _total_alloc_size )( &new_table )
+ #ifdef CTX_TY
+ , &new_table.ctx
+ #endif
+ );
+
+ if( VT_UNLIKELY( !allocation ) )
+ return false;
+
+ new_table.buckets = (VT_CAT( NAME, _bucket ) *)allocation;
+ new_table.metadata = (uint16_t *)( (unsigned char *)allocation + VT_CAT( NAME, _metadata_offset )( &new_table ) );
+
+ memset( new_table.metadata, 0x00, ( bucket_count + 4 ) * sizeof( uint16_t ) );
+
+ // Iteration stopper at the end of the actual metadata array (i.e. the first of the four excess metadata).
+ new_table.metadata[ bucket_count ] = 0x01;
+
+ for( size_t bucket = 0; bucket < VT_CAT( NAME, _bucket_count )( table ); ++bucket )
+ if( table->metadata[ bucket ] != VT_EMPTY )
+ {
+ VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )(
+ &new_table,
+ table->buckets[ bucket ].key,
+ #ifdef VAL_TY
+ &table->buckets[ bucket ].val,
+ #endif
+ true,
+ false
+ );
+
+ if( VT_UNLIKELY( VT_CAT( NAME, _is_end )( itr ) ) )
+ break;
+ }
+
+ // If a key could not be reinserted due to the displacement limit, double the bucket count and retry.
+ if( VT_UNLIKELY( new_table.key_count < table->key_count ) )
+ {
+ FREE_FN(
+ new_table.buckets,
+ VT_CAT( NAME, _total_alloc_size )( &new_table )
+ #ifdef CTX_TY
+ , &new_table.ctx
+ #endif
+ );
+
+ bucket_count *= 2;
+ continue;
+ }
+
+ if( table->buckets_mask )
+ FREE_FN(
+ table->buckets,
+ VT_CAT( NAME, _total_alloc_size )( table )
+ #ifdef CTX_TY
+ , &table->ctx
+ #endif
+ );
+
+ *table = new_table;
+ return true;
+ }
+}
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+// Inserts a key, replacing the existing key if it already exists.
+// This function wraps insert_raw in a loop that handles growing and rehashing the table if a new key cannot be inserted
+// because of the maximum load factor or displacement limit constraints.
+// Returns an iterator to the inserted key, or an end iterator in the case of allocation failure.
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _insert )(
+ NAME *table,
+ KEY_TY key
+ #ifdef VAL_TY
+ , VAL_TY val
+ #endif
+)
+{
+ while( true )
+ {
+ VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )(
+ table,
+ key,
+ #ifdef VAL_TY
+ &val,
+ #endif
+ false,
+ true
+ );
+
+ if(
+ // Lookup succeeded, in which case itr points to the found key.
+ VT_LIKELY( !VT_CAT( NAME, _is_end )( itr ) ) ||
+ // Lookup failed and rehash also fails, in which case itr is an end iterator.
+ VT_UNLIKELY(
+ !VT_CAT( NAME, _rehash )(
+ table, table->buckets_mask ? VT_CAT( NAME, _bucket_count )( table ) * 2 : VT_MIN_NONZERO_BUCKET_COUNT
+ )
+ )
+ )
+ return itr;
+ }
+}
+
+// Same as NAME_insert, except that if the key already exists, no insertion occurs and the function returns an iterator
+// to the existing key.
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get_or_insert )(
+ NAME *table,
+ KEY_TY key
+ #ifdef VAL_TY
+ , VAL_TY val
+ #endif
+)
+{
+ while( true )
+ {
+ VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _insert_raw )(
+ table,
+ key,
+ #ifdef VAL_TY
+ &val,
+ #endif
+ false,
+ false
+ );
+
+ if(
+ // Lookup succeeded, in which case itr points to the found key.
+ VT_LIKELY( !VT_CAT( NAME, _is_end )( itr ) ) ||
+ // Lookup failed and rehash also fails, in which case itr is an end iterator.
+ VT_UNLIKELY(
+ !VT_CAT( NAME, _rehash )(
+ table, table->buckets_mask ? VT_CAT( NAME, _bucket_count )( table ) * 2 : VT_MIN_NONZERO_BUCKET_COUNT
+ )
+ )
+ )
+ return itr;
+ }
+}
+
+// Returns an iterator pointing to the specified key, or an end iterator if the key does not exist.
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _get )( NAME *table, KEY_TY key )
+{
+ uint64_t hash = HASH_FN( key );
+ size_t home_bucket = hash & table->buckets_mask;
+
+ // If the home bucket is empty or contains a key that does not belong there, then our key does not exist.
+ // This check also implicitly handles the case of a zero bucket count, since home_bucket will be zero and
+ // metadata[ 0 ] will be the empty placeholder.
+ if( !( table->metadata[ home_bucket ] & VT_IN_HOME_BUCKET_MASK ) )
+ return VT_CAT( NAME, _end_itr )();
+
+ // Traverse the chain of keys belonging to the home bucket.
+ uint16_t hashfrag = vt_hashfrag( hash );
+ size_t bucket = home_bucket;
+ while( true )
+ {
+ if(
+ ( table->metadata[ bucket ] & VT_HASH_FRAG_MASK ) == hashfrag &&
+ VT_LIKELY( CMPR_FN( table->buckets[ bucket ].key, key ) )
+ )
+ {
+ VT_CAT( NAME, _itr ) itr = {
+ table->buckets + bucket,
+ table->metadata + bucket,
+ table->metadata + table->buckets_mask + 1,
+ home_bucket
+ };
+ return itr;
+ }
+
+ uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK;
+ if( displacement == VT_DISPLACEMENT_MASK )
+ return VT_CAT( NAME, _end_itr )();
+
+ bucket = ( home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask;
+ }
+}
+
+// Erases the key pointed to by the specified iterator.
+// The erasure always occurs at the end of the chain to which the key belongs.
+// If the key to be erased is not the last in the chain, it is swapped with the last so that erasure occurs at the end.
+// This helps keep a chain's keys close to their home bucket for the sake of cache locality.
+// Returns true if, in the case of iteration from first to end, NAME_next should now be called on the iterator to find
+// the next key.
+// This return value is necessary because at the iterator location, the erasure could result in an empty bucket, a
+// bucket containing a moved key already visited during the iteration, or a bucket containing a moved key not yet
+// visited.
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw )( NAME *table, VT_CAT( NAME, _itr ) itr )
+{
+ --table->key_count;
+ size_t itr_bucket = itr.metadatum - table->metadata;
+
+ // Case 1: The key is the only one in its chain, so just remove it.
+ if(
+ table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK &&
+ ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK
+ )
+ {
+ #ifdef KEY_DTOR_FN
+ KEY_DTOR_FN( table->buckets[ itr_bucket ].key );
+ #endif
+
+ #ifdef VAL_DTOR_FN
+ VAL_DTOR_FN( table->buckets[ itr_bucket ].val );
+ #endif
+
+ table->metadata[ itr_bucket ] = VT_EMPTY;
+ return true;
+ }
+
+ // Case 2 and 3 require that we know the key's home bucket, which the iterator may not have recorded.
+ if( itr.home_bucket == SIZE_MAX )
+ {
+ if( table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK )
+ itr.home_bucket = itr_bucket;
+ else
+ itr.home_bucket = HASH_FN( table->buckets[ itr_bucket ].key ) & table->buckets_mask;
+ }
+
+ // The key can now be safely destructed for cases 2 and 3.
+ #ifdef KEY_DTOR_FN
+ KEY_DTOR_FN( table->buckets[ itr_bucket ].key );
+ #endif
+
+ #ifdef VAL_DTOR_FN
+ VAL_DTOR_FN( table->buckets[ itr_bucket ].val );
+ #endif
+
+ // Case 2: The key is the last in a multi-key chain.
+ // Traverse the chain from the beginning and find the penultimate key.
+ // Then disconnect the key and erase.
+ if( ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK )
+ {
+ size_t bucket = itr.home_bucket;
+ while( true )
+ {
+ uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK;
+ size_t next = ( itr.home_bucket + vt_quadratic( displacement ) ) & table->buckets_mask;
+ if( next == itr_bucket )
+ {
+ table->metadata[ bucket ] |= VT_DISPLACEMENT_MASK;
+ table->metadata[ itr_bucket ] = VT_EMPTY;
+ return true;
+ }
+
+ bucket = next;
+ }
+ }
+
+ // Case 3: The chain has multiple keys, and the key is not the last one.
+ // Traverse the chain from the key to be erased and find the last and penultimate keys.
+ // Disconnect the last key from the chain, and swap it with the key to erase.
+ size_t bucket = itr_bucket;
+ while( true )
+ {
+ size_t prev = bucket;
+ bucket = ( itr.home_bucket + vt_quadratic( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) ) &
+ table->buckets_mask;
+
+ if( ( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK )
+ {
+ table->buckets[ itr_bucket ] = table->buckets[ bucket ];
+
+ table->metadata[ itr_bucket ] = ( table->metadata[ itr_bucket ] & ~VT_HASH_FRAG_MASK ) | (
+ table->metadata[ bucket ] & VT_HASH_FRAG_MASK );
+
+ table->metadata[ prev ] |= VT_DISPLACEMENT_MASK;
+ table->metadata[ bucket ] = VT_EMPTY;
+
+ // Whether the iterator should be advanced depends on whether the key moved to the iterator bucket came from
+ // before or after that bucket.
+ // In the former case, the iteration would already have hit the moved key, so the iterator should still be
+ // advanced.
+ if( bucket > itr_bucket )
+ return false;
+
+ return true;
+ }
+ }
+}
+
+// Erases the specified key, if it exists.
+// Returns true if a key was erased.
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase )( NAME *table, KEY_TY key )
+{
+ VT_CAT( NAME, _itr ) itr = VT_CAT( NAME, _get)( table, key );
+ if( VT_CAT( NAME, _is_end )( itr ) )
+ return false;
+
+ VT_CAT( NAME, _erase_itr_raw )( table, itr );
+ return true;
+}
+
+// Finds the first occupied bucket at or after the bucket pointed to by itr.
+// This function scans four buckets at a time, ideally using intrinsics.
+static inline void VT_CAT( NAME, _fast_forward )( VT_CAT( NAME, _itr ) *itr )
+{
+ while( true )
+ {
+ uint64_t metadata;
+ memcpy( &metadata, itr->metadatum, sizeof( uint64_t ) );
+ if( metadata )
+ {
+ int offset = vt_first_nonzero_uint16( metadata );
+ itr->data += offset;
+ itr->metadatum += offset;
+ itr->home_bucket = SIZE_MAX;
+ return;
+ }
+
+ itr->data += 4;
+ itr->metadatum += 4;
+ }
+}
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _next )( VT_CAT( NAME, _itr ) itr )
+{
+ ++itr.data;
+ ++itr.metadatum;
+ VT_CAT( NAME, _fast_forward )( &itr );
+ return itr;
+}
+
+// Returns the minimum bucket count required to accommodate a certain number of keys, which is governed by the maximum
+// load factor.
+static inline size_t VT_CAT( NAME, _min_bucket_count_for_size )( size_t size )
+{
+ if( size == 0 )
+ return 0;
+
+ // Round up to a power of two.
+ size_t bucket_count = VT_MIN_NONZERO_BUCKET_COUNT;
+ while( size > bucket_count * MAX_LOAD )
+ bucket_count *= 2;
+
+ return bucket_count;
+}
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _reserve )( NAME *table, size_t size )
+{
+ size_t bucket_count = VT_CAT( NAME, _min_bucket_count_for_size )( size );
+
+ if( bucket_count <= VT_CAT( NAME, _bucket_count )( table ) )
+ return true;
+
+ return VT_CAT( NAME, _rehash )( table, bucket_count );
+}
+
+VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _shrink )( NAME *table )
+{
+ size_t bucket_count = VT_CAT( NAME, _min_bucket_count_for_size )( table->key_count );
+
+ if( bucket_count == VT_CAT( NAME, _bucket_count )( table ) ) // Shrink unnecessary.
+ return true;
+
+ if( bucket_count == 0 )
+ {
+ FREE_FN(
+ table->buckets,
+ VT_CAT( NAME, _total_alloc_size )( table )
+ #ifdef CTX_TY
+ , &table->ctx
+ #endif
+ );
+
+ table->buckets_mask = 0x0000000000000000ull;
+ table->metadata = (uint16_t *)&vt_empty_placeholder_metadatum;
+ return true;
+ }
+
+ return VT_CAT( NAME, _rehash )( table, bucket_count );
+}
+
+VT_API_FN_QUALIFIERS VT_CAT( NAME, _itr ) VT_CAT( NAME, _first )( NAME *table )
+{
+ if( !table->key_count )
+ return VT_CAT( NAME, _end_itr )();
+
+ VT_CAT( NAME, _itr ) itr = { table->buckets, table->metadata, table->metadata + table->buckets_mask + 1, SIZE_MAX };
+ VT_CAT( NAME, _fast_forward )( &itr );
+ return itr;
+}
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _clear )( NAME *table )
+{
+ if( !table->key_count )
+ return;
+
+ for( size_t i = 0; i < VT_CAT( NAME, _bucket_count )( table ); ++i )
+ {
+ if( table->metadata[ i ] != VT_EMPTY )
+ {
+ #ifdef KEY_DTOR_FN
+ KEY_DTOR_FN( table->buckets[ i ].key );
+ #endif
+ #ifdef VAL_DTOR_FN
+ VAL_DTOR_FN( table->buckets[ i ].val );
+ #endif
+ }
+
+ table->metadata[ i ] = VT_EMPTY;
+ }
+
+ table->key_count = 0;
+}
+
+VT_API_FN_QUALIFIERS void VT_CAT( NAME, _cleanup )( NAME *table )
+{
+ if( !table->buckets_mask )
+ return;
+
+ #if defined( KEY_DTOR_FN ) || defined( VAL_DTOR_FN )
+ VT_CAT( NAME, _clear )( table );
+ #endif
+
+ FREE_FN(
+ table->buckets,
+ VT_CAT( NAME, _total_alloc_size )( table )
+ #ifdef CTX_TY
+ , &table->ctx
+ #endif
+ );
+
+ VT_CAT( NAME, _init )(
+ table
+ #ifdef CTX_TY
+ , table->ctx
+ #endif
+ );
+}
+
+#endif
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/* Wrapper types and functions for the C11 generic API */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+#if defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 201112L && \
+ !defined( IMPLEMENTATION_MODE ) && \
+ !defined( VT_NO_C11_GENERIC_API ) \
+
+typedef NAME VT_CAT( vt_table_, VT_TEMPLATE_COUNT );
+typedef VT_CAT( NAME, _itr ) VT_CAT( vt_table_itr_, VT_TEMPLATE_COUNT );
+
+static inline void VT_CAT( vt_init_, VT_TEMPLATE_COUNT )(
+ NAME *table
+ #ifdef CTX_TY
+ , CTX_TY ctx
+ #endif
+)
+{
+ VT_CAT( NAME, _init )(
+ table
+ #ifdef CTX_TY
+ , ctx
+ #endif
+ );
+}
+
+static inline bool VT_CAT( vt_init_clone_, VT_TEMPLATE_COUNT )(
+ NAME *table,
+ NAME* source
+ #ifdef CTX_TY
+ , CTX_TY ctx
+ #endif
+)
+{
+ return VT_CAT( NAME, _init_clone )(
+ table,
+ source
+ #ifdef CTX_TY
+ , ctx
+ #endif
+ );
+}
+
+static inline size_t VT_CAT( vt_size_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ return VT_CAT( NAME, _size )( table );
+}
+
+static inline size_t VT_CAT( vt_bucket_count_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ return VT_CAT( NAME, _bucket_count )( table );
+}
+
+static inline bool VT_CAT( vt_is_end_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
+{
+ return VT_CAT( NAME, _is_end )( itr );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_insert_, VT_TEMPLATE_COUNT )(
+ NAME *table,
+ KEY_TY key
+ #ifdef VAL_TY
+ , VAL_TY val
+ #endif
+)
+{
+ return VT_CAT( NAME, _insert )(
+ table,
+ key
+ #ifdef VAL_TY
+ , val
+ #endif
+ );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_get_or_insert_, VT_TEMPLATE_COUNT )(
+ NAME *table,
+ KEY_TY key
+ #ifdef VAL_TY
+ , VAL_TY val
+ #endif
+)
+{
+ return VT_CAT( NAME, _get_or_insert )(
+ table,
+ key
+ #ifdef VAL_TY
+ , val
+ #endif
+ );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_get_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key )
+{
+ return VT_CAT( NAME, _get )( table, key );
+}
+
+static inline bool VT_CAT( vt_erase_, VT_TEMPLATE_COUNT )( NAME *table, KEY_TY key )
+{
+ return VT_CAT( NAME, _erase )( table, key );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_next_, VT_TEMPLATE_COUNT )( VT_CAT( NAME, _itr ) itr )
+{
+ return VT_CAT( NAME, _next )( itr );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_erase_itr_, VT_TEMPLATE_COUNT )( NAME *table, VT_CAT( NAME, _itr ) itr )
+{
+ return VT_CAT( NAME, _erase_itr )( table, itr );
+}
+
+static inline bool VT_CAT( vt_reserve_, VT_TEMPLATE_COUNT )( NAME *table, size_t bucket_count )
+{
+ return VT_CAT( NAME, _reserve )( table, bucket_count );
+}
+
+static inline bool VT_CAT( vt_shrink_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ return VT_CAT( NAME, _shrink )( table );
+}
+
+static inline VT_CAT( NAME, _itr ) VT_CAT( vt_first_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ return VT_CAT( NAME, _first )( table );
+}
+
+static inline void VT_CAT( vt_clear_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ VT_CAT( NAME, _clear )( table );
+}
+
+static inline void VT_CAT( vt_cleanup_, VT_TEMPLATE_COUNT )( NAME *table )
+{
+ VT_CAT( NAME, _cleanup )( table );
+}
+
+// Increment the template counter.
+#if VT_TEMPLATE_COUNT_D1 == 0
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 1
+#elif VT_TEMPLATE_COUNT_D1 == 1
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 2
+#elif VT_TEMPLATE_COUNT_D1 == 2
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 3
+#elif VT_TEMPLATE_COUNT_D1 == 3
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 4
+#elif VT_TEMPLATE_COUNT_D1 == 4
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 5
+#elif VT_TEMPLATE_COUNT_D1 == 5
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 6
+#elif VT_TEMPLATE_COUNT_D1 == 6
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 7
+#elif VT_TEMPLATE_COUNT_D1 == 7
+#undef VT_TEMPLATE_COUNT_D1
+#define VT_TEMPLATE_COUNT_D1 0
+#if VT_TEMPLATE_COUNT_D2 == 0
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 1
+#elif VT_TEMPLATE_COUNT_D2 == 1
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 2
+#elif VT_TEMPLATE_COUNT_D2 == 2
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 3
+#elif VT_TEMPLATE_COUNT_D2 == 3
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 4
+#elif VT_TEMPLATE_COUNT_D2 == 4
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 5
+#elif VT_TEMPLATE_COUNT_D2 == 5
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 6
+#elif VT_TEMPLATE_COUNT_D2 == 6
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 7
+#elif VT_TEMPLATE_COUNT_D2 == 7
+#undef VT_TEMPLATE_COUNT_D2
+#define VT_TEMPLATE_COUNT_D2 0
+#if VT_TEMPLATE_COUNT_D3 == 0
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 1
+#elif VT_TEMPLATE_COUNT_D3 == 1
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 2
+#elif VT_TEMPLATE_COUNT_D3 == 2
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 3
+#elif VT_TEMPLATE_COUNT_D3 == 3
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 4
+#elif VT_TEMPLATE_COUNT_D3 == 4
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 5
+#elif VT_TEMPLATE_COUNT_D3 == 5
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 6
+#elif VT_TEMPLATE_COUNT_D3 == 6
+#undef VT_TEMPLATE_COUNT_D3
+#define VT_TEMPLATE_COUNT_D3 7
+#elif VT_TEMPLATE_COUNT_D3 == 7
+#error Sorry, the number of template instances is limited to 511. Define VT_NO_C11_GENERIC_API globally and use the \
+C99 prefixed function API to circumvent this restriction.
+#endif
+#endif
+#endif
+
+#endif
+
+#undef NAME
+#undef KEY_TY
+#undef VAL_TY
+#undef HASH_FN
+#undef CMPR_FN
+#undef MAX_LOAD
+#undef KEY_DTOR_FN
+#undef VAL_DTOR_FN
+#undef CTX_TY
+#undef MALLOC_FN
+#undef FREE_FN
+#undef HEADER_MODE
+#undef IMPLEMENTATION_MODE
+#undef VT_API_FN_QUALIFIERS
diff --git a/vere/pkg/noun/vortex.c b/vere/pkg/noun/vortex.c
new file mode 100644
index 0000000..8496307
--- /dev/null
+++ b/vere/pkg/noun/vortex.c
@@ -0,0 +1,411 @@
+/// @file
+
+#include "vortex.h"
+
+#include "allocate.h"
+#include "imprison.h"
+#include "jets/k.h"
+#include "jets/q.h"
+#include "log.h"
+#include "manage.h"
+#include "nock.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "xtract.h"
+
+#define _CVX_LOAD 4
+#define _CVX_PEEK 22
+#define _CVX_POKE 23
+#define _CVX_WISH 10
+
+u3v_home* u3v_Home;
+
+/* u3v_life(): execute initial lifecycle, producing Arvo core.
+*/
+u3_noun
+u3v_life(u3_noun eve)
+{
+ u3_noun lyf = u3nt(2, u3nc(0, 3), u3nc(0, 2));
+ u3_noun gat = u3n_nock_on(eve, lyf);
+ u3_noun cor = u3k(u3x_at(7, gat));
+
+ u3z(gat);
+ return cor;
+}
+
+/* u3v_boot(): evaluate boot sequence, making a kernel
+*/
+c3_o
+u3v_boot(u3_noun eve)
+{
+ c3_d len_d;
+ {
+ u3_noun len = u3qb_lent(eve);
+ u3_assert( c3y == u3r_safe_chub(len, &len_d) );
+ u3z(len);
+ }
+
+ {
+ u3_noun pro = u3m_soft(0, u3v_life, eve);
+
+ if ( u3_blip != u3h(pro) ) {
+ u3z(pro);
+ return c3n;
+ }
+
+ u3z(u3A->roc);
+ u3A->roc = u3k(u3t(pro));
+ u3A->eve_d = len_d;
+ u3z(pro);
+ }
+
+ return c3y;
+}
+
+/* _cv_lite(): load lightweight, core-only pill.
+*/
+static u3_noun
+_cv_lite(u3_noun pil)
+{
+ u3_noun eve, pro;
+
+ {
+ u3_noun hed, tal;
+ u3x_cell(pil, &hed, &tal);
+ if ( !_(u3r_sing_c("ivory", hed)) ) {
+ u3m_bail(c3__exit);
+ }
+ eve = tal;
+ }
+
+ u3l_log("lite: arvo formula %x", u3r_mug(pil));
+ pro = u3v_life(u3k(eve));
+ u3l_log("lite: core %x", u3r_mug(pro));
+
+ u3z(pil);
+ return pro;
+}
+
+/* u3v_boot_lite(): light bootstrap sequence, just making a kernel.
+*/
+c3_o
+u3v_boot_lite(u3_noun pil)
+{
+ // ensure zero-initialized kernel
+ //
+ u3A->roc = 0;
+
+ {
+ u3_noun pro = u3m_soft(0, _cv_lite, pil);
+
+ if ( u3_blip != u3h(pro) ) {
+ u3z(pro);
+ return c3n;
+ }
+
+ u3A->roc = u3k(u3t(pro));
+ u3z(pro);
+ }
+
+ u3l_log("lite: final state %x", u3r_mug(u3A->roc));
+
+ return c3y;
+}
+
+/* _cv_nock_wish(): call wish through hardcoded interface.
+*/
+static u3_noun
+_cv_nock_wish(u3_noun txt)
+{
+ u3_noun fun, pro;
+
+ fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_WISH, u3A->roc)));
+ pro = u3n_slam_on(fun, txt);
+
+ return pro;
+}
+
+/* u3v_wish_n(): text expression with cache. with the input as a u3_noun.
+*/
+u3_noun
+u3v_wish_n(u3_noun txt)
+{
+ u3t_event_trace("u3v_wish", 'b');
+ u3_weak exp = u3kdb_get(u3k(u3A->yot), u3k(txt));
+
+ if ( u3_none == exp ) {
+ exp = _cv_nock_wish(u3k(txt));
+
+ // It's probably not a good idea to use u3v_wish()
+ // outside the top level... (as the result is uncached)
+ //
+ if ( u3R == &u3H->rod_u ) {
+ u3A->yot = u3kdb_put(u3A->yot, u3k(txt), u3k(exp));
+ }
+ }
+
+ u3t_event_trace("u3v_wish", 'e');
+
+ u3z(txt);
+ return exp;
+}
+
+/* u3v_wish(): text expression with cache.
+*/
+u3_noun
+u3v_wish(const c3_c* str_c)
+{
+ u3t_event_trace("u3v_wish", 'b');
+ u3_noun txt = u3i_string(str_c);
+ u3_weak exp = u3kdb_get(u3k(u3A->yot), u3k(txt));
+
+ if ( u3_none == exp ) {
+ exp = _cv_nock_wish(u3k(txt));
+
+ // It's probably not a good idea to use u3v_wish()
+ // outside the top level... (as the result is uncached)
+ //
+ if ( u3R == &u3H->rod_u ) {
+ u3A->yot = u3kdb_put(u3A->yot, u3k(txt), u3k(exp));
+ }
+ }
+
+ u3t_event_trace("u3v_wish", 'e');
+
+ u3z(txt);
+ return exp;
+}
+
+/* u3v_do(): use a kernel gate.
+*/
+u3_noun
+u3v_do(const c3_c* txt_c, u3_noun sam)
+{
+ u3_noun gat = u3v_wish(txt_c);
+ u3_noun pro;
+
+#if 0
+ if ( &u3H->rod_u == u3R ) {
+ pro = u3m_soft_slam(gat, sam);
+ }
+ else {
+ pro = u3n_slam_on(gat, sam);
+ }
+#else
+ pro = u3n_slam_on(gat, sam);
+#endif
+
+ return pro;
+}
+
+/* u3v_lily(): parse little atom.
+*/
+c3_o
+u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l)
+{
+ c3_w wad_w;
+ u3_noun uco = u3dc("slaw", fot, u3k(txt));
+ u3_noun p_uco, q_uco;
+
+ if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) ||
+ (u3_nul != p_uco) ||
+ (c3n == u3r_safe_word(q_uco, &wad_w)) ||
+ (wad_w & 0x80000000) )
+ {
+ c3_c* txt_c = u3r_string(txt);
+ u3l_log("strange lily %s", txt_c);
+ c3_free(txt_c);
+ u3z(txt); u3z(uco);
+ return c3n;
+ }
+ else {
+ *tid_l = (c3_l)wad_w;
+ u3z(txt); u3z(uco);
+ return c3y;
+ }
+}
+
+/* u3v_peek(): query the reck namespace (protected).
+*/
+u3_noun
+u3v_peek(u3_noun sam)
+{
+ u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_PEEK, u3A->roc)));
+ return u3n_slam_on(fun, sam);
+}
+
+/* u3v_soft_peek(): softly query the reck namespace.
+*/
+u3_noun
+u3v_soft_peek(c3_w mil_w, u3_noun sam)
+{
+ u3_noun gon = u3m_soft(mil_w, u3v_peek, sam);
+ u3_noun tag, dat;
+ u3x_cell(gon, &tag, &dat);
+
+ // read failed, produce trace
+ //
+ // NB, reads *should not* fail deterministically
+ //
+ if ( u3_blip != tag ) {
+ return u3nc(c3n, gon);
+ }
+
+ // read succeeded, produce result
+ //
+ {
+ u3_noun pro = u3nc(c3y, u3k(dat));
+ u3z(gon);
+ return pro;
+ }
+}
+
+/* u3v_poke(): compute a timestamped ovum.
+*/
+u3_noun
+u3v_poke(u3_noun sam)
+{
+ u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_POKE, u3A->roc)));
+ u3_noun pro;
+
+ {
+# ifdef U3_MEMORY_DEBUG
+ c3_w cod_w = u3a_lush(u3h(u3t(u3t(sam))));
+# endif
+
+ pro = u3n_slam_on(fun, sam);
+
+# ifdef U3_MEMORY_DEBUG
+ u3a_lop(cod_w);
+# endif
+ }
+
+ return pro;
+}
+
+/* u3v_poke_sure(): inject an event, saving new state if successful.
+*/
+c3_o
+u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro)
+{
+ u3_noun gon = u3m_soft(mil_w, u3v_poke, eve);
+ u3_noun tag, dat;
+ u3x_cell(gon, &tag, &dat);
+
+ // event failed, produce trace
+ //
+ if ( u3_blip != tag ) {
+ *pro = gon;
+ return c3n;
+ }
+
+ // event succeeded, persist state and produce effects
+ //
+ {
+ u3_noun vir, cor;
+ u3x_cell(dat, &vir, &cor);
+
+ u3z(u3A->roc);
+ u3A->roc = u3k(cor);
+ u3A->eve_d++;
+
+ *pro = u3k(vir);
+ u3z(gon);
+ return c3y;
+ }
+}
+
+/* u3v_tank(): dump single tank.
+*/
+void
+u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac)
+{
+ u3v_punt(blu, tab_l, u3nc(tac, u3_nul));
+}
+
+/* u3v_punt(): dump tank list.
+*/
+void
+u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac)
+{
+#if 0
+ u3_noun blu = u3_term_get_blew(0);
+#endif
+ c3_l col_l = u3h(blu);
+ u3_noun cat = tac;
+
+ // We are calling nock here, but hopefully need no protection.
+ //
+ while ( c3y == u3du(cat) ) {
+ u3_noun wol = u3dc("wash", u3nc(tab_l, col_l), u3k(u3h(cat)));
+
+ u3m_wall(wol);
+ cat = u3t(cat);
+ }
+ u3z(tac);
+ u3z(blu);
+}
+
+/* u3v_sway(): print trace.
+*/
+void
+u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax)
+{
+ u3_noun mok = u3dc("mook", 2, tax);
+
+ u3v_punt(blu, tab_l, u3k(u3t(mok)));
+ u3z(mok);
+}
+
+/* u3v_mark(): mark arvo kernel.
+*/
+u3m_quac*
+u3v_mark()
+{
+ u3v_arvo* arv_u = &(u3H->arv_u);
+
+ u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 3);
+
+ qua_u[0] = c3_calloc(sizeof(*qua_u[0]));
+ qua_u[0]->nam_c = strdup("kernel");
+ qua_u[0]->siz_w = u3a_mark_noun(arv_u->roc) * 4;
+
+ qua_u[1] = c3_calloc(sizeof(*qua_u[2]));
+ qua_u[1]->nam_c = strdup("wish cache");
+ qua_u[1]->siz_w = u3a_mark_noun(arv_u->yot) * 4;
+
+ qua_u[2] = NULL;
+
+ u3m_quac* tot_u = c3_malloc(sizeof(*tot_u));
+ tot_u->nam_c = strdup("total arvo stuff");
+ tot_u->siz_w = qua_u[0]->siz_w + qua_u[1]->siz_w;
+ tot_u->qua_u = qua_u;
+
+ return tot_u;
+}
+
+/* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3v_reclaim(void)
+{
+ // clear the u3v_wish cache
+ //
+ // NB: this would leak if not on the home road
+ //
+ if ( &(u3H->rod_u) == u3R ) {
+ u3z(u3A->yot);
+ u3A->yot = u3_nul;
+ }
+}
+
+/* u3v_rewrite_compact(): rewrite arvo kernel for compaction.
+*/
+void
+u3v_rewrite_compact(void)
+{
+ // XX fix these to correctly no-op on inner roads
+ //
+ u3a_relocate_noun(&(u3A->roc));
+ u3a_relocate_noun(&(u3A->yot));
+}
diff --git a/vere/pkg/noun/vortex.h b/vere/pkg/noun/vortex.h
new file mode 100644
index 0000000..9b48ba5
--- /dev/null
+++ b/vere/pkg/noun/vortex.h
@@ -0,0 +1,135 @@
+/// @file
+
+#ifndef U3_VORTEX_H
+#define U3_VORTEX_H
+
+#include "allocate.h"
+#include "c3/c3.h"
+#include "imprison.h"
+#include "version.h"
+
+ /** Data structures.
+ **/
+ /* u3v_arvo: modern arvo structure.
+ */
+ typedef struct _u3v_arvo {
+ c3_d eve_d; // event number
+ u3_noun roc; // kernel core
+ u3_noun yot; // cached gates
+ } u3v_arvo;
+
+ /* u3v_home: all internal (within image) state.
+ ** NB: version must first for ease of migration.
+ */
+ typedef struct _u3v_home {
+ u3v_version ver_d; // version number
+ c3_d pam_d; // parameters
+ u3v_arvo arv_u; // arvo state
+ u3a_road rod_u; // storage state
+ } u3v_home;
+
+
+ /** Globals.
+ **/
+ /// Arvo internal state.
+ extern u3v_home* u3v_Home;
+# define u3H u3v_Home
+# define u3A (&(u3v_Home->arv_u))
+
+ /** Functions.
+ **/
+ /* u3v_life(): execute initial lifecycle, producing Arvo core.
+ */
+ u3_noun
+ u3v_life(u3_noun eve);
+
+ /* u3v_boot(): evaluate boot sequence, making a kernel
+ */
+ c3_o
+ u3v_boot(u3_noun eve);
+
+ /* u3v_boot_lite(): light bootstrap sequence, just making a kernel.
+ */
+ c3_o
+ u3v_boot_lite(u3_noun lit);
+
+ /* u3v_wish_n(): text expression with cache.
+ */
+ u3_noun
+ u3v_wish_n(const u3_noun txt);
+
+ /* u3v_do(): use a kernel function.
+ */
+ u3_noun
+ u3v_do(const c3_c* txt_c, u3_noun arg);
+# define u3do(txt_c, a) u3v_do(txt_c, a)
+# define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b))
+# define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c))
+# define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nq(a, b, c, d))
+
+ /* u3v_wish(): text expression with cache.
+ */
+ u3_noun
+ u3v_wish(const c3_c* str_c);
+
+ /* u3v_lily(): parse little atom.
+ */
+ c3_o
+ u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l);
+
+ /* u3v_peek(): query the reck namespace.
+ */
+ u3_noun
+ u3v_peek(u3_noun hap);
+
+ /* u3v_soft_peek(): softly query the reck namespace.
+ */
+ u3_noun
+ u3v_soft_peek(c3_w mil_w, u3_noun sam);
+
+ /* u3v_poke(): compute a timestamped ovum.
+ */
+ u3_noun
+ u3v_poke(u3_noun sam);
+
+ /* u3v_poke_sure(): inject an event, saving new state if successful.
+ */
+ c3_o
+ u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro);
+
+ /* u3v_tank(): dump single tank.
+ */
+ void
+ u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac);
+
+ /* u3v_punt(): dump tank list.
+ */
+ void
+ u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac);
+
+ /* u3v_sway(): print trace.
+ */
+ void
+ u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax);
+
+ /* u3v_plan(): queue ovum (external).
+ */
+ void
+ u3v_plan(u3_noun pax, u3_noun fav);
+
+ /* u3v_mark(): mark arvo kernel.
+ */
+ u3m_quac*
+ u3v_mark();
+
+ /* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3v_reclaim(void);
+
+ /* u3v_rewrite_compact(): rewrite arvo kernel for compaction.
+ */
+ void
+ u3v_rewrite_compact(void);
+
+#endif /* ifndef U3_VORTEX_H */
diff --git a/vere/pkg/noun/xtract.c b/vere/pkg/noun/xtract.c
new file mode 100644
index 0000000..f18aa68
--- /dev/null
+++ b/vere/pkg/noun/xtract.c
@@ -0,0 +1,33 @@
+/// @file
+
+#include "xtract.h"
+
+#include "manage.h"
+#include "retrieve.h"
+
+u3_atom
+u3x_atom(u3_noun a);
+u3_noun
+u3x_good(u3_weak som);
+c3_o
+u3x_loob(u3_noun a);
+
+/* u3x_mean():
+**
+** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates.
+** Axes must be sorted in tree order.
+*/
+void
+u3x_mean(u3_noun som, ...)
+{
+ c3_o ret_o;
+ va_list ap;
+
+ va_start(ap, som);
+ ret_o = u3r_vmean(som, ap);
+ va_end(ap);
+
+ if ( c3n == ret_o ) {
+ u3m_bail(c3__exit);
+ }
+}
diff --git a/vere/pkg/noun/xtract.h b/vere/pkg/noun/xtract.h
new file mode 100644
index 0000000..c527a43
--- /dev/null
+++ b/vere/pkg/noun/xtract.h
@@ -0,0 +1,162 @@
+/// @file
+
+#ifndef U3_XTRACT_H
+#define U3_XTRACT_H
+
+#include "c3/c3.h"
+#include "types.h"
+#include "allocate.h"
+#include "manage.h"
+
+ /** Constants.
+ **/
+ /* Conventional axes for gate call.
+ */
+# define u3x_pay 3 // payload
+# define u3x_sam 6 // sample
+# define u3x_sam_1 6
+# define u3x_sam_2 12
+# define u3x_sam_3 13
+# define u3x_sam_4 24
+# define u3x_sam_5 25
+# define u3x_sam_6 26
+# define u3x_sam_12 52
+# define u3x_sam_13 53
+# define u3x_sam_7 27
+# define u3x_sam_14 54
+# define u3x_sam_15 55
+# define u3x_sam_30 110
+# define u3x_sam_31 111
+# define u3x_sam_62 222
+# define u3x_sam_63 223
+# define u3x_con 7 // context
+# define u3x_con_2 14 // context
+# define u3x_con_3 15 // context
+# define u3x_con_sam 30 // sample in gate context
+# define u3x_con_sam_2 60
+# define u3x_con_sam_3 61
+# define u3x_bat 2 // battery
+
+
+ /** Macros.
+ **/
+ /* Word axis macros. For 31-bit axes only.
+ */
+
+ /* u3x_at (u3at): fragment.
+ */
+# define u3x_at(a, b) u3x_good(u3r_at(a, b))
+# define u3at(a, b) u3x_at(a, b)
+
+ /* u3x_bite(): xtract/default $bloq and $step from $bite.
+ */
+# define u3x_bite(a, b, c) \
+ do { \
+ if ( c3n == u3r_bite(a, b, c) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /* u3x_dep(): number of axis bits.
+ */
+# define u3x_dep(a_w) (c3_bits_word(a_w) - 1)
+
+ /* u3x_cap(): root axis, 2 or 3.
+ */
+# define u3x_cap(a_w) ({ \
+ u3_assert( 1 < a_w ); \
+ (0x2 | (a_w >> (u3x_dep(a_w) - 1))); })
+
+ /* u3x_mas(): remainder after cap.
+ */
+# define u3x_mas(a_w) ({ \
+ u3_assert( 1 < a_w ); \
+ ( (a_w & ~(1 << u3x_dep(a_w))) | (1 << (u3x_dep(a_w) - 1)) ); })
+
+ /* u3x_peg(): connect two axes.
+ */
+# define u3x_peg(a_w, b_w) \
+ ( (a_w << u3x_dep(b_w)) | (b_w &~ (1 << u3x_dep(b_w))) )
+
+ /* u3x_cell(): divide `a` as a cell `[b c]`.
+ */
+# define u3x_cell(a, b, c) \
+ do { \
+ if ( c3n == u3r_cell(a, b, c) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /* u3x_trel(): divide `a` as a trel `[b c d]`, or bail.
+ */
+# define u3x_trel(a, b, c, d) \
+ do { \
+ if ( c3n == u3r_trel(a, b, c, d) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /* u3x_qual(): divide `a` as a quadruple `[b c d e]`.
+ */
+# define u3x_qual(a, b, c, d, e) \
+ do { \
+ if ( c3n == u3r_qual(a, b, c, d, e) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /* u3x_quil(): divide `a` as a quintuple `[b c d e f]`.
+ */
+# define u3x_quil(a, b, c, d, e, f) \
+ do { \
+ if ( c3n == u3r_quil(a, b, c, d, e, f) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /* u3x_hext(): divide `a` as a hextuple `[b c d e f g]`.
+ */
+# define u3x_hext(a, b, c, d, e, f, g) \
+ do { \
+ if ( c3n == u3r_hext(a, b, c, d, e, f, g) ) { \
+ u3m_bail(c3__exit); \
+ } \
+ } while (0)
+
+ /** Functions.
+ **/
+ /** u3x_*: read, but bail with c3__exit on a crash.
+ **/
+ /* u3x_atom(): atom or exit.
+ */
+ inline u3_atom
+ u3x_atom(u3_noun a)
+ {
+ return ( c3y == u3a_is_cell(a) ) ? u3m_bail(c3__exit) : a;
+ }
+
+ /* u3x_good(): test for u3_none.
+ */
+ inline u3_noun
+ u3x_good(u3_weak som)
+ {
+ return ( u3_none == som ) ? u3m_bail(c3__exit) : som;
+ }
+
+ /* u3x_loob(): loobean or exit.
+ */
+ inline c3_o
+ u3x_loob(u3_noun a)
+ {
+ return ( a > 1 ) ? u3m_bail(c3__exit) : a;
+ }
+
+ /* u3x_mean():
+ **
+ ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates.
+ ** Axes must be sorted in tree order.
+ */
+ void
+ u3x_mean(u3_noun a, ...);
+
+#endif /* ifndef U3_XTRACT_H */
diff --git a/vere/pkg/noun/zave.c b/vere/pkg/noun/zave.c
new file mode 100644
index 0000000..2530718
--- /dev/null
+++ b/vere/pkg/noun/zave.c
@@ -0,0 +1,157 @@
+/// @file
+
+#include "zave.h"
+
+#include "allocate.h"
+#include "hashtable.h"
+#include "imprison.h"
+#include "options.h"
+#include "vortex.h"
+
+/* u3z_key(): construct a memo cache-key. Arguments retained.
+*/
+u3_noun
+u3z_key(c3_m fun, u3_noun one)
+{
+ return u3nc(fun, u3k(one));
+}
+u3_noun
+u3z_key_2(c3_m fun, u3_noun one, u3_noun two)
+{
+ return u3nt(fun, u3k(one), u3k(two));
+}
+u3_noun
+u3z_key_3(c3_m fun, u3_noun one, u3_noun two, u3_noun tri)
+{
+ return u3nq(fun, u3k(one), u3k(two), u3k(tri));
+}
+u3_noun
+u3z_key_4(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua)
+{
+ return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3k(qua)));
+}
+u3_noun
+u3z_key_5(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua, u3_noun qin)
+{
+ return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3nc(u3k(qua), u3k(qin))));
+}
+
+/* _har(): get the memo cache for the given cid.
+*/
+static u3p(u3h_root)
+_har(u3a_road* rod_u, u3z_cid cid)
+{
+ switch ( cid ) {
+ case u3z_memo_toss:
+ return rod_u->cax.har_p;
+ case u3z_memo_keep:
+ return rod_u->cax.per_p;
+ }
+ u3_assert(0);
+}
+
+/* u3z_find(): find in memo cache. Arguments retained.
+*/
+u3_weak
+u3z_find(u3z_cid cid, u3_noun key)
+{
+ if ( (u3z_memo_toss == cid) || (u3C.wag_w & u3o_cash) ) {
+ // XX under cash lookup in parent roads,
+ // copying cache hits into the current road
+ return u3h_get(_har(u3R, cid), key);
+ }
+ else {
+ // XX needs to be benchmarked (up vs. down search)
+ u3a_road* rod_u = &(u3H->rod_u);
+ while ( 1 ) {
+ u3_weak got = u3h_get(_har(rod_u, cid), key);
+ if ( u3_none != got ) {
+ return got;
+ }
+ if ( 0 == rod_u->kid_p ) {
+ return u3_none;
+ }
+ rod_u = u3to(u3a_road, rod_u->kid_p);
+ };
+ }
+}
+
+/* u3z_find_up(): find in persistent memo cache,
+ starting from the current road. Arguments retained
+*/
+u3_weak
+u3z_find_up(u3_noun key)
+{
+ u3a_road* rod_u = u3R;
+ while ( 1 ) {
+ u3_weak got = u3h_get(_har(rod_u, u3z_memo_keep), key);
+ if ( u3_none != got ) {
+ return got;
+ }
+ if ( rod_u == &(u3H->rod_u) ) {
+ return u3_none;
+ }
+ rod_u = u3to(u3a_road, rod_u->par_p);
+ }
+}
+
+u3_weak
+u3z_find_m(u3z_cid cid, c3_m fun, u3_noun one)
+{
+ u3_noun key = u3nc(fun, u3k(one));
+ u3_weak val;
+ val = u3z_find(cid, key);
+ u3z(key);
+
+ return val;
+}
+
+/* u3z_save(): save in memo cache. TRANSFER key; RETAIN val
+*/
+u3_noun
+u3z_save(u3z_cid cid, u3_noun key, u3_noun val)
+{
+ u3h_put(_har(u3R, cid), key, u3k(val));
+ u3z(key);
+ return val;
+}
+
+/* u3z_save_m(): save in memo cache. Arguments retained.
+*/
+u3_noun
+u3z_save_m(u3z_cid cid, c3_m fun, u3_noun one, u3_noun val)
+{
+ u3_noun key = u3nc(fun, u3k(one));
+
+ u3h_put(_har(u3R, cid), key, u3k(val));
+ u3z(key);
+ return val;
+}
+
+/* u3z_uniq(): uniquify with memo cache. XX not used.
+*/
+u3_noun
+u3z_uniq(u3z_cid cid, u3_noun som)
+{
+ u3_noun key = u3nc(c3__uniq, u3k(som));
+ u3_noun val = u3h_get(_har(u3R, cid), key);
+
+ if ( u3_none != val ) {
+ u3z(key); u3z(som); return val;
+ }
+ else {
+ u3h_put(_har(u3R, cid), key, u3k(som));
+ return som;
+ }
+}
+
+/* u3z_reap(): promote memoization cache state.
+*/
+void
+u3z_reap(u3z_cid cid, u3p(u3h_root) har_p)
+{
+ u3_assert(u3z_memo_toss != cid);
+
+ u3h_uni(_har(u3R, cid), har_p);
+ u3h_free(har_p);
+}
diff --git a/vere/pkg/noun/zave.h b/vere/pkg/noun/zave.h
new file mode 100644
index 0000000..f7e2be9
--- /dev/null
+++ b/vere/pkg/noun/zave.h
@@ -0,0 +1,69 @@
+/// @file
+
+#ifndef U3_ZAVE_H
+#define U3_ZAVE_H
+
+#include "c3/c3.h"
+#include "types.h"
+
+ /** Memoization.
+ ***
+ *** The memo cache is keyed by an arbitrary symbolic function
+ *** and a noun argument to that (logical) function. Functions
+ *** are predefined by C-level callers, but 0 means nock.
+ ***
+ *** Memo functions RETAIN keys and transfer values.
+ **/
+ /* u3z_cid: cache id
+ */
+ typedef enum {
+ u3z_memo_toss = 0,
+ u3z_memo_keep = 1,
+ // u3z_memo_ford = 2,
+ // u3z_memo_ames = 3,
+ // ...
+ } u3z_cid;
+
+ /* u3z_key*(): construct a memo cache-key. Arguments retained.
+ */
+ u3_noun u3z_key(c3_m, u3_noun);
+ u3_noun u3z_key_2(c3_m, u3_noun, u3_noun);
+ u3_noun u3z_key_3(c3_m, u3_noun, u3_noun, u3_noun);
+ u3_noun u3z_key_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun);
+ u3_noun u3z_key_5(c3_m, u3_noun, u3_noun, u3_noun, u3_noun, u3_noun);
+
+ /* u3z_find*(): find in memo cache. Arguments retained
+ */
+ u3_weak u3z_find(u3z_cid cid, u3_noun key);
+ u3_weak u3z_find_m(u3z_cid cid, c3_m fun_m, u3_noun one);
+ u3_weak u3z_find_up(u3_noun key);
+
+ /* u3z_save(): save in memo cache. TRANSFER key; RETAIN val;
+ */
+ u3_noun u3z_save(u3z_cid cid, u3_noun key, u3_noun val);
+
+ /* u3z_save_m(): save in memo cache. Arguments retained
+ */
+ u3_noun u3z_save_m(u3z_cid cid, c3_m fun_m, u3_noun one, u3_noun val);
+
+ /* u3z_uniq(): uniquify with memo cache.
+ */
+ u3_noun
+ u3z_uniq(u3z_cid cid, u3_noun som);
+
+ /* u3z_reap(): promote memoization cache state.
+ */
+ void
+ u3z_reap(u3z_cid cid, u3p(u3h_root) har_p);
+
+ /* u3z_free(): free memoization cache.
+ */
+ void
+ u3z_free(u3z_cid cid);
+
+ /* u3z_ream(): refresh after restoring from checkpoint.
+ */
+ void
+ u3z_ream(u3z_cid cid);
+
+#endif /* ifndef U3_ZAVE_H */