diff --git a/src/builtins/internal.c b/src/builtins/internal.c index cdd01d8c..e1295860 100644 --- a/src/builtins/internal.c +++ b/src/builtins/internal.c @@ -233,7 +233,7 @@ static B internalNS; B getInternalNS() { if (internalNS.u == 0) { #define F(X) inc(bi_##X), - B fn = bqn_exec(m_str32(U"{⟨ Type, Refc, Squeeze, IsPure, Info, ListVariations, Variation, ClearRefs, Unshare⟩⇐𝕩}"), inc(bi_emptyHVec), inc(bi_emptyHVec)); + B fn = bqn_exec(m_str32(U"{⟨ Type, Refc, Squeeze, IsPure, Info, ListVariations, Variation, ClearRefs, Unshare⟩⇐𝕩}"), inc(bi_emptyCVec), inc(bi_emptySVec)); B arg = m_caB(9, (B[]){F(itype)F(refc)F(squeeze)F(isPure)F(info)F(listVariations)F(variation)F(clearRefs)F(unshare)}); #undef F internalNS = c1(fn,arg); diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 2d54be76..fbb308e0 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -175,7 +175,7 @@ B hash_c1(B t, B x) { static B rand_ns; static B rand_rangeName; static i32 rand_a, rand_b; -static NFnDesc* rand_range; +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"); @@ -210,9 +210,9 @@ B rand_range_c2(B t, B w, B x) { } static NOINLINE void rand_init() { - rand_ns = bqn_exec(m_str32(U"{a←𝕨⋄b←𝕩⋄range⇐0}"), inc(bi_emptyHVec), inc(bi_emptyHVec)); gc_add(rand_ns); + 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_range = registerNFn(m_str32(U"(rand).Range"), rand_range_c1, rand_range_c2); + rand_rangeDesc = registerNFn(m_str32(U"(rand).Range"), rand_range_c1, rand_range_c2); B tmp = c1(rand_ns, m_f64(0)); rand_a = ns_pos(tmp, m_str32(U"a")); rand_b = ns_pos(tmp, m_str32(U"b")); @@ -222,21 +222,21 @@ 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_range, inc(r))); + ns_set(r, rand_rangeName, m_nfn(rand_rangeDesc, inc(r))); return r; } static NFnDesc* fCharsDesc; -B fchars_c1(B d, B x) { B base = nfn_objU(d); - return file_chars(path_resolve(base, x)); +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) { B base = nfn_objU(d); - file_write(path_resolve(base, w), x); +B fchars_c2(B d, B w, B x) { + file_write(path_resolve(nfn_objU(d), w), x); return x; } static NFnDesc* fBytesDesc; -B fbytes_c1(B d, B x) { B base = nfn_objU(d); - TmpFile* tf = file_bytes(path_resolve(base, x)); +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]; @@ -244,8 +244,8 @@ B fbytes_c1(B d, B x) { B base = nfn_objU(d); return r; } static NFnDesc* fLinesDesc; -B flines_c1(B d, B x) { B base = nfn_objU(d); - TmpFile* tf = file_bytes(path_resolve(base, x)); +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++) { @@ -270,11 +270,11 @@ B flines_c1(B d, B x) { B base = nfn_objU(d); return harr_fv(r); } static NFnDesc* importDesc; -B import_c1(B d, B x) { B base = nfn_objU(d); - return bqn_execFile(path_resolve(base, x), inc(bi_emptyHVec)); -} -B import_c2(B d, B w, B x) { B base = nfn_objU(d); - return bqn_execFile(path_resolve(base, x), w); +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 exit_c1(B t, B x) { @@ -283,16 +283,27 @@ B exit_c1(B t, B x) { B getInternalNS(); +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"type")) r.a[i] = inc(bi_type); else if (eqStr(c, U"decompose")) r.a[i] = inc(bi_decp); @@ -312,6 +323,7 @@ B sys_c1(B t, B x) { r.a[i] = inc(comp_currArgs); } else { dec(x); thrF("Unknown system function •%R", c); } } + dec(fileNS); return harr_fcd(r, x); } @@ -320,4 +332,8 @@ void sysfn_init() { 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); } diff --git a/src/core/c32arr.c b/src/core/c32arr.c index db412e95..4171e81a 100644 --- a/src/core/c32arr.c +++ b/src/core/c32arr.c @@ -44,6 +44,8 @@ void c32arr_init() { ti[t_i32arr].arrD1 = true; ti[t_i32slice].arrD1 = true; ti[t_c32arr].elType = el_c32; ti[t_c32slice].elType = el_c32; ti[t_c32arr].canStore = c32arr_canStore; - u32* tmp; bi_emptyCVec = m_c32arrv(&tmp, 0); - gc_add(bi_emptyCVec); + u32* tmp; bi_emptyCVec = m_c32arrv(&tmp, 0); gc_add(bi_emptyCVec); + bi_emptySVec = m_fillarrp(0); gc_add(bi_emptySVec); + arr_shVec(bi_emptySVec, 0); + fillarr_setFill(bi_emptySVec, bi_emptyCVec); } diff --git a/src/core/stuff.c b/src/core/stuff.c index 36239eaf..4ee3e63d 100644 --- a/src/core/stuff.c +++ b/src/core/stuff.c @@ -3,7 +3,7 @@ #include "../utils/utf.h" u64 allocB; // currently allocated number of bytes -B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec; +B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec; #define F(N) u64 N; CTR_FOR(F) #undef F diff --git a/src/h.h b/src/h.h index 304ca040..c89f315d 100644 --- a/src/h.h +++ b/src/h.h @@ -242,7 +242,7 @@ static const B bi_noVar = tag(1, TAG_TAG); static const B bi_badHdr = tag(2, TAG_TAG); static const B bi_optOut = tag(3, TAG_TAG); static const B bi_noFill = tag(5, TAG_TAG); -extern B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec; +extern B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec; static void dec(B x); static B inc(B x); static void ptr_dec(void* x); diff --git a/src/load.c b/src/load.c index 1160ea89..c436dbb8 100644 --- a/src/load.c +++ b/src/load.c @@ -365,7 +365,7 @@ static inline void base_init() { // very first init function #undef FD } -#define FOR_INIT(F) F(base) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) 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(load) +#define FOR_INIT(F) F(base) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) 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(load) F(sysfnPost) #define F(X) void X##_init(); FOR_INIT(F) #undef F diff --git a/src/main.c b/src/main.c index 61342315..56fec65c 100644 --- a/src/main.c +++ b/src/main.c @@ -89,17 +89,17 @@ int main(int argc, char* argv[]) { #define REQARG(X) if(*carg) { fprintf(stderr, "%s: -%s must end the option\n", argv[0], #X); exit(1); } if (i==argc) { fprintf(stderr, "%s: -%s requires an argument\n", argv[0], #X); exit(1); } case 'f': repl_init(); REQARG(f); goto execFile; case 'e': { repl_init(); REQARG(e); - dec(gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-e)"), inc(bi_emptyHVec))); + dec(gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-e)"), inc(bi_emptySVec))); break; } case 'p': { repl_init(); REQARG(p); - B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-p)"), inc(bi_emptyHVec)); + B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-p)"), inc(bi_emptySVec)); print(r); dec(r); printf("\n"); break; } case 'o': { repl_init(); REQARG(o); - B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-o)"), inc(bi_emptyHVec)); + B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-o)"), inc(bi_emptySVec)); printRaw(r); dec(r); printf("\n"); break; @@ -130,7 +130,7 @@ int main(int argc, char* argv[]) { B src = fromUTF8l(argv[i++]); B args; if (i==argc) { - args = inc(bi_emptyHVec); + args = inc(bi_emptySVec); } else { HArr_p ap = m_harrUv(argc-i); // eh whatever, erroring will exit anyways for (usz j = 0; j < argc-i; j++) { @@ -158,7 +158,7 @@ int main(int argc, char* argv[]) { size_t gl = 0; i64 read = getline(&ln, &gl, stdin); if (read<=0 || ln[0]==0 || ln[0]==10) break; - Block* block = bqn_compSc(fromUTF8(ln, strlen(ln)), inc(replPath), inc(bi_emptyHVec), gsc, true); + Block* block = bqn_compSc(fromUTF8(ln, strlen(ln)), inc(replPath), inc(bi_emptySVec), gsc, true); free(ln); ptr_dec(gsc->body); ptr_inc(block->body); diff --git a/src/nfns.h b/src/nfns.h index dd8730d5..ad9b3478 100644 --- a/src/nfns.h +++ b/src/nfns.h @@ -11,7 +11,7 @@ typedef struct NFn { // native function } NFn; NFnDesc* registerNFn(B name, BB2B c1, BBB2B c2); // should be called a constant number of times; consumes name -B m_nfn(NFnDesc* desc, B obj); +B m_nfn(NFnDesc* desc, B obj); // consumes obj B nfn_name(B x); // doesn't consume static B nfn_objU(B t) { return c(NFn,t)->obj; diff --git a/src/utils/file.c b/src/utils/file.c index 525983af..3edf7eb9 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -1,7 +1,9 @@ +#include #include "../core.h" #include "file.h" +#include "mut.h" -static FILE* file_open(B path, char* desc, char* mode) { // doesn't consume; can error +static FILE* file_open(B path, char* desc, char* mode) { // doesn't consume u64 plen = utf8lenB(path); TALLOC(char, p, plen+1); toUTF8(path, p); @@ -11,8 +13,18 @@ static FILE* file_open(B path, char* desc, char* mode) { // doesn't consume; can if (f==NULL) thrF("Couldn't %S file \"%R\"", desc, path); return f; } +static DIR* dir_open(B path) { // doesn't consume + u64 plen = utf8lenB(path); + TALLOC(char, p, plen+1); + toUTF8(path, p); + p[plen] = 0; + DIR* f = opendir(p); + TFREE(p); + if (f==NULL) thrF("Couldn't open directory \"%R\"", path); + return f; +} -TmpFile* file_bytes(B path) { // consumes; may throw +TmpFile* file_bytes(B path) { // consumes FILE* f = file_open(path, "read", "r"); fseek(f, 0, SEEK_END); u64 len = ftell(f); @@ -24,14 +36,14 @@ TmpFile* file_bytes(B path) { // consumes; may throw fclose(f); return src; } -B file_chars(B path) { // consumes; may throw +B file_chars(B path) { // consumes 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 +B path_resolve(B base, B rel) { // consumes rel; 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; @@ -52,7 +64,7 @@ B path_resolve(B base, B rel) { // consumes rel; may error; assumes base is a ch return r; } -B path_dir(B path) { // consumes; returns directory part of file path, with trailing slash; may error +B path_dir(B path) { // consumes; returns directory part of file path with trailing slash, or · assert(isArr(path) || isNothing(path)); if (isNothing(path)) return path; BS2B pgetU = TI(path).getU; @@ -72,7 +84,7 @@ B path_dir(B path) { // consumes; returns directory part of file path, with trai } -void file_write(B path, B x) { // consumes path; may throw +void file_write(B path, B x) { // consumes path FILE* f = file_open(path, "write to", "w"); u64 len = utf8lenB(x); @@ -84,3 +96,14 @@ void file_write(B path, B x) { // consumes path; may throw dec(path); fclose(f); } + +B file_list(B path) { + DIR* d = dir_open(path); + struct dirent *c; + B res = inc(bi_emptySVec); + while ((c = readdir(d)) != NULL) { + char* name = c->d_name; + if (name[0]=='.'? !(name[1]==0 || (name[1]=='.'&&name[2]==0)) : true) res = vec_add(res, m_str8l(name)); + } + return res; +} diff --git a/src/utils/file.h b/src/utils/file.h index d969d2a6..63379e24 100644 --- a/src/utils/file.h +++ b/src/utils/file.h @@ -6,9 +6,12 @@ typedef struct TmpFile { // to be turned into a proper I8Arr i8 a[]; } TmpFile; -B path_resolve(B base, B rel); // consumes rel; may error; assumes base is a char vector or bi_N -B path_dir(B path); // consumes; returns directory part of file path, with trailing slash; may error +B path_resolve(B base, B rel); // consumes rel; assumes base is a char vector or bi_N +B path_dir(B path); // consumes; returns directory part of file path, with trailing slash -TmpFile* file_bytes(B path); // consumes; may throw -B file_chars(B path); // consumes; may throw -void file_write(B path, B x); // consumes path; may throw +TmpFile* file_bytes(B path); // consumes +B file_chars(B path); // consumes + +void file_write(B path, B x); // consumes path + +B file_list(B path); // consumes