uCBQN/src/load.c
2021-12-17 18:04:19 +02:00

665 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "core.h"
#include "utils/mut.h"
#include "utils/file.h"
#include "vm.h"
#include "ns.h"
#include "builtins.h"
#define FOR_INIT(F) F(base) F(harr) F(mutF) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(inverse) F(load) F(sysfnPost) F(dervPost)
#define F(X) void X##_init(void);
FOR_INIT(F)
#undef F
u64 mm_heapMax = HEAP_MAX;
u64 mm_heapAlloc;
// compiler result:
// [
// [...bytecode],
// [...objects],
// [ // block data
// [
// type, // 0: function; 1: 1-modifier; 2: 2-modifier
// immediateness, // 0: non-immediate; 1: immediate
// ambivalentIndex OR [monadicIndices, dyadicIndices], // indexes into body data array
// ]*
// ],
// [ // body data
// [
// bytecodeOffset,
// variableCount, // number of variable slots needed
// ( // optional extra info for namespace stuff
// [...variableIDs] // a number for each variable slot; indexes into nameList
// [...exportMask] // a unique number for each variable
// )?
// ]*
// ],
// [[...startIndices], [...endIndices]],? // optional, for each bytecode; inclusive
// [%, %, [[...nameList], %], %]? // optional; % marks things i haven't bothered to understand
// ]
#define FA(N,X) B bi_##N; B N##_c1(B t, B x); B N##_c2(B t, B w, B x);
#define FM(N,X) B bi_##N; B N##_c1(B t, B x);
#define FD(N,X) B bi_##N; B N##_c2(B t, B w, B x);
FOR_PFN(FA,FM,FD)
#undef FA
#undef FM
#undef FD
#define FA(N,X) B bi_##N; B N##_c1(Md1D* d, B x); B N##_c2(Md1D* d, B w, B x);
#define FM(N,X) B bi_##N; B N##_c1(Md1D* d, B x);
#define FD(N,X) B bi_##N; B N##_c2(Md1D* d, B w, B x);
FOR_PM1(FA,FM,FD)
#undef FA
#undef FM
#undef FD
#define FA(N,X) B bi_##N; B N##_c1(Md2D*, B x); B N##_c2(Md2D*, B w, B x);
#define FM(N,X) B bi_##N; B N##_c1(Md2D*, B x);
#define FD(N,X) B bi_##N; B N##_c2(Md2D*, B w, B x);
FOR_PM2(FA,FM,FD)
#undef FA
#undef FM
#undef FD
#define F(N) u64 N;
CTR_FOR(F)
#undef F
char* pfn_repr(u8 u) {
switch(u) { default: return "(unknown function)";
#define F(N,X) case pf_##N: return X;
FOR_PFN(F,F,F)
#undef F
}
}
char* pm1_repr(u8 u) {
switch(u) { default: return"(unknown 1-modifier)";
#define F(N,X) case pm1_##N: return X;
FOR_PM1(F,F,F)
#undef F
}
}
char* pm2_repr(u8 u) {
switch(u) { default: return"(unknown 2-modifier)";
#define F(N,X) case pm2_##N: return X;
FOR_PM2(F,F,F)
#undef F
}
}
#define F(TY,N) TY ti_##N[t_COUNT];
FOR_TI(F)
#undef F
B r1Objs[rtLen];
B rtWrap_wrap(B x); // consumes
void rtWrap_print(void);
i64 comp_currEnvPos;
B comp_currPath;
B comp_currArgs;
B comp_currSrc;
B comp_currRe;
B rt_merge, rt_undo, rt_select, rt_slash, rt_join, rt_ud, rt_pick,rt_take, rt_drop,
rt_group, rt_under, rt_reverse, rt_indexOf, rt_count, rt_memberOf, rt_find, rt_cell;
Block* load_compObj(B x, B src, B path, Scope* sc) { // consumes x,src
SGet(x)
usz xia = a(x)->ia;
if (xia!=6 & xia!=4) thrM("load_compObj: bad item count");
Block* r = xia==6? compile(Get(x,0),Get(x,1),Get(x,2),Get(x,3),Get(x,4),Get(x,5), src, inc(path), sc)
: compile(Get(x,0),Get(x,1),Get(x,2),Get(x,3),bi_N, bi_N, src, inc(path), sc);
dec(x);
return r;
}
#include "gen/src"
#if RT_SRC
Block* load_compImport(B bc, B objs, B blocks, B bodies, B inds, B src) { // consumes all
return compile(bc, objs, blocks, bodies, inds, bi_N, src, m_str8l("(precompiled)"), NULL);
}
#else
Block* load_compImport(B bc, B objs, B blocks, B bodies) { // consumes all
return compile(bc, objs, blocks, bodies, bi_N, bi_N, bi_N, bi_N, NULL);
}
#endif
B load_comp;
B load_compgen;
B load_rtObj;
B load_compArg;
B load_glyphs;
#if FORMATTER
B load_fmt, load_repr;
B bqn_fmt(B x) { // consumes
return c1(load_fmt, x);
}
B bqn_repr(B x) { // consumes
return c1(load_repr, x);
}
#else
B bqn_fmt(B x) {
return x;
}
B bqn_repr(B x) {
return x;
}
#endif
void load_gcFn() {
mm_visit(comp_currPath);
mm_visit(comp_currArgs);
mm_visit(comp_currSrc);
mm_visit(comp_currRe);
mm_visit(rt_invFnReg);
mm_visit(rt_invFnSwap);
}
static NOINLINE Block* bqn_compc(B str, B path, B args, B comp, B compArg) { // consumes str,path,args
B prevPath = comp_currPath ; comp_currPath = path;
B prevArgs = comp_currArgs ; comp_currArgs = args;
B prevSrc = comp_currSrc ; comp_currSrc = str;
i64 prevEnvPos = comp_currEnvPos; comp_currEnvPos = envCurr-envStart;
Block* r = load_compObj(c2(comp, incG(compArg), inc(str)), str, path, NULL);
dec(path); dec(args);
comp_currPath = prevPath;
comp_currArgs = prevArgs;
comp_currSrc = prevSrc;
comp_currEnvPos = prevEnvPos;
return r;
}
Block* bqn_comp(B str, B path, B args) { // consumes all
return bqn_compc(str, path, args, load_comp, load_compArg);
}
Block* bqn_compScc(B str, B path, B args, Scope* sc, B comp, B rt, bool repl) { // consumes str,path,args
B prevPath = comp_currPath ; comp_currPath = path;
B prevArgs = comp_currArgs ; comp_currArgs = args;
B prevSrc = comp_currSrc ; comp_currSrc = str;
i64 prevEnvPos = comp_currEnvPos; comp_currEnvPos = envCurr-envStart;
B vName = emptyHVec();
B vDepth = emptyIVec();
if (repl && (!sc || sc->psc)) thrM("VM compiler: REPL mode must be used at top level scope");
i32 depth = repl? -1 : 0;
Scope* csc = sc;
while (csc) {
Body* body = csc->body;
if (csc->varAm) {
B nameList = body->bl->comp->nameList; SGetU(nameList);
for (u64 i = 0; i < csc->varAm; i++) {
i32 nameID = body->varData[i + body->varAm];
vName = vec_add(vName, inc(GetU(nameList, nameID)));
vDepth = vec_add(vDepth, m_i32(depth));
}
}
if (csc->ext) for (u64 i = 0; i < csc->ext->varAm; i++) {
vName = vec_add(vName, inc(csc->ext->vars[i+csc->ext->varAm]));
vDepth = vec_add(vDepth, m_i32(depth));
}
csc = csc->psc;
depth++;
}
Block* r = load_compObj(c2(comp, m_hVec4(incG(rt), incG(bi_sys), vName, vDepth), inc(str)), str, path, sc);
dec(path); dec(args);
comp_currPath = prevPath;
comp_currArgs = prevArgs;
comp_currSrc = prevSrc;
comp_currEnvPos = prevEnvPos;
return r;
}
NOINLINE Block* bqn_compSc(B str, B path, B args, Scope* sc, bool repl) { // consumes str,path,args
return bqn_compScc(str, path, args, sc, load_comp, load_rtObj, repl);
}
B bqn_exec(B str, B path, B args) { // consumes all
Block* block = bqn_comp(str, path, args);
B res = m_funBlock(block, 0);
ptr_dec(block);
return res;
}
void init_comp(B* set, B prim) {
if (q_N(prim)) {
set[0] = inc(load_comp);
set[1] = inc(load_rtObj);
set[2] = inc(load_glyphs);
} else {
if (!isArr(prim) || rnk(prim)!=1) thrM("•ReBQN: 𝕩.primitives must be a list");
usz pia = a(prim)->ia;
usz np[3] = {0}; // number of functions, 1-modifiers, and 2-modifiers
SGetU(prim);
for (usz i = 0; i < pia; i++) { // check and count
B p = GetU(prim, i);
if (!isArr(p) || rnk(p)!=1 || a(p)->ia!=2) thrM("•ReBQN: 𝕩.primitives must consist of glyph-primitive pairs");
if (!isC32(IGet(p, 0))) thrM("•ReBQN 𝕩.primitives: Glyphs must be characters");
B v = IGetU(p, 1);
i32 t = isFun(v)? 0 : isMd1(v)? 1 : isMd2(v)? 2 : 3;
if (t==3) thrM("•ReBQN 𝕩.primitives: Primitives must be operations");
np[t]+= 1;
}
M_HARR(r, 3)
u32* gl[3];
usz sum = 0;
for (usz i = 0; i < 3; i++) {
usz l = np[i];
HARR_ADD(r, i, m_c32arrv(gl+i, l));
np[i] = sum;
sum+= l;
}
B rb = HARR_FV(r);
HArr_p prh = m_harr0v(pia);
for (usz i = 0; i < pia; i++) {
B gv = GetU(prim, i);
B v = IGet(gv, 1);
i32 t = isFun(v)? 0 : isMd1(v)? 1 : isMd2(v)? 2 : 3;
*(gl[t]++) = o2cu(IGet(gv, 0));
prh.a[np[t]++] = v;
}
set[1] = prh.b;
set[2] = inc(rb);
set[0] = c1(load_compgen, rb);
}
}
B getPrimitives() {
B g, r;
if (q_N(comp_currRe)) {
g = load_glyphs; r = load_rtObj;
} else {
B* o = harr_ptr(comp_currRe); g = o[4]; r = o[3];
}
B* pr = harr_ptr(r);
B* gg = harr_ptr(g);
M_HARR(ph, a(r)->ia);
for (usz gi = 0; gi < 3; gi++) {
usz l = a(gg[gi])->ia;
u32* gp = c32arr_ptr(gg[gi]);
for (usz i = 0; i < l; i++) {
HARR_ADDA(ph, m_hVec2(m_c32(gp[i]), inc(pr[i])));
}
pr+= l;
}
return HARR_FV(ph);
}
B rebqn_exec(B str, B path, B args, B o) {
B prevRe = comp_currRe; comp_currRe = inc(o);
B* op = harr_ptr(o);
i32 replMode = o2iu(op[0]);
Scope* sc = c(Scope, op[1]);
B res;
if (replMode>0) {
Block* block = bqn_compScc(str, path, args, sc, op[2], op[3], replMode==2);
comp_currRe = prevRe;
ptr_dec(sc->body);
sc->body = ptr_inc(block->bodies[0]);
res = execBlockInline(block, sc);
ptr_dec(block);
} else {
B rtsys = m_hVec2(inc(op[3]), incG(bi_sys));
Block* block = bqn_compc(str, path, args, op[2], rtsys);
dec(rtsys);
comp_currRe = prevRe;
res = m_funBlock(block, 0);
ptr_dec(block);
}
dec(o);
return res;
}
static NOINLINE B m_lvB_0( ) { return emptyHVec(); }
static NOINLINE B m_lvB_1(B a ) { return m_hVec1(a); }
static NOINLINE B m_lvB_2(B a, B b ) { return m_hVec2(a,b); }
static NOINLINE B m_lvB_3(B a, B b, B c ) { return m_hVec3(a,b,c); }
static NOINLINE B m_lvB_4(B a, B b, B c, B d) { return m_hVec4(a,b,c,d); }
static NOINLINE B m_lvi32_0( ) { return emptyIVec(); }
static NOINLINE B m_lvi32_1(i32 a ) { i32* rp; B r = m_i32arrv(&rp,1); rp[0]=a; return r; }
static NOINLINE B m_lvi32_2(i32 a, i32 b ) { i32* rp; B r = m_i32arrv(&rp,2); rp[0]=a; rp[1]=b; return r; }
static NOINLINE B m_lvi32_3(i32 a, i32 b, i32 c ) { i32* rp; B r = m_i32arrv(&rp,3); rp[0]=a; rp[1]=b; rp[2]=c; return r; }
static NOINLINE B m_lvi32_4(i32 a, i32 b, i32 c, i32 d) { i32* rp; B r = m_i32arrv(&rp,4); rp[0]=a; rp[1]=b; rp[2]=c; rp[3]=d; return r; }
void load_init() { // very last init function
comp_currPath = bi_N;
comp_currArgs = bi_N;
comp_currSrc = bi_N;
comp_currRe = bi_N;
gc_addFn(load_gcFn);
B fruntime[] = {
/* +-×÷⋆√⌊⌈|¬ */ bi_add , bi_sub , bi_mul , bi_div , bi_pow , bi_root , bi_floor , bi_ceil , bi_stile , bi_not,
/* ∧∨<>≠=≤≥≡≢ */ bi_and , bi_or , bi_lt , bi_gt , bi_ne , bi_eq , bi_le , bi_ge , bi_feq , bi_fne,
/* ⊣⊢⥊∾≍⋈↑↓↕« */ bi_ltack , bi_rtack , bi_shape , bi_join , bi_couple , bi_pair , bi_take , bi_drop , bi_ud , bi_shifta,
/* »⌽⍉/⍋⍒⊏⊑⊐⊒ */ bi_shiftb , bi_reverse, bi_N , bi_slash, bi_gradeUp, bi_gradeDown, bi_select, bi_pick , bi_indexOf, bi_count,
/* ∊⍷⊔!˙˜˘¨⌜⁼ */ bi_memberOf, bi_find , bi_group , bi_asrt , bi_const , bi_swap , bi_cell , bi_each , bi_tbl , bi_undo,
/* ´˝`∘○⊸⟜⌾⊘◶ */ bi_fold , bi_N , bi_scan , bi_atop , bi_over , bi_before , bi_after , bi_under, bi_val , bi_cond,
/* ⎉⚇⍟⎊ */ bi_N , bi_N , bi_repeat, bi_catch
};
bool rtComplete[] = {
/* +-×÷⋆√⌊⌈|¬ */ 1,1,1,1,1,1,1,1,1,1,
/* ∧∨<>≠=≤≥≡≢ */ 1,1,1,1,1,1,1,1,1,1,
/* ⊣⊢⥊∾≍⋈↑↓↕« */ 1,1,1,1,1,1,1,1,1,1,
/* »⌽⍉/⍋⍒⊏⊑⊐⊒ */ 1,1,0,1,1,1,1,1,1,1,
/* ∊⍷⊔!˙˜˘¨⌜⁼ */ 1,1,1,1,1,1,1,1,1,1,
/* ´˝`∘○⊸⟜⌾⊘◶ */ 1,0,1,1,1,1,1,1,1,1,
/* ⎉⚇⍟⎊ */ 0,0,1,1
};
assert(sizeof(fruntime)/sizeof(B) == rtLen);
for (u64 i = 0; i < rtLen; i++) inc(fruntime[i]);
B frtObj = m_caB(rtLen, fruntime);
#ifndef NO_RT
B provide[] = {bi_type,bi_fill,bi_log,bi_grLen,bi_grOrd,bi_asrt,bi_add,bi_sub,bi_mul,bi_div,bi_pow,bi_floor,bi_eq,bi_le,bi_fne,bi_shape,bi_pick,bi_ud,bi_tbl,bi_scan,bi_fillBy,bi_val,bi_catch};
#ifndef ALL_R0
B runtime_0[] = {bi_floor,bi_ceil,bi_stile,bi_lt,bi_gt,bi_ne,bi_ge,bi_rtack,bi_ltack,bi_join,bi_pair,bi_take,bi_drop,bi_select,bi_const,bi_swap,bi_each,bi_fold,bi_atop,bi_over,bi_before,bi_after,bi_cond,bi_repeat};
#else
Block* runtime0_b = load_compImport(
#include "gen/runtime0"
);
B r0r = m_funBlock(runtime0_b, 0); ptr_dec(runtime0_b);
B* runtime_0 = toHArr(r0r)->a;
#endif
Block* runtime_b = load_compImport(
#include "gen/runtime1"
);
#ifdef ALL_R0
dec(r0r);
#endif
B rtRes = m_funBlock(runtime_b, 0); ptr_dec(runtime_b);
SGet(rtRes);
B rtObjRaw = Get(rtRes,0);
B setPrims = Get(rtRes,1);
B setInv = Get(rtRes,2);
dec(rtRes);
dec(c1(setPrims, m_hVec2(incG(bi_decp), incG(bi_primInd)))); dec(setPrims);
dec(c2(setInv, incG(bi_setInvSwap), incG(bi_setInvReg))); dec(setInv);
if (c(Arr,rtObjRaw)->ia != rtLen) err("incorrectly defined rtLen!");
HArr_p runtimeH = m_harrUc(rtObjRaw);
SGet(rtObjRaw)
rt_undo = Get(rtObjRaw, n_undo ); gc_add(rt_undo);
rt_select = Get(rtObjRaw, n_select ); gc_add(rt_select);
rt_slash = Get(rtObjRaw, n_slash ); gc_add(rt_slash);
rt_join = Get(rtObjRaw, n_join ); gc_add(rt_join);
rt_ud = Get(rtObjRaw, n_ud ); gc_add(rt_ud);
rt_pick = Get(rtObjRaw, n_pick ); gc_add(rt_pick);
rt_take = Get(rtObjRaw, n_take ); gc_add(rt_take);
rt_drop = Get(rtObjRaw, n_drop ); gc_add(rt_drop);
rt_group = Get(rtObjRaw, n_group ); gc_add(rt_group);
rt_under = Get(rtObjRaw, n_under ); gc_add(rt_under);
rt_reverse = Get(rtObjRaw, n_reverse ); gc_add(rt_reverse);
rt_indexOf = Get(rtObjRaw, n_indexOf ); gc_add(rt_indexOf);
rt_count = Get(rtObjRaw, n_count ); gc_add(rt_count);
rt_memberOf= Get(rtObjRaw, n_memberOf); gc_add(rt_memberOf);
rt_find = Get(rtObjRaw, n_find ); gc_add(rt_find);
rt_cell = Get(rtObjRaw, n_cell ); gc_add(rt_cell);
for (usz i = 0; i < rtLen; i++) {
#ifdef RT_WRAP
r1Objs[i] = Get(rtObjRaw, i); gc_add(r1Objs[i]);
#endif
#ifdef ALL_R1
B r = Get(rtObjRaw, i);
#else
B r = rtComplete[i]? inc(fruntime[i]) : Get(rtObjRaw, i);
#endif
if (q_N(r)) err("· in runtime!\n");
if (isVal(r)) v(r)->flags|= i+1;
#ifdef RT_WRAP
r = rtWrap_wrap(r);
if (isVal(r)) v(r)->flags|= i+1;
#endif
runtimeH.a[i] = r;
}
dec(rtObjRaw);
B* runtime = runtimeH.a;
B rtObj = runtimeH.b;
load_rtObj = FAKE_RUNTIME? frtObj : rtObj;
load_compArg = m_hVec2(load_rtObj, incG(bi_sys)); gc_add(FAKE_RUNTIME? rtObj : frtObj);
gc_add(load_compArg);
#else
B* runtime = fruntime;
(void)frtObj;
(void)rtComplete;
(void)runtime;
#endif
#ifdef PRECOMP
Block* c = compile(
#include "gen/interp"
, bi_N, bi_N, bi_N, bi_N, NULL
);
B interp = m_funBlock(c, 0); ptr_dec(c);
print(interp);
printf("\n");
dec(interp);
#ifdef HEAP_VERIFY
heapVerify();
#endif
rtWrap_print();
CTR_FOR(CTR_PRINT)
print_allocStats();
exit(0);
#else // use compiler
B prevAsrt = runtime[n_asrt];
runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine
Block* comp_b = load_compImport(
#include "gen/compiles"
);
runtime[n_asrt] = prevAsrt;
load_glyphs = m_hVec3(m_str32(U"+-×÷⋆√⌊⌈|¬∧∨<>≠=≤≥≡≢⊣⊢⥊∾≍⋈↑↓↕«»⌽⍉/⍋⍒⊏⊑⊐⊒∊⍷⊔!"), m_str32(U"˙˜˘¨⌜⁼´˝`"), m_str32(U"∘○⊸⟜⌾⊘◶⎉⚇⍟⎊"));
load_compgen = m_funBlock(comp_b, 0); ptr_dec(comp_b);
load_comp = c1(load_compgen, inc(load_glyphs));
gc_add(load_compgen); gc_add(load_comp); gc_add(load_glyphs);
#if FORMATTER
Block* fmt_b = load_compImport(
#include "gen/formatter"
);
B fmtM = m_funBlock(fmt_b, 0); ptr_dec(fmt_b);
B fmtR = c1(fmtM, m_caB(4, (B[]){incG(bi_type), incG(bi_decp), incG(bi_glyph), incG(bi_repr)}));
SGet(fmtR)
load_fmt = Get(fmtR, 0); gc_add(load_fmt);
load_repr = Get(fmtR, 1); gc_add(load_repr);
dec(fmtR);
dec(fmtM);
#endif
gc_enable();
#endif // PRECOMP
}
B bqn_execFile(B path, B args) { // consumes both
return bqn_exec(file_chars(inc(path)), path, args);
}
void bqn_exit(i32 code) {
rtWrap_print();
CTR_FOR(CTR_PRINT)
print_allocStats();
exit(code);
}
static void freed_visit(Value* x) {
#if CATCH_ERRORS
err("visiting t_freed\n");
#endif
}
static void empty_free(Value* x) { err("FREEING EMPTY\n"); }
static void builtin_free(Value* x) { err("FREEING BUILTIN\n"); }
DEF_FREE(def) { }
static void def_visit(Value* x) { printf("(no visit for %d=%s)\n", x->type, type_repr(x->type)); }
static void def_print(B x) { printf("(%d=%s)", v(x)->type, type_repr(v(x)->type)); }
static bool def_canStore(B x) { return false; }
static B def_identity(B f) { return bi_N; }
static B def_get(Arr* x, usz n) { err("def_get"); }
static B def_getU(Arr* x, usz n) { err("def_getU"); }
static B def_m1_d(B m, B f ) { thrM("cannot derive this"); }
static B def_m2_d(B m, B f, B g) { thrM("cannot derive this"); }
static Arr* def_slice(B x, usz s, usz ia) { thrM("cannot slice non-array!"); }
B rt_invFnReg, rt_invFnSwap;
BB2B rt_invFnRegFn;
BB2B rt_invFnSwapFn;
B def_fn_im(B t, B x) { B fn = rt_invFnRegFn(rt_invFnReg, inc(t)); B r = c1(fn, x); dec(fn); return r; }
B def_fn_is(B t, B x) { B fn = rt_invFnSwapFn(rt_invFnSwap, inc(t)); B r = c1(fn, x); dec(fn); return r; }
B def_fn_iw(B t, B w, B x) { B fn = rt_invFnSwapFn(rt_invFnSwap, inc(t)); B r = c2(fn, w, x); dec(fn); return r; }
B def_fn_ix(B t, B w, B x) { B fn = rt_invFnRegFn(rt_invFnReg, inc(t)); B r = c2(fn, w, x); dec(fn); return r; }
B def_m1_im(Md1D* t, B x) { return def_fn_im(tag(t,FUN_TAG), x); }
B def_m1_iw(Md1D* t, B w, B x) { return def_fn_iw(tag(t,FUN_TAG), w, x); }
B def_m1_ix(Md1D* t, B w, B x) { return def_fn_ix(tag(t,FUN_TAG), w, x); }
B def_m2_im(Md2D* t, B x) { return def_fn_im(tag(t,FUN_TAG), x); }
B def_m2_iw(Md2D* t, B w, B x) { return def_fn_iw(tag(t,FUN_TAG), w, x); }
B def_m2_ix(Md2D* t, B w, B x) { return def_fn_ix(tag(t,FUN_TAG), w, x); }
#ifdef DONT_FREE
static B empty_get(Arr* x, usz n) {
x->type = x->flags;
B r = TIv(x,get)(x, n);
x->type = t_empty;
return r;
}
static B empty_getU(Arr* x, usz n) {
x->type = x->flags;
B r = TIv(x,getU)(x, n);
x->type = t_empty;
return r;
}
#endif
static void funBI_visit(Value* x) {
mm_visit(((BFn*)x)->rtInvReg);
}
static B funBI_imRt(B t, B x) {
return c1(c(BFn, t)->rtInvReg, x);
}
static B funBI_imInit(B t, B x) {
B f = c(BFn, t)->rtInvReg = c1(rt_invFnReg, inc(t));
c(BFn, t)->im = funBI_imRt;
return c1(f, x);
}
static NOINLINE B m_bfn(BB2B c1, BBB2B c2, u8 id) {
BFn* f = mm_alloc(sizeof(BFn), t_funBI);
f->c1 = c1;
f->c2 = c2;
f->extra = id;
f->ident = bi_N;
f->uc1 = def_fn_uc1;
f->ucw = def_fn_ucw;
f->im = funBI_imInit;
f->rtInvReg = m_f64(0);
B r = tag(f,FUN_TAG); gc_add(r);
return r;
}
static NOINLINE B m_bm1(M1C1 c1, M1C2 c2, u8 id) {
BMd1* m = mm_alloc(sizeof(BMd1), t_md1BI);
m->c1 = c1;
m->c2 = c2;
m->extra = id;
m->im = def_m1_im;
m->iw = def_m1_iw;
m->ix = def_m1_ix;
B r = tag(m,MD1_TAG); gc_add(r);
return r;
}
static NOINLINE B m_bm2(M2C1 c1, M2C2 c2, u8 id) {
BMd2* m = mm_alloc(sizeof(BMd2), t_md2BI);
m->c1 = c1;
m->c2 = c2;
m->extra = id;
m->uc1 = def_m2_uc1;
m->ucw = def_m2_ucw;
B r = tag(m,MD2_TAG); gc_add(r);
return r;
}
void base_init() { // very first init function
for (u64 i = 0; i < t_COUNT; i++) {
TIi(i,freeO) = def_freeO;
TIi(i,freeF) = def_freeF;
TIi(i,visit) = def_visit;
TIi(i,get) = def_get;
TIi(i,getU) = def_getU;
TIi(i,print) = def_print;
TIi(i,m1_d) = def_m1_d;
TIi(i,m2_d) = def_m2_d;
TIi(i,isArr) = false;
TIi(i,arrD1) = false;
TIi(i,elType) = el_B;
TIi(i,identity) = def_identity;
TIi(i,decompose) = def_decompose;
TIi(i,slice) = def_slice;
TIi(i,canStore) = def_canStore;
TIi(i,fn_uc1) = def_fn_uc1;
TIi(i,fn_ucw) = def_fn_ucw;
TIi(i,m1_uc1) = def_m1_uc1;
TIi(i,m1_ucw) = def_m1_ucw;
TIi(i,m2_uc1) = def_m2_uc1;
TIi(i,m2_ucw) = def_m2_ucw;
TIi(i,fn_im) = def_fn_im; TIi(i,m1_im) = def_m1_im; TIi(i,m2_im) = def_m2_im;
TIi(i,fn_is) = def_fn_is;
TIi(i,fn_iw) = def_fn_iw; TIi(i,m1_iw) = def_m1_iw; TIi(i,m2_iw) = def_m2_iw;
TIi(i,fn_ix) = def_fn_ix; TIi(i,m1_ix) = def_m1_ix; TIi(i,m2_ix) = def_m2_ix;
}
TIi(t_empty,freeO) = empty_free; TIi(t_freed,freeO) = def_freeO;
TIi(t_empty,freeF) = empty_free; TIi(t_freed,freeF) = def_freeF;
TIi(t_freed,visit) = freed_visit;
#ifdef DONT_FREE
TIi(t_empty,get) = empty_get;
TIi(t_empty,getU) = empty_getU;
#endif
TIi(t_shape,visit) = noop_visit;
TIi(t_funBI,visit) = TIi(t_md1BI,visit) = TIi(t_md2BI,visit) = noop_visit;
TIi(t_funBI,freeO) = TIi(t_md1BI,freeO) = TIi(t_md2BI,freeO) = builtin_free;
TIi(t_funBI,freeF) = TIi(t_md1BI,freeF) = TIi(t_md2BI,freeF) = builtin_free;
TIi(t_funBI,visit) = funBI_visit;
TIi(t_hashmap,visit) = noop_visit;
assert((MD1_TAG>>1) == (MD2_TAG>>1)); // just to be sure it isn't changed incorrectly, `isMd` depends on this
#define FA(N,X) bi_##N = m_bfn(N##_c1, N##_c2, pf_##N);
#define FM(N,X) bi_##N = m_bfn(N##_c1, c2_bad, pf_##N);
#define FD(N,X) bi_##N = m_bfn(c1_bad, N##_c2, pf_##N);
FOR_PFN(FA,FM,FD)
#undef FA
#undef FM
#undef FD
#define FA(N,X) bi_##N = m_bm1(N##_c1, N##_c2, pm1_##N);
#define FM(N,X) bi_##N = m_bm1(N##_c1, c2_bad, pm1_##N);
#define FD(N,X) bi_##N = m_bm1(c1_bad, N##_c2, pm1_##N);
FOR_PM1(FA,FM,FD)
#undef FA
#undef FM
#undef FD
#define FA(N,X) bi_##N = m_bm2(N##_c1, N##_c2, pm2_##N);
#define FM(N,X) bi_##N = m_bm2(m1c1_bad, N##_c2, pm2_##N);
#define FD(N,X) bi_##N = m_bm2(N##_c1, m1c2_bad, pm2_##N);
FOR_PM2(FA,FM,FD)
#undef FA
#undef FM
#undef FD
}
void cbqn_init() {
#define F(X) X##_init();
FOR_INIT(F)
#undef F
}
#undef FOR_INIT