diff --git a/src/arith.c b/src/arith.c index 6b23d0c1..bd39b233 100644 --- a/src/arith.c +++ b/src/arith.c @@ -123,4 +123,4 @@ static inline void arith_init() { BI_FNS1(F) c(BFn,bi_floor)->ident = m_f64(1.0/0.0); c(BFn,bi_ceil )->ident = m_f64(-1.0/0.0); } -#undef F \ No newline at end of file +#undef F diff --git a/src/file.c b/src/file.c new file mode 100644 index 00000000..d0a60bd6 --- /dev/null +++ b/src/file.c @@ -0,0 +1,65 @@ +typedef struct TmpFile { // to be turned into a proper I8Arr + struct Arr; + i8 a[]; +} TmpFile; + +TmpFile* file_bytes(B path) { // consumes; may throw + u64 plen = utf8lenB(path); + char p[plen+1]; + toUTF8(path, p); + p[plen] = 0; + FILE* f = fopen(p, "r"); + if (f==NULL) thrM("Couldn't read file"); + fseek(f, 0, SEEK_END); + u64 len = ftell(f); + fseek(f, 0, SEEK_SET); + TmpFile* src = mm_allocN(fsizeof(TmpFile,a,u8,len), t_i8arr); + arr_shVec(tag(src,ARR_TAG), len); + fread((char*)src->a, 1, len, f); + fclose(f); + dec(path); + return src; +} +B file_chars(B path) { // consumes; may throw + TmpFile* c = file_bytes(path); + B r = fromUTF8((char*)c->a, c->ia); + ptr_dec(c); + return r; +} + +B path_resolve(B base, B rel) { // consumes rel; may error; assumes base is a char vector or bi_N + assert((isArr(base) || isNothing(base)) && isArr(rel)); + BS2B rgetU = TI(rel).getU; + usz ria = a(rel)->ia; + if (rnk(rel)!=1) thrM("Paths must be character vectors"); + for (usz i = 0; i < ria; i++) if (!isC32(rgetU(rel, i))) thrM("Paths must be character vectors"); + if (ria==0) { dec(rel); return inc(base); } + if (o2cu(rgetU(rel, 0))=='/') return rel; + if (isNothing(base)) thrM("Using relative path with no absolute base path known"); + BS2B bgetU = TI(base).getU; + usz bia = a(base)->ia; + bool has = bia && o2cu(bgetU(base, bia-1))=='/'; + u32* rp; B r = m_c32arrv(&rp, bia+ria+(has?0:1)); + usz ri = 0; + for (usz i = 0; i < bia-(has?1:0); i++) rp[ri++] = o2cu(bgetU(base, i)); + rp[ri++] = '/'; + for (usz i = 0; i < ria; i++) rp[ri++] = o2cu(rgetU(rel, i)); + dec(rel); + return r; +} + +B path_dir(B path) { // consumes; returns directory part of file path, with trailing slash; may error + BS2B pgetU = TI(path).getU; + usz pia = a(path)->ia; + for (usz i = 0; i < pia; i++) if (!isC32(pgetU(path, i))) thrM("Paths must be character vectors"); + for (usz i = pia-1; i >= 0; i--) { + if (o2cu(pgetU(path, i))=='/') { + B r = TI(path).slice(path, 0); + arr_shVec(r, i+1); + return r; + } + } + dec(path); + u32* rp; B r = m_c32arrv(&rp, 2); rp[0] = '.'; rp[1] = '/'; + return r; +} \ No newline at end of file diff --git a/src/fns.c b/src/fns.c index 6c0bd793..05163d79 100644 --- a/src/fns.c +++ b/src/fns.c @@ -186,4 +186,4 @@ static inline void fns_init() { BI_FNS1(F) ti[t_funBI].print = print_funBI; ti[t_funBI].identity = funBI_identity; } -#undef F \ No newline at end of file +#undef F diff --git a/src/h.h b/src/h.h index 140441dc..b5ddd381 100644 --- a/src/h.h +++ b/src/h.h @@ -126,7 +126,6 @@ char* format_type(u8 u) { /*sort.c*/ F(gradeUp,"⍋") \ /*sysfn.c*/ F(type,"•Type") F(decp,"•Decompose") F(primInd,"•PrimInd") F(glyph,"•Glyph") F(fill,"•FillFn") \ /*sysfn.c*/ F(grLen,"•GroupLen") F(grOrd,"•groupOrd") F(asrt,"!") F(sys,"•getsys") F(bqn,"•BQN") F(cmp,"•Cmp") F(internal,"•Internal") F(show,"•Show") F(out,"•Out") \ - /*sysfn.c*/ F(fchars,"•FChars") F(fbytes,"•FBytes") enum PrimFns { #define F(N,X) pf_##N, @@ -143,11 +142,13 @@ char* format_pf(u8 u) { enum PrimMd1 { pm1_none, pm1_tbl, pm1_each, pm1_fold, pm1_scan, pm1_const, pm1_swap, pm1_timed, // md1.c + pm1_fchars, pm1_fbytes, pm1_import, // md1.c }; char* format_pm1(u8 u) { switch(u) { default: case pf_none: return"(unknown 1-modifier)"; case pm1_tbl:return"⌜"; case pm1_each:return"¨"; case pm1_fold:return"´"; case pm1_scan:return"`"; case pm1_const:return"˙"; case pm1_swap:return"˜"; case pm1_timed:return"•_timed"; + case pm1_fchars:return"•FChars"; case pm1_fbytes:return"•FBytes"; case pm1_import:return"•Import"; } } enum PrimMd2 { @@ -254,7 +255,8 @@ B m_unit (B x); // consumes B m_hunit(B x); // consumes B m_str32(u32* s); // meant to be used as m_str32(U"{𝕨‿𝕩}"), so doesn't free for you -B bqn_exec(B str); // consumes +B bqn_exec(B str, B path); // consumes both +B bqn_execFile(B path); // consumes NOINLINE NORETURN void thr(B b); NOINLINE NORETURN void thrM(char* s); diff --git a/src/load.c b/src/load.c index 4c00efb4..d1bc90c5 100644 --- a/src/load.c +++ b/src/load.c @@ -23,13 +23,17 @@ B bqn_fmt(B x) { // consumes } #endif - -Block* bqn_comp(B str) { // consumes - inc(str); - return load_compObj(c2(load_comp, inc(load_compArg), str), str); +void load_gcFn() { mm_visit(comp_currPath); } +Block* bqn_comp(B str, B path) { // consumes + comp_currPath = path; + Block* r = load_compObj(c2(load_comp, inc(load_compArg), inc(str)), str); + dec(path); + comp_currPath = bi_N; + return r; } -B bqn_exec(B str) { // consumes - Block* block = bqn_comp(str); + +B bqn_exec(B str, B path) { // consumes both + Block* block = bqn_comp(str, path); B res = m_funBlock(block, 0); ptr_dec(block); return res; @@ -40,6 +44,8 @@ void bqn_setComp(B comp) { // consumes; doesn't unload old comp, but whatever } static inline void load_init() { + comp_currPath = bi_N; + gc_addFn(load_gcFn); B fruntime[] = { /* +-×÷⋆√⌊⌈|¬ */ bi_add , bi_sub , bi_mul , bi_div , bi_pow , bi_N , 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, @@ -155,6 +161,6 @@ static inline void load_init() { #endif // NO_COMP } -B bqn_execFile(B path) { - return bqn_exec(file_chars(path)); -} \ No newline at end of file +B bqn_execFile(B path) { // consumes + return bqn_exec(file_chars(inc(path)), path); +} diff --git a/src/main.c b/src/main.c index 024b54e3..4f635afa 100644 --- a/src/main.c +++ b/src/main.c @@ -37,6 +37,7 @@ #include "fillarr.c" #include "mut.c" #include "utf.c" +#include "file.c" #include "derv.c" #include "fns.c" #include "sfns.c" @@ -92,7 +93,7 @@ int main(int argc, char* argv[]) { size_t gl = 0; getline(&ln, &gl, stdin); if (ln[0]==0 || ln[0]==10) break; - Block* block = bqn_comp(fromUTF8(ln, strlen(ln))); + Block* block = bqn_comp(fromUTF8(ln, strlen(ln)), bi_N); free(ln); #ifdef TIME diff --git a/src/md1.c b/src/md1.c index 6ca1532d..4f8f6677 100644 --- a/src/md1.c +++ b/src/md1.c @@ -211,14 +211,28 @@ B timed_c1(B d, B x) { B f = c(Md1D,d)->f; return m_f64((ens-sns)/1e9); } +B fchars_c1(B d, B x) { B f = c(Md1D,d)->f; + return file_chars(path_resolve(f, x)); +} +B fbytes_c1(B d, B x) { B f = c(Md1D,d)->f; + TmpFile* tf = file_bytes(path_resolve(f, 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; +} +B import_c1(B d, B x) { B f = c(Md1D,d)->f; + return bqn_execFile(path_resolve(f, x)); +} + #define ba(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1BI, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); #define bd(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1BI, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = c1_invalid; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); #define bm(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1BI, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = c2_invalid;c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); void print_md1BI(B x) { printf("%s", format_pm1(c(Md1,x)->extra)); } -B bi_tbl, bi_each, bi_fold, bi_scan, bi_const, bi_swap, bi_timed; -static inline void md1_init() { ba(tbl) ba(each) ba(fold) ba(scan) ba(const) ba(swap) ba(timed) +B bi_tbl, bi_each, bi_fold, bi_scan, bi_const, bi_swap, bi_timed, bi_fchars, bi_fbytes, bi_import; +static inline void md1_init() { ba(tbl) ba(each) ba(fold) ba(scan) ba(const) ba(swap) ba(timed) bm(fchars) bm(fbytes) bm(import) ti[t_md1BI].print = print_md1BI; } diff --git a/src/mm_malloc.c b/src/mm_malloc.c index f346c8ed..b0e4ab98 100644 --- a/src/mm_malloc.c +++ b/src/mm_malloc.c @@ -29,4 +29,4 @@ void mm_visitP(void* x) { } u64 mm_round(usz x) { return x; } u64 mm_size(Value* x) { return -1; } u64 mm_totalAllocated() { return -1; } -void mm_forHeap(V2v f) { } \ No newline at end of file +void mm_forHeap(V2v f) { } diff --git a/src/stuff.c b/src/stuff.c index ffd8afef..fed8a34a 100644 --- a/src/stuff.c +++ b/src/stuff.c @@ -364,6 +364,7 @@ void printAllocStats() { #endif } +_Thread_local B comp_currPath; #define FOR_INIT(F) F(hdr) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) F(fns) F(sfns) F(arith) F(grade) F(md1) F(md2) F(sysfn) F(derv) F(comp) F(rtPerf) F(ns) F(load) #define F(X) static inline void X##_init(); FOR_INIT(F) @@ -373,4 +374,4 @@ void cbqn_init() { FOR_INIT(F) #undef F } -#undef FOR_INIT \ No newline at end of file +#undef FOR_INIT diff --git a/src/sysfn.c b/src/sysfn.c index a30241ea..90af11c4 100644 --- a/src/sysfn.c +++ b/src/sysfn.c @@ -137,7 +137,7 @@ B bqn_c1(B t, B x) { 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); + return bqn_exec(x, bi_N); } B cmp_c2(B t, B w, B x) { @@ -146,54 +146,17 @@ B cmp_c2(B t, B w, B x) { return r; } -typedef struct TmpFile { // to be turned into a proper I8Arr - struct Arr; - i8 a[]; -} TmpFile; -TmpFile* file_bytes(B path) { // consumes; may throw - u64 plen = utf8lenB(path); - char p[plen+1]; - toUTF8(path, p); - p[plen] = 0; - FILE* f = fopen(p, "r"); - if (f==NULL) thrM("Couldn't read file"); - fseek(f, 0, SEEK_END); - u64 len = ftell(f); - fseek(f, 0, SEEK_SET); - TmpFile* src = mm_allocN(fsizeof(TmpFile,a,u8,len), t_i8arr); - arr_shVec(tag(src,ARR_TAG), len); - fread((char*)src->a, 1, len, f); - fclose(f); - dec(path); - return src; -} -B file_chars(B path) { // consumes; may throw - TmpFile* c = file_bytes(path); - B r = fromUTF8((char*)c->a, c->ia); - ptr_dec(c); - return r; -} - -B fchars_c1(B t, B x) { - return file_chars(x); -} -B fbytes_c1(B t, B x) { - TmpFile* f = file_bytes(x); usz ia = f->ia; u8* p = (u8*)f->a; - u32* rp; B r = m_c32arrv(&rp, ia); - for (i64 i = 0; i < ia; i++) rp[i] = p[i]; - ptr_dec(f); - return r; -} - - - -#define F(A,M,D) M(type) M(decp) M(primInd) M(glyph) A(fill) A(grLen) D(grOrd) A(asrt) M(out) M(show) M(sys) M(bqn) D(cmp) D(internal) M(fchars) M(fbytes) +#define F(A,M,D) M(type) M(decp) M(primInd) M(glyph) A(fill) A(grLen) D(grOrd) A(asrt) M(out) M(show) M(sys) M(bqn) D(cmp) D(internal) BI_FNS0(F); static inline void sysfn_init() { BI_FNS1(F) } #undef F -B bi_timed; +static B makeRel(B md) { // doesn't consume + return m1_d(inc(md), path_dir(inc(comp_currPath))); +} + +B bi_timed, bi_fchars, bi_fbytes, bi_import; B sys_c1(B t, B x) { assert(isArr(x)); usz i = 0; @@ -210,8 +173,9 @@ B sys_c1(B t, B x) { 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"fchars")) r.a[i] = inc(bi_fchars); - else if (eqStr(c, U"fbytes")) r.a[i] = inc(bi_fbytes); + else if (eqStr(c, U"fchars")) r.a[i] = makeRel(bi_fchars); + else if (eqStr(c, U"fbytes")) r.a[i] = makeRel(bi_fbytes); + else if (eqStr(c, U"import")) r.a[i] = makeRel(bi_import); else { dec(x); thrM("Unknown system function"); } } return harr_fcd(r, x); diff --git a/src/utf.c b/src/utf.c index 9c1580a1..1019a5ba 100644 --- a/src/utf.c +++ b/src/utf.c @@ -19,12 +19,12 @@ B fromUTF8(char* s, i64 len) { u64 sz = 0; i64 j = 0; while (true) { - i8 l = utf8lenb((u8)s[j]); - if (l==-1) thrM("Invalid UTF-8"); if (j>=len) { if (j!=len) thrM("Invalid UTF-8"); break; } + i8 l = utf8lenb((u8)s[j]); + if (l==-1) thrM("Invalid UTF-8"); sz++; j+= l; } @@ -74,4 +74,4 @@ void toUTF8(B x, char* p) { // doesn't consume; doesn't verify anything; p must else if (c<=0xFFFF) { *p++ = 0xE0|c>>12; *p++ = 0x80|(c>>6 &0x3F);*p++ = 0x80|(c &0x3F); } else { *p++ = 0xF0|c>>18; *p++ = 0x80|(c>>12&0x3F);*p++ = 0x80|(c>>6&0x3F); *p++ = 0x80|(c&0x3F); } } -} \ No newline at end of file +}