#include "core.h" #include "utils/file.h" #include "vm.h" #include "ns.h" #include "builtins.h" #include "load.h" #ifndef FAKE_RUNTIME #define FAKE_RUNTIME 0 #endif #define PRECOMPILED_FILE(END) STR1(../build/BYTECODE_DIR/gen/END) #define FOR_INIT(F) \ /* initialize primary things */ F(base) F(harr) F(mutF) F(cmpA) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arithm) F(arithd) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(inverse) F(slash) F(search) F(transp) F(ryu) F(ffi) F(mmap) \ /* first thing that executes BQN code (the precompiled stuff) */ F(load) \ /* precompiled stuff loaded; init things that need it */ F(sysfnPost) F(dervPost) F(typesFinished) #define F(X) NOINLINE 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 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[RT_LEN]; B rtWrap_wrap(B x, bool nnbi); // consumes void rtWrap_print(void); static NOINLINE B evalFunBlockConsume(Block* block) { B r = evalFunBlock(block, NULL); ptr_dec(block); return r; } HArr* comps_curr; B rt_undo, rt_select, rt_slash, rt_insert, rt_depth, rt_group, rt_under, rt_find; Block* load_buildBlock(B x, B src, B path, Scope* sc, i32 nsResult) { // consumes x,src SGet(x) usz xia = IA(x); if (xia!=6 & xia!=4) thrM("load_buildBlock: bad item count"); Block* r = xia==6? compileAll(Get(x,0),Get(x,1),Get(x,2),Get(x,3),Get(x,4),Get(x,5), src, inc(path), sc, nsResult) : compileAll(Get(x,0),Get(x,1),Get(x,2),Get(x,3),bi_N, bi_N, src, inc(path), sc, nsResult); decG(x); return r; } #if !(ONLY_NATIVE_COMP && !FORMATTER && NO_RT && NO_EXPLAIN) #include PRECOMPILED_FILE(src) #endif #if RT_SRC Block* load_importBlock(char* name, B bc, B objs, B blocks, B bodies, B inds, B src) { // consumes all return compileAll(bc, objs, blocks, bodies, inds, bi_N, src, m_c8vec_0(name), NULL, 0); } #else Block* load_importBlock(char* name, B bc, B objs, B blocks, B bodies) { // consumes all return compileAll(bc, objs, blocks, bodies, bi_N, bi_N, bi_N, m_c8vec_0(name), NULL, 0); } #endif B load_compgen; B def_re; static void change_def_comp(B comp) { // consumes B* re = harr_ptr(def_re); // not pretty changing in-place, but still should be fine and it's for an unsafe feature anyway B prev = re[re_comp]; re[re_comp] = comp; dec(prev); } #if NATIVE_COMPILER #include "opt/comp.c" B load_fullComp; void switchComp(void) { change_def_comp(harr_ptr(def_re)[re_comp].u==load_fullComp.u? incG(native_comp) : incG(load_fullComp)); } #endif B compObj_c1(B t, B x) { return evalFunBlockConsume(load_buildBlock(x, bi_N, bi_N, NULL, 0)); } B compObj_c2(B t, B w, B x) { change_def_comp(x); return w; } #if FORMATTER B load_fmt, load_repr; B bqn_fmt(B x) { // consumes return c1G(load_fmt, x); } B bqn_repr(B x) { // consumes return c1G(load_repr, x); } #else B bqn_fmt(B x) { return x; } B bqn_repr(B x) { return x; } #endif NOINLINE HArr* m_comps(B path, B args, B src, B re, i64 envPos) { assert(!q_N(re)); HArr* r = m_harr0v(comps_max).c; COMPS_REF(r, path) = inc(path); COMPS_REF(r, args) = inc(args); COMPS_REF(r, src) = inc(src); COMPS_REF(r, re) = inc(re); COMPS_REF(r, envPos) = m_f64(envPos); return r; } #define COMPS_PUSH(PATH, ARGS, STR, RE) \ assert(comps_curr == NULL); \ HArr* compsN = comps_curr = m_comps(PATH, ARGS, STR, RE, envCurr-envStart); \ if (CATCH) { COMPS_POP; rethrow(); } #define COMPS_POP ({ assert(comps_curr==compsN); ptr_dec(comps_curr); comps_curr = NULL; }) static NOINLINE Block* bqn_compc(B str, B path, B args, B re) { // consumes str,path,args str = chr_squeeze(str); COMPS_PUSH(path, args, str, re); B* o = harr_ptr(re); Block* r = load_buildBlock(c2G(o[re_comp], incG(o[re_compOpts]), inc(str)), str, path, NULL, 0); dec(path); dec(args); COMPS_POP; popCatch(); return r; } Block* bqn_comp(B str, B path, B args) { return bqn_compc(str, path, args, def_re); } Block* bqn_compScc(B str, B path, B args, B re, Scope* sc, bool loose, bool noNS) { str = chr_squeeze(str); COMPS_PUSH(path, args, str, re); B* o = harr_ptr(re); B vName = emptyHVec(); B vDepth = emptyIVec(); if (loose && (!sc || sc->psc)) thrM("VM compiler: REPL mode must be used at top level scope"); i32 depth = loose? -1 : 0; Scope* csc = sc; while (csc) { B vars = listVars(csc); usz am = IA(vars); vName = vec_join(vName, vars); for (usz i = 0; i < am; i++) vDepth = vec_addN(vDepth, m_i32(depth)); csc = csc->psc; depth++; } Block* r = load_buildBlock(c2G(o[re_comp], m_hvec4(incG(o[re_rt]), incG(bi_sys), vName, vDepth), inc(str)), str, path, sc, sc!=NULL? (noNS? -1 : 1) : 0); dec(path); dec(args); COMPS_POP; popCatch(); 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, def_re, sc, repl, false); } B bqn_exec(B str, B path, B args) { // consumes all return evalFunBlockConsume(bqn_comp(str, path, args)); } B str_all, str_none; void init_comp(B* new_re, B* prev_re, B prim, B sys) { if (q_N(prim)) { new_re[re_comp] = inc(prev_re[re_comp]); new_re[re_compOpts] = inc(prev_re[re_compOpts]); new_re[re_rt] = inc(prev_re[re_rt]); new_re[re_glyphs] = inc(prev_re[re_glyphs]); } else { if (!isArr(prim) || RNK(prim)!=1) thrM("β€’ReBQN: 𝕩.primitives must be a list"); usz pia = IA(prim); 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 || IA(p)!=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]++) = o2cG(IGet(gv, 0)); prh.a[np[t]++] = v; } new_re[re_rt] = prh.b; new_re[re_glyphs] = inc(rb); new_re[re_comp] = c1(load_compgen, rb); new_re[re_compOpts] = m_hvec2(inc(prh.b), incG(bi_sys)); } if (q_N(sys)) { inherit_sys: new_re[re_sysNames] = inc(prev_re[re_sysNames]); new_re[re_sysVals] = inc(prev_re[re_sysVals]); } else { if (!isArr(sys) || RNK(sys)!=1) thrM("β€’ReBQN: 𝕩.system must be a list"); if (str_all.u==0) { gc_add(str_all = m_c8vec("all",3)); gc_add(str_none = m_c8vec("none",4)); } if (equal(sys, str_all)) goto inherit_sys; if (equal(sys, str_none)) { new_re[re_sysNames] = new_re[re_sysVals] = emptyHVec(); } else { usz ia = IA(sys); SGetU(sys) M_HARR(nns, ia); M_HARR(nvs, ia); i8* inh; B inhA = m_i8arrv(&inh, ia); for (usz i = 0; i < ia; i++) { // write defined system values, inherited ones get inserted later B c = GetU(sys,i); B nn, nv; if (isStr(c)) { nn = incG(c); nv = bi_N; inh[i] = 1; } else { if (!isArr(c) || RNK(c)!=1 || IA(c)!=2) thrM("β€’ReBQN: 𝕩.system must be either \"all\", \"none\", or a list of names or pairs of name & value"); SGet(c) nn = Get(c,0); nv = Get(c,1); inh[i] = 0; } HARR_ADD(nns, i, nn); HARR_ADD(nvs, i, nv); } B nnsA = HARR_FV(nns); // system value inheriting B inhNs = C2(slash, incG(inhA), incG(nnsA)); usz inhN = IA(inhNs); if (inhN>0) { B prevN = prev_re[re_sysNames]; B prevV = prev_re[re_sysVals]; B idxs = C2(indexOf, incG(prevN), inhNs); B inhNIs = C1(slash, inhA); SGetU(idxs) SGet(prevV) SGetU(inhNIs) for (usz i = 0; i < inhN; i++) { usz oi = o2sG(GetU(inhNIs,i)); usz idx = o2sG(GetU(idxs,i)); if (idx == IA(prevN)) thrF("β€’ReBQN: No system value \"%R\" to inherit", IGet(nnsA, oi)); HARR_O(nvs).a[oi] = Get(prevV, idx); } decG(inhNIs); decG(idxs); } else { decG(inhNs); decG(inhA); } new_re[re_sysNames] = nnsA; new_re[re_sysVals] = HARR_FV(nvs); } } } B comps_getPrimitives(void) { B* o = harr_ptr(COMPS_CREF(re)); B r = o[re_rt]; B g = o[re_glyphs]; B* pr = harr_ptr(r); B* gg = harr_ptr(g); M_HARR(ph, IA(r)); for (usz gi = 0; gi < 3; gi++) { usz l = IA(gg[gi]); 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); } void comps_getSysvals(B* res) { B* o = harr_ptr(COMPS_CREF(re)); res[0] = o[re_sysNames]; res[1] = o[re_sysVals]; } B rebqn_exec(B str, B path, B args, B re) { return evalFunBlockConsume(bqn_compc(str, path, args, re)); } B repl_exec(B str, B path, B args, B re) { B* op = harr_ptr(re); i32 replMode = o2iG(op[re_mode]); if (replMode>0) { Scope* sc = c(Scope, op[re_scope]); Block* block = bqn_compScc(str, path, args, re, sc, replMode==2, true); ptr_dec(sc->body); sc->body = ptr_inc(block->bodies[0]); B res = execBlockInplace(block, sc); ptr_dec(block); return res; } else { return rebqn_exec(str, path, args, re); } } 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; } B invalidFn_c1(B t, B x); void comps_gcFn() { if (comps_curr!=NULL) mm_visitP(comps_curr); } void load_init() { // very last init function comps_curr = NULL; gc_addFn(comps_gcFn); gc_add_ref(&rt_invFnReg); gc_add_ref(&rt_invFnSwap); 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) == RT_LEN); for (u64 i = 0; i < RT_LEN; i++) inc(fruntime[i]); B frtObj = m_caB(RT_LEN, fruntime); B load_compOpts, load_rt; #if !NO_RT B provide[] = { /* actual 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 /* result list from commented-out β€’Out line in cc.bqn: */, bi_root,bi_not,bi_and,bi_or,bi_feq,bi_couple,bi_shifta,bi_shiftb,bi_reverse,bi_transp,bi_gradeUp,bi_gradeDown,bi_indexOf,bi_count,bi_memberOf,bi_cell,bi_rank }; #if !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_importBlock("(self-hosted runtime0)", #include PRECOMPILED_FILE(runtime0) ); HArr* r0r = toHArr(evalFunBlockConsume(runtime0_b)); B* runtime_0 = r0r->a; #endif Block* runtime_b = load_importBlock("(self-hosted runtime1)", #if ALL_R0 || ALL_R1 || NO_EXTENDED_PROVIDE || RT_VERIFY #include PRECOMPILED_FILE(runtime1) #else #include PRECOMPILED_FILE(runtime1x) #endif ); #if ALL_R0 ptr_dec(r0r); #endif B rtRes = evalFunBlockConsume(runtime_b); SGet(rtRes); B rtObjRaw = Get(rtRes,0); B setPrims = Get(rtRes,1); B setInv = Get(rtRes,2); dec(rtRes); dec(c1G(setPrims, m_hvec2(incG(bi_decp), incG(bi_primInd)))); decG(setPrims); dec(c2G(setInv, incG(bi_setInvSwap), incG(bi_setInvReg))); decG(setInv); if (IA(rtObjRaw) != RT_LEN) fatal("incorrectly defined RT_LEN!"); HArr_p runtimeH = m_harrUc(rtObjRaw); SGet(rtObjRaw) gc_add(rt_undo = Get(rtObjRaw, n_undo )); gc_add(rt_select = Get(rtObjRaw, n_select)); gc_add(rt_slash = Get(rtObjRaw, n_slash )); gc_add(rt_group = Get(rtObjRaw, n_group )); gc_add(rt_under = Get(rtObjRaw, n_under )); gc_add(rt_find = Get(rtObjRaw, n_find )); gc_add(rt_depth = Get(rtObjRaw, n_depth )); gc_add(rt_insert = Get(rtObjRaw, n_insert)); for (usz i = 0; i < RT_LEN; i++) { #ifdef RT_WRAP r1Objs[i] = Get(rtObjRaw, i); gc_add(r1Objs[i]); #endif #if ALL_R1 bool nnbi = true; B r = Get(rtObjRaw, i); #else bool nnbi = !rtComplete[i]; #if !defined(WRAP_NNBI) if (nnbi) fatal("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)) fatal("Β· 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; } NOGC_E; decG(rtObjRaw); B* runtime = runtimeH.a; B rtObj = runtimeH.b; load_rt = FAKE_RUNTIME? frtObj : rtObj; gc_add( FAKE_RUNTIME? rtObj : frtObj); #else // NO_RT B* runtime = fruntime; (void)frtObj; (void)rtComplete; (void)runtime; for (usz i = 0; i < RT_LEN; i++) { B r = fruntime[i]; if (isVal(r)) v(r)->flags|= i+1; } load_rt = frtObj; rt_select = rt_slash = rt_group = rt_find = bi_invalidFn; rt_undo = rt_insert = bi_invalidMd1; rt_under = rt_depth = bi_invalidMd2; rt_invFnRegFn = rt_invFnSwapFn = invalidFn_c1; rt_invFnReg = rt_invFnSwap = incByG(bi_invalidFn, 2); #endif load_compOpts = m_hvec2(load_rt, incG(bi_sys)); #ifdef PRECOMP decG(load_compOpts); Block* c = compileAll( #include "../build/interp" , bi_N, bi_N, bi_N, bi_N, NULL, 0 ); B interp = evalFunBlockConsume(c); printI(interp); printf("\n"); dec(interp); #if HEAP_VERIFY cbqn_heapVerify(); #endif bqn_exit(0); #else // use compiler B load_glyphs = m_hvec3(m_c32vec_0(U"+-Γ—Γ·β‹†βˆšβŒŠβŒˆ|¬∧∨<>β‰ =≀β‰₯β‰‘β‰’βŠ£βŠ’β₯ŠβˆΎβ‰β‹ˆβ†‘β†“β†•Β«Β»βŒ½β‰/β‹β’βŠβŠ‘βŠβŠ’βˆŠβ·βŠ”!"), m_c32vec_0(U"Λ™ΛœΛ˜Β¨βŒœβΌΒ΄Λ`"), m_c32vec_0(U"βˆ˜β—‹βŠΈβŸœβŒΎβŠ˜β—ΆβŽ‰βš‡βŸβŽŠ")); B load_comp; #if ONLY_NATIVE_COMP load_comp = m_f64(0); #else B prevAsrt = runtime[n_asrt]; runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine Block* comp_b = load_importBlock("(compiler)", #include PRECOMPILED_FILE(compiles) ); runtime[n_asrt] = prevAsrt; gc_add(load_compgen = evalFunBlockConsume(comp_b)); load_comp = c1(load_compgen, incG(load_glyphs)); #if NATIVE_COMPILER load_fullComp = load_comp; #endif #endif HArr_p ps = m_harr0v(re_max); ps.a[re_comp] = load_comp; ps.a[re_compOpts] = load_compOpts; ps.a[re_rt] = incG(load_rt); ps.a[re_glyphs] = load_glyphs; ps.a[re_sysNames] = incG(def_sysNames); ps.a[re_sysVals] = incG(def_sysVals); gc_add(def_re = ps.b); #if FORMATTER Block* fmt_b = load_importBlock("(formatter)", #include PRECOMPILED_FILE(formatter) ); B fmtM = evalFunBlockConsume(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) gc_add(load_fmt = Get(fmtR, 0)); gc_add(load_repr = Get(fmtR, 1)); decG(fmtR); #endif #endif // PRECOMP } B bqn_execFile(B path, B args) { // consumes both return bqn_exec(path_chars(inc(path)), path, args); } void before_exit(void); void bqn_exit(i32 code) { #ifdef DUMP_ON_EXIT cbqn_heapDump(NULL); #endif rtWrap_print(); print_allocStats(); before_exit(); exit(code); } static B load_explain; B bqn_explain(B str, B path) { #if NO_EXPLAIN thrM("Explainer not included in this CBQN build"); #else B* o = harr_ptr(def_re); if (load_explain.u==0) { B* runtime = harr_ptr(o[re_rt]); Block* expl_b = load_importBlock("(explain)", #include PRECOMPILED_FILE(explain) ); gc_add(load_explain = evalFunBlockConsume(expl_b)); } COMPS_PUSH(path, bi_N, str, def_re); B c = c2(o[re_comp], incG(o[re_compOpts]), inc(str)); COMPS_POP; B ret = c2(load_explain, c, str); return ret; #endif } static void freed_visit(Value* x) { #if CATCH_ERRORS fatal("visiting t_freed\n"); #endif } static void empty_free(Value* x) { fatal("FREEING EMPTY\n"); } static void builtin_free(Value* x) { fatal("FREEING BUILTIN\n"); } DEF_FREE(def) { } static void def_visit(Value* x) { fatal("undefined visit for object\n"); } 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) { fatal("def_get"); } static B def_getU(Arr* x, usz n) { fatal("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) { fatal("cannot slice non-array!"); } B rt_invFnReg, rt_invFnSwap; FC1 rt_invFnRegFn; FC1 rt_invFnSwapFn; B def_fn_im(B t, B x) { B fn = rt_invFnRegFn(rt_invFnReg, inc(t)); SLOW2("!runtime π•ŽβΌπ•©", t, x); 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)); SLOW2("!runtime π•ŽβΌπ•©", t, x); 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)); SLOW3("!runtime 𝕨F⁼𝕩", w, x, 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)); SLOW3("!runtime 𝕨F⁼𝕩", w, x, t); B r = c2(fn, w, x); dec(fn); return r; } B def_m1_im(Md1D* d, B x) { return def_fn_im(tag(d,FUN_TAG), x); } B def_m1_iw(Md1D* d, B w, B x) { return def_fn_iw(tag(d,FUN_TAG), w, x); } B def_m1_ix(Md1D* d, B w, B x) { return def_fn_ix(tag(d,FUN_TAG), w, x); } B def_m2_im(Md2D* d, B x) { return def_fn_im(tag(d,FUN_TAG), x); } B def_m2_iw(Md2D* d, B w, B x) { return def_fn_iw(tag(d,FUN_TAG), w, x); } B def_m2_ix(Md2D* d, B w, B x) { return def_fn_ix(tag(d,FUN_TAG), w, x); } #if DONT_FREE static B empty_get(Arr* x, usz n) { x->type = x->flags; if (x->type==t_empty) fatal("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) fatal("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); mm_visit(((BFn*)x)->rtInvSwap); } static B funBI_imRt(B t, B x) { return c1(c(BFn, t)->rtInvReg, x); } static B funBI_isRt(B t, B x) { return c1(c(BFn, t)->rtInvSwap, x); } static B funBI_iwRt(B t, B w, B x) { return c2(c(BFn, t)->rtInvSwap, w, x); } static B funBI_ixRt(B t, B w, B x) { return c2(c(BFn, t)->rtInvReg, w, x); } static B funBI_imInit(B t, B x) { B f=c(BFn,t)->rtInvReg; if(f.u==0) f=c(BFn,t)->rtInvReg =c1rt(invFnReg, incG(t)); c(BFn,t)->im=funBI_imRt; return c1(f, x); } static B funBI_isInit(B t, B x) { B f=c(BFn,t)->rtInvSwap; if(f.u==0) f=c(BFn,t)->rtInvSwap=c1rt(invFnSwap, incG(t)); c(BFn,t)->is=funBI_isRt; return c1(f, x); } static B funBI_ixInit(B t, B w, B x) { B f=c(BFn,t)->rtInvReg; if(f.u==0) f=c(BFn,t)->rtInvReg =c1rt(invFnReg, incG(t)); c(BFn,t)->ix=funBI_ixRt; return c2(f, w, x); } static B funBI_iwInit(B t, B w, B x) { B f=c(BFn,t)->rtInvSwap; if(f.u==0) f=c(BFn,t)->rtInvSwap=c1rt(invFnSwap, incG(t)); c(BFn,t)->iw=funBI_iwRt; return c2(f, w, x); } void* m_customObj(u64 size, V2v visit, V2v freeO) { CustomObj* r = mm_alloc(size, t_customObj); r->visit = visit; r->freeO = freeO; return r; } void customObj_visit(Value* v) { ((CustomObj*)v)->visit(v); } void customObj_freeO(Value* v) { ((CustomObj*)v)->freeO(v); } void customObj_freeF(Value* v) { ((CustomObj*)v)->freeO(v); mm_free(v); } void def_fallbackTriv(Value* v) { // used while vtables aren't yet fully loaded; should become completely unused after typesFinished_init TIv(v,freeF)(v); } static NOINLINE B m_bfn(FC1 c1, FC2 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->iw = funBI_iwInit; f->ix = funBI_ixInit; f->is = funBI_isInit; f->rtInvReg = m_f64(0); f->rtInvSwap = 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,freeT) = def_fallbackTriv; 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_invalid,freeO) = empty_free; TIi(t_freed,freeO) = def_freeO; TIi(t_empty,freeF) = empty_free; TIi(t_invalid,freeF) = empty_free; TIi(t_freed,freeF) = def_freeF; TIi(t_invalid,visit) = freed_visit; TIi(t_freed,visit) = freed_visit; #if DONT_FREE TIi(t_empty,get) = empty_get; TIi(t_empty,getU) = empty_getU; #endif TIi(t_shape,visit) = noop_visit; TIi(t_temp,visit) = noop_visit; TIi(t_talloc,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; TIi(t_customObj,freeO) = customObj_freeO; TIi(t_customObj,freeF) = customObj_freeF; TIi(t_customObj,visit) = customObj_visit; TIi(t_arbObj,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 } void typesFinished_init() { for (u64 i = 0; i < t_COUNT; i++) { if (TIi(i,freeT) == def_fallbackTriv) TIi(i,freeT) = TIi(i,freeF); } #if NATIVE_COMPILER nativeCompiler_init(); #if ONLY_NATIVE_COMP change_def_comp(incG(native_comp)); #endif #endif } bool cbqn_initialized; void cbqn_init() { if (cbqn_initialized) return; #define F(X) X##_init(); FOR_INIT(F) #undef F cbqn_initialized = true; gc_enable(); } #undef FOR_INIT