uCBQN/src/builtins/sysfn.c
2021-06-29 22:54:37 +03:00

379 lines
11 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/hash.h"
#include "../utils/file.h"
#include "../utils/wyhash.h"
#include "../utils/builtins.h"
#include "../ns.h"
#include "../nfns.h"
B type_c1(B t, B x) {
i32 r = -1;
if (isArr(x)) r = 0;
else if (isI32(x)) r = 1;
else if (isF64(x)) r = 1;
else if (isC32(x)) r = 2;
else if (isFun(x)) r = 3;
else if (isMd1(x)) r = 4;
else if (isMd2(x)) r = 5;
else if (isNsp(x)) r = 6;
if (r==-1) { print(x); err(": getting type"); }
decR(x);
return m_i32(r);
}
B decp_c1(B t, B x) {
if (!isVal(x)) return m_v2(m_i32(-1), x);
if (v(x)->flags) return m_v2(m_i32(0), x);
return TI(x).decompose(x);
}
B primInd_c1(B t, B x) {
if (!isVal(x)) return m_i32(rtLen);
if (v(x)->flags) { B r = m_i32(v(x)->flags-1); dec(x); return r; }
dec(x);
return m_i32(rtLen);
}
B glyph_c1(B t, B x) {
return x;
}
B repr_c1(B t, B x) {
#define BL 100
if (isF64(x)) {
char buf[BL];
snprintf(buf, BL, "%.14g", x.f);
return m_str8(strlen(buf), buf);
} else {
#if FORMATTER
return bqn_repr(x);
#else
thrM("•Repr: Cannot represent non-numbers");
#endif
}
}
B fill_c1(B t, B x) {
B r = getFillE(x);
dec(x);
return r;
}
B fill_c2(B t, B w, B x) { // TODO not set fill for typed arrays
if (isArr(x)) {
B fill = asFill(w);
if (noFill(fill)) return x;
return withFill(x, fill);
}
dec(w);
return x;
}
B grLen_both(i64 ria, B x) {
usz ia = a(x)->ia;
BS2B xgetU = TI(x).getU;
for (usz i = 0; i < ia; i++) {
i64 c = o2i64u(xgetU(x, i));
if (c>ria) ria = c;
}
if (ria>USZ_MAX-1) thrOOM();
ria++;
i32* rp; B r = m_i32arrv(&rp, ria);
for (usz i = 0; i < ria; i++) rp[i] = 0;
for (usz i = 0; i < ia; i++) {
i64 n = o2i64u(xgetU(x, i));
if (n>=0) rp[n]++;
assert(n>=-1);
}
dec(x);
return r;
}
B grLen_c1(B t, B x) { return grLen_both( -1, x); } // assumes valid arguments
B grLen_c2(B t, B w, B x) { return grLen_both(o2i64u(w)-1, x); } // assumes valid arguments
B grOrd_c2(B t, B w, B x) { // assumes valid arguments
usz wia = a(w)->ia;
usz xia = a(x)->ia;
if (wia==0) { dec(w); dec(x); return inc(bi_emptyIVec); }
if (xia==0) { dec(w); return x; }
BS2B wgetU = TI(w).getU;
BS2B xgetU = TI(x).getU;
TALLOC(usz, tmp, wia);
tmp[0] = 0;
for (usz i = 1; i < wia; i++) tmp[i] = tmp[i-1]+o2su(wgetU(w,i-1));
usz ria = tmp[wia-1]+o2su(wgetU(w,wia-1));
i32* rp; B r = m_i32arrv(&rp, ria);
if (xia>=I32_MAX) thrM("⊔: Too large");
for (usz i = 0; i < xia; i++) {
i64 c = o2i64(xgetU(x,i));
if (c>=0) rp[tmp[c]++] = i;
}
dec(w); dec(x); TFREE(tmp);
return r;
}
B asrt_c1(B t, B x) {
if (isI32(x) && 1==(i32)x.u) return x;
if (isF64(x) && 1==x.f) return x;
dec(x);
thrM("Assertion error");
}
B asrt_c2(B t, B w, B x) {
if (isI32(x) && 1==(u32)x.u) { dec(w); return x; }
if (isF64(x) && 1==x.f) { dec(w); return x; }
dec(x);
thr(w);
}
B casrt_c1(B t, B x) {
if (isI32(x) && 1==(i32)x.u) return x;
if (isF64(x) && 1==x.f) return x;
unwindCompiler();
dec(x);
thrM("Compilation error");
}
B casrt_c2(B t, B w, B x) {
if (isI32(x) && 1==(u32)x.u) { dec(w); return x; }
if (isF64(x) && 1==x.f) { dec(w); return x; }
unwindCompiler();
dec(x);
if (isArr(w) && a(w)->ia==2) {
B w0 = TI(w).getU(w,0);
if (!isArr(w0) || a(w0)->ia<2) goto base;
B s = TI(w).get(w,1);
BS2B w0getU = TI(w0).getU;
AFMT("\n");
s = vm_fmtPoint(comp_currSrc, s, comp_currPath, o2s(w0getU(w0,0)), o2s(w0getU(w0,1))+1);
dec(w);
thr(s);
}
base:
thr(w);
}
B sys_c1(B t, B x);
B out_c1(B t, B x) { printRaw(x); putchar('\n'); return x; }
B show_c1(B t, B x) {
#if FORMATTER
B fmt = bqn_fmt(inc(x));
printRaw(fmt); dec(fmt);
#else
print(x);
#endif
putchar('\n');
return x;
}
B bqn_c1(B t, B x) {
if (isAtm(x) || rnk(x)!=1) thrM("•BQN: Argument must be a character vector");
if (a(x)->type!=t_c32arr && a(x)->type!=t_c32slice) {
usz ia = a(x)->ia;
BS2B xgetU = TI(x).getU;
for (usz i = 0; i < ia; i++) if (!isC32(xgetU(x,i))) thrM("•BQN: Argument must be a character vector");
}
return bqn_exec(x, bi_N, bi_N);
}
B cmp_c2(B t, B w, B x) {
B r = m_i32(compare(w, x));
dec(w); dec(x);
return r;
}
B hash_c2(B t, B w, B x) {
u64 secret[4]; make_secret(o2i64(w), secret);
u64 rv = bqn_hash(x, secret);
dec(x);
i32* rp; B r = m_i32arrv(&rp, 4);
rp[0] = (u16)(rv>>48); rp[1] = (u16)(rv>>32);
rp[2] = (u16)(rv>>16); rp[3] = (u16)(rv );
return r;
}
B hash_c1(B t, B x) {
u64 rv = bqn_hash(x, wy_secret);
dec(x);
i32* rp; B r = m_i32arrv(&rp, 4);
rp[0] = (u16)(rv>>48); rp[1] = (u16)(rv>>32);
rp[2] = (u16)(rv>>16); rp[3] = (u16)(rv );
return r;
}
static B rand_ns;
static B rand_rangeName;
static i32 rand_a, rand_b;
static NFnDesc* rand_rangeDesc;
B rand_range_c1(B t, B x) {
i64 xv = o2i64(x);
if (xv<0) thrM("(rand).Range: 𝕩 cannot be negative");
Scope* sc = c(NS,nfn_objU(t))->sc;
u64 seed = sc->vars[rand_a].u | sc->vars[rand_b].u<<32;
u64 rnd = wyrand(&seed);
sc->vars[rand_a].u = seed>>32;
sc->vars[rand_a].u = seed&0xFFFFFFFF;
return xv? m_f64(wy2u0k(rnd, xv)) : m_f64(wy2u01(rnd));
}
B rand_range_c2(B t, B w, B x) {
Scope* sc = c(NS,nfn_objU(t))->sc;
u64 seed = sc->vars[rand_a].u | sc->vars[rand_b].u<<32;
usz am = o2s(w);
i64 max = o2i64(x);
B r;
if (max<1) {
if (max!=0) thrM("(rand).Range: 𝕩 cannot be negative");
f64* rp; r = m_f64arrv(&rp, am);
for (usz i = 0; i < am; i++) rp[i] = wy2u01(wyrand(&seed));
} else if (max > I32_MAX) {
if (max >= 1ULL<<53) thrM("(rand).Range: 𝕩 must be less than 2⋆53");
f64* rp; r = m_f64arrv(&rp, am);
for (usz i = 0; i < am; i++) rp[i] = wy2u0k(wyrand(&seed), max);
} else {
i32* rp; r = m_i32arrv(&rp, am);
for (usz i = 0; i < am; i++) rp[i] = wy2u0k(wyrand(&seed), max);
}
sc->vars[rand_a].u = seed>>32;
sc->vars[rand_a].u = seed&0xFFFFFFFF;
return r;
}
static NOINLINE void rand_init() {
rand_ns = bqn_exec(m_str32(U"{a←𝕨⋄b←𝕩⋄range⇐0}"), inc(bi_emptyCVec), inc(bi_emptySVec)); gc_add(rand_ns);
rand_rangeName = m_str32(U"range"); gc_add(rand_rangeName);
rand_rangeDesc = registerNFn(m_str32(U"(rand).Range"), rand_range_c1, rand_range_c2);
B tmp = c2(rand_ns, m_f64(0), m_f64(0));
rand_a = ns_pos(tmp, m_str32(U"a"));
rand_b = ns_pos(tmp, m_str32(U"b"));
dec(tmp);
}
B makeRand_c1(B t, B x) {
if (!isNum(x)) thrM("•MakeRand: 𝕩 must be a number");
if (rand_ns.u==0) rand_init();
B r = c2(rand_ns, b(x.u>>32), b(x.u&0xFFFFFFFF));
ns_set(r, rand_rangeName, m_nfn(rand_rangeDesc, inc(r)));
return r;
}
static NFnDesc* fCharsDesc;
B fchars_c1(B d, B x) {
return file_chars(path_resolve(nfn_objU(d), x));
}
B fchars_c2(B d, B w, B x) {
file_wChars(path_resolve(nfn_objU(d), w), x);
return x;
}
static NFnDesc* fBytesDesc;
B fbytes_c1(B d, B x) {
TmpFile* tf = file_bytes(path_resolve(nfn_objU(d), x));
usz ia = tf->ia; u8* p = (u8*)tf->a;
u32* rp; B r = m_c32arrv(&rp, ia);
for (i64 i = 0; i < ia; i++) rp[i] = p[i];
ptr_dec(tf);
return r;
}
static NFnDesc* fLinesDesc;
B flines_c1(B d, B x) {
TmpFile* tf = file_bytes(path_resolve(nfn_objU(d), x));
usz ia = tf->ia; u8* p = (u8*)tf->a;
usz lineCount = 0;
for (usz i = 0; i < ia; i++) {
if (p[i]=='\n') lineCount++;
else if (p[i]=='\r') {
lineCount++;
if(i+1<ia && p[i+1]=='\n') i++;
}
}
if (ia && (p[ia-1]!='\n' && p[ia-1]!='\r')) lineCount++;
usz i = 0;
HArr_p r = m_harrs(lineCount, &i);
usz pos = 0;
while (i < lineCount) {
usz spos = pos;
while(pos<ia && p[pos]!='\n' && p[pos]!='\r') pos++;
r.a[i++] = fromUTF8((char*)p+spos, pos-spos);
if (p[pos]=='\r' && pos+1<ia && p[pos+1]=='\n') pos+= 2;
else pos++;
}
ptr_dec(tf);
return harr_fv(r);
}
static NFnDesc* importDesc;
B import_c1(B d, B x) { return bqn_execFile(path_resolve(nfn_objU(d), x), inc(bi_emptySVec)); }
B import_c2(B d, B w, B x) { return bqn_execFile(path_resolve(nfn_objU(d), x), w); }
static NFnDesc* listDesc;
B list_c1(B d, B x) {
return file_list(path_resolve(nfn_objU(d), x));
}
B delay_c1(B t, B x) {
f64 sf = o2f(x);
if (sf<0 || sf>1ULL<<63) thrF("•Delay: Bad argument: %f", sf);
struct timespec ts;
u64 s = (u64)sf;
ts.tv_sec = (u64)sf;
ts.tv_nsec = (u64)((sf-s)*1e9);
nanosleep(&ts, &ts);
return x; // TODO figure out how to return an actually correct thing
}
B exit_c1(B t, B x) {
bqn_exit(q_i32(x)? o2i(x) : 0);
}
B getInternalNS();
B getMathNS();
static B file_nsGen;
B sys_c1(B t, B x) {
assert(isArr(x));
usz i = 0;
HArr_p r = m_harrs(a(x)->ia, &i);
BS2B xgetU = TI(x).getU;
B fileNS = m_f64(0);
for (; i < a(x)->ia; i++) {
B c = xgetU(x,i);
if (eqStr(c, U"out")) r.a[i] = inc(bi_out);
else if (eqStr(c, U"show")) r.a[i] = inc(bi_show);
else if (eqStr(c, U"exit")) r.a[i] = inc(bi_exit);
else if (eqStr(c, U"file")) {
if(fileNS.u==m_f64(0).u) {
#define F(X) m_nfn(X##Desc, path_dir(inc(comp_currPath))),
B arg = m_caB(4, (B[]){F(list)F(fBytes)F(fChars)F(fLines)});
#undef F
fileNS = c1(file_nsGen,arg);
}
r.a[i] = inc(fileNS);
}
else if (eqStr(c, U"internal")) r.a[i] = getInternalNS();
else if (eqStr(c, U"math")) r.a[i] = getMathNS();
else if (eqStr(c, U"type")) r.a[i] = inc(bi_type);
else if (eqStr(c, U"decompose")) r.a[i] = inc(bi_decp);
else if (eqStr(c, U"primind")) r.a[i] = inc(bi_primInd);
else if (eqStr(c, U"bqn")) r.a[i] = inc(bi_bqn);
else if (eqStr(c, U"cmp")) r.a[i] = inc(bi_cmp);
else if (eqStr(c, U"timed")) r.a[i] = inc(bi_timed);
else if (eqStr(c, U"delay")) r.a[i] = inc(bi_delay);
else if (eqStr(c, U"hash")) r.a[i] = inc(bi_hash);
else if (eqStr(c, U"repr")) r.a[i] = inc(bi_repr);
else if (eqStr(c, U"makerand")) r.a[i] = inc(bi_makeRand);
else if (eqStr(c, U"fchars")) r.a[i] = m_nfn(fCharsDesc, path_dir(inc(comp_currPath)));
else if (eqStr(c, U"fbytes")) r.a[i] = m_nfn(fBytesDesc, path_dir(inc(comp_currPath)));
else if (eqStr(c, U"flines")) r.a[i] = m_nfn(fLinesDesc, path_dir(inc(comp_currPath)));
else if (eqStr(c, U"import")) r.a[i] = m_nfn(importDesc, path_dir(inc(comp_currPath)));
else if (eqStr(c, U"args")) {
if(isNothing(comp_currArgs)) thrM("No arguments present for •args");
r.a[i] = inc(comp_currArgs);
} else { dec(x); thrF("Unknown system function •%R", c); }
}
dec(fileNS);
return harr_fcd(r, x);
}
void sysfn_init() {
fCharsDesc = registerNFn(m_str32(U"•FChars"), fchars_c1, fchars_c2);
fLinesDesc = registerNFn(m_str32(U"•FLines"), flines_c1, c2_invalid);
fBytesDesc = registerNFn(m_str32(U"•FBytes"), fbytes_c1, c2_invalid);
importDesc = registerNFn(m_str32(U"•Import"), import_c1, import_c2);
listDesc = registerNFn(m_str32(U"•file.List"), list_c1, c2_invalid);
}
void sysfnPost_init() {
file_nsGen = bqn_exec(m_str32(U"{⟨List, Bytes, Chars, Lines⟩⇐𝕩}"), inc(bi_emptyCVec), inc(bi_emptySVec)); gc_add(file_nsGen);
}