uCBQN/src/load.c
2022-04-07 15:15:28 +03:00

678 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, bool nnbi); // consumes
void rtWrap_print(void);
// comp_currEnvPos/comp_currPath/comp_currArgs/comp_currSrc are only valid while evaluating through bqn_comp*; comp_currRe is valid at all times
i64 comp_currEnvPos;
B comp_currPath;
B comp_currArgs;
B comp_currSrc;
B comp_currRe;
B rt_undo, rt_select, rt_slash, rt_join, rt_ud, rt_pick, rt_take, rt_drop, rt_insert, rt_depth,
rt_group, rt_under, rt_reverse, rt_indexOf, rt_count, rt_memberOf, rt_find, rt_cell, rt_rank, rt_transp;
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);
decG(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) {
B vars = listVars(csc);
usz am = a(vars)->ia;
vName = vec_join(vName, vars);
for (usz i = 0; i < am; i++) 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;
if (CATCH) { comp_currRe = prevRe; rethrow(); }
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);
decG(rtsys);
comp_currRe = prevRe;
res = m_funBlock(block, 0);
ptr_dec(block);
}
decG(o);
popCatch();
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_transp, 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_insert , bi_scan , bi_atop , bi_over , bi_before , bi_after , bi_under, bi_val , bi_cond,
/* ⎉⚇⍟⎊ */ bi_rank , bi_depth , bi_repeat, bi_catch
};
bool rtComplete[] = { // if you unset any of these, also define WRAP_NNBI
/* +-×÷⋆√⌊⌈|¬ */ 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,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
};
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)))); decG(setPrims);
dec(c2(setInv, incG(bi_setInvSwap), incG(bi_setInvReg))); decG(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);
rt_rank = Get(rtObjRaw, n_rank ); gc_add(rt_rank);
rt_transp = Get(rtObjRaw, n_transp ); gc_add(rt_transp);
rt_depth = Get(rtObjRaw, n_depth ); gc_add(rt_depth);
rt_insert = Get(rtObjRaw, n_insert ); gc_add(rt_insert);
for (usz i = 0; i < rtLen; i++) {
#ifdef RT_WRAP
r1Objs[i] = Get(rtObjRaw, i); gc_add(r1Objs[i]);
#endif
#ifdef ALL_R1
bool nnbi = true;
B r = Get(rtObjRaw, i);
#else
bool nnbi = !rtComplete[i];
#if !defined(WRAP_NNBI)
if (nnbi) err("Refusing to load non-native builtin into runtime without -DWRAP_NNBI");
#endif
B r = nnbi? Get(rtObjRaw, i) : inc(fruntime[i]);
#endif
if (q_N(r)) err("· in runtime!\n");
if (isVal(r)) v(r)->flags|= i+1;
#if defined(RT_WRAP) || defined(WRAP_NNBI)
r = rtWrap_wrap(r, nnbi);
if (isVal(r)) v(r)->flags|= i+1;
#endif
runtimeH.a[i] = r;
}
decG(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");
decG(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)}));
decG(fmtM);
SGet(fmtR)
load_fmt = Get(fmtR, 0); gc_add(load_fmt);
load_repr = Get(fmtR, 1); gc_add(load_repr);
decG(fmtR);
#endif
gc_enable();
#endif // PRECOMP
}
B bqn_execFile(B path, B args) { // consumes both
return bqn_exec(path_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(FILE* f, B x) { fprintf(f, "(%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;
if (x->type==t_empty) err("getting from empty without old type data");
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;
if (x->type==t_empty) err("getting from empty without old type data");
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(D1C1 c1, D1C2 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(D2C1 c1, D2C2 c2, u8 id) {
BMd2* m = mm_alloc(sizeof(BMd2), t_md2BI);
m->c1 = c1;
m->c2 = c2;
m->extra = id;
m->im = def_m2_im;
m->iw = def_m2_iw;
m->ix = def_m2_ix;
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, m1c2_bad, pm1_##N);
#define FD(N,X) bi_##N = m_bm1(m1c1_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(m2c1_bad, N##_c2, pm2_##N);
#define FD(N,X) bi_##N = m_bm2(N##_c1, m2c2_bad, pm2_##N);
FOR_PM2(FA,FM,FD)
#undef FA
#undef FM
#undef FD
}
bool cbqn_initialized;
void cbqn_init() {
#define F(X) X##_init();
FOR_INIT(F)
#undef F
cbqn_initialized = true;
}
#undef FOR_INIT