From 21033fa3551b7b81638d747518ef8628d95094ab Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Fri, 16 Sep 2022 10:59:03 -0400 Subject: [PATCH] Move Group to its own file --- makefile | 2 +- src/builtins/group.c | 225 ++++++++++++++++++++++++++++++++++++ src/builtins/sfns.c | 265 ------------------------------------------- src/builtins/slash.c | 51 ++++++++- src/opt/single.c | 1 + 5 files changed, 277 insertions(+), 267 deletions(-) create mode 100644 src/builtins/group.c diff --git a/makefile b/makefile index 6da1bdf2..38b18583 100644 --- a/makefile +++ b/makefile @@ -198,7 +198,7 @@ ${bd}/%.o: src/jit/%.c @echo $< | cut -c 5- @$(CC_INC) $@.d -o $@ -c $< -builtins: ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o squeeze.o select.o slash.o sort.o selfsearch.o md1.o md2.o fns.o sysfn.o internal.o inverse.o} +builtins: ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o squeeze.o select.o slash.o group.o sort.o selfsearch.o md1.o md2.o fns.o sysfn.o internal.o inverse.o} ${bd}/%.o: src/builtins/%.c @echo $< | cut -c 5- @$(CC_INC) $@.d -o $@ -c $< diff --git a/src/builtins/group.c b/src/builtins/group.c new file mode 100644 index 00000000..7cca8b1a --- /dev/null +++ b/src/builtins/group.c @@ -0,0 +1,225 @@ +#include "../core.h" +#include "../utils/talloc.h" +#include "../utils/mut.h" +#include "../builtins.h" + +extern B ne_c2(B, B, B); +extern B slash_c1(B, B); +extern B slash_c2(B, B, B); +extern B select_c2(B, B, B); +extern B take_c2(B, B, B); +extern B drop_c2(B, B, B); +extern B join_c2(B, B, B); + +extern B rt_group; +B group_c2(B t, B w, B x) { + if (isArr(w)&isArr(x) && RNK(w)==1 && RNK(x)==1 && depth(w)==1) { + usz wia = IA(w); + usz xia = IA(x); + if (wia-xia > 1) thrF("โŠ”: โ‰ ๐•จ must be either โ‰ ๐•ฉ or one bigger (%sโ‰กโ‰ ๐•จ, %sโ‰กโ‰ ๐•ฉ)", wia, xia); + u8 we = TI(w,elType); + if (elInt(we)) { + if (we==el_bit) w = taga(cpyI8Arr(w)); + i64 ria = 0; + bool bad = false, sort = true; + usz neg = 0, change = 0; + void *wp0 = tyany_ptr(w); + #define CASE(T) case el_##T: { \ + T max = -1, prev = -1; \ + for (usz i = 0; i < xia; i++) { \ + T n = ((T*)wp0)[i]; \ + if (n>max) max = n; \ + bad |= n < -1; \ + neg += n == -1; \ + sort &= prev <= n; \ + change += prev != n; \ + prev = n; \ + } \ + if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ + i64 m=(i64)max+1; if (m>ria) ria=m; \ + break; } + switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) } + #undef CASE + if (bad) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); + if (ria > (i64)(USZ_MAX)) thrOOM(); + + Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); + B* rp = fillarr_ptr(r); + for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors + B xf = getFillQ(x); + + Arr* rf = arr_shVec(m_fillarrp(0)); fillarr_setFill(rf, m_f64(0)); + B z = taga(rf); + fillarr_setFill(r, z); + + TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; + // Both cases needed to make sure wia>0 for ip[wia-1] below + if (ria==0) goto intvec_ret; + if (neg==xia) { + for (usz i = 0; i < ria; i++) rp[i] = inc(z); + goto intvec_ret; + } + + u8 xe = TI(x,elType); + u8 width = elWidth(xe); + u64 xw; + if (xia>64 && (xw=(u64)xia*width)<=I32_MAX && changexia) w = C2(take, m_f64(xia), w); + B c = C2(ne, C2(drop, m_f64(-1), inc(w)), + C2(drop, m_f64( 1), inc(w))); + B ind = C1(slash, C2(join, m_f64(-1!=IGetU(w,0).f), c)); + w = C2(select, inc(ind), w); + #undef C1 + #undef C2 + if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind)); + if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w )); + wia = IA(ind); + + i32* ip = i32any_ptr(ind); + i32* wp = i32any_ptr(w); + usz i0 = ip[0]; + for (usz i=0; i32 && neg>xia/4+xia/8) { + if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); + B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); + w = slash_c2(m_f64(0), inc(m), w); + x = slash_c2(m_f64(0), m, x); xia = IA(x); + neg = 0; + } + if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w)); + i32* wp = i32any_ptr(w); + for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; + for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check + + switch (xe) { default: UD; + case el_i8: case el_c8: + case el_i16: case el_c16: + case el_i32: case el_c32: case el_f64: { + void* xp = tyany_ptr(x); + u8 xt = el2t(xe); + if (sort) { + for (usz j=0, i=neg*width; j=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; + case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; + case 4: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; + case 8: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((f64*)tyarr_ptr(rp[n]))[pos[n]++] = ((f64*)xp)[i]; } break; + } + break; + } + case el_bit: case el_B: { + for (usz i = 0; i < ria; i++) { + Arr* c = m_fillarrp(len[i]); + c->ia = 0; + fillarr_setFill(c, inc(xf)); + arr_shVec(c); + rp[i] = taga(c); + } + SLOW2("๐•จโŠ”๐•ฉ", w, x); + SGet(x) + for (usz i = 0; i < xia; i++) { + i32 n = wp[i]; + if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); + } + for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]; + break; + } + } + intvec_ret: + fillarr_setFill(rf, xf); + decG(w); decG(x); TFREE(pos); + return taga(r); + } else { + SLOW2("๐•จโŠ”๐•ฉ", w, x); + SGetU(w) + i64 ria = wia==xia? 0 : o2i64(GetU(w, xia)); + if (ria<-1) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); + ria--; + for (usz i = 0; i < xia; i++) { + B cw = GetU(w, i); + if (!q_i64(cw)) goto base; + i64 c = o2i64G(cw); + if (c>ria) ria = c; + if (c<-1) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); + } + if (ria > (i64)(USZ_MAX-1)) thrOOM(); + ria++; + TALLOC(i32, lenO, ria+1); i32* len = lenO+1; + TALLOC(i32, pos, ria); + for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; + for (usz i = 0; i < xia; i++) len[o2i64G(GetU(w, i))]++; + + Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); + B* rp = fillarr_ptr(r); + for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors + B xf = getFillQ(x); + + for (usz i = 0; i < ria; i++) { + Arr* c = m_fillarrp(len[i]); + c->ia = 0; + fillarr_setFill(c, inc(xf)); + arr_shVec(c); + rp[i] = taga(c); + } + Arr* rf = m_fillarrp(0); arr_shVec(rf); + fillarr_setFill(rf, xf); + fillarr_setFill(r, taga(rf)); + SGet(x) + for (usz i = 0; i < xia; i++) { + i64 n = o2i64G(GetU(w, i)); + if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); + } + for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]; + decG(w); decG(x); TFREE(lenO); TFREE(pos); + return taga(r); + } + } + base: + return c2(rt_group, w, x); +} +B ud_c1(B, B); +B group_c1(B t, B x) { + if (isArr(x) && RNK(x)==1 && TI(x,arrD1)) { + usz ia = IA(x); + B range = ud_c1(t, m_f64(ia)); + return group_c2(m_f64(0), x, range); + } + return c1(rt_group, x); +} + diff --git a/src/builtins/sfns.c b/src/builtins/sfns.c index e4de367b..d635da65 100644 --- a/src/builtins/sfns.c +++ b/src/builtins/sfns.c @@ -811,222 +811,6 @@ B shifta_c2(B t, B w, B x) { return qWithFill(mut_fcd(r, x), f); } -extern B ne_c2(B, B, B); -extern B slash_c1(B, B); -extern B slash_c2(B, B, B); -extern B select_c2(B, B, B); -extern B rt_group; -B group_c2(B t, B w, B x) { - if (isArr(w)&isArr(x) && RNK(w)==1 && RNK(x)==1 && depth(w)==1) { - usz wia = IA(w); - usz xia = IA(x); - if (wia-xia > 1) thrF("โŠ”: โ‰ ๐•จ must be either โ‰ ๐•ฉ or one bigger (%sโ‰กโ‰ ๐•จ, %sโ‰กโ‰ ๐•ฉ)", wia, xia); - u8 we = TI(w,elType); - if (elInt(we)) { - if (we==el_bit) w = taga(cpyI8Arr(w)); - i64 ria = 0; - bool bad = false, sort = true; - usz neg = 0, change = 0; - void *wp0 = tyany_ptr(w); - #define CASE(T) case el_##T: { \ - T max = -1, prev = -1; \ - for (usz i = 0; i < xia; i++) { \ - T n = ((T*)wp0)[i]; \ - if (n>max) max = n; \ - bad |= n < -1; \ - neg += n == -1; \ - sort &= prev <= n; \ - change += prev != n; \ - prev = n; \ - } \ - if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ - i64 m=(i64)max+1; if (m>ria) ria=m; \ - break; } - switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) } - #undef CASE - if (bad) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); - if (ria > (i64)(USZ_MAX)) thrOOM(); - - Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); - B* rp = fillarr_ptr(r); - for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors - B xf = getFillQ(x); - - Arr* rf = arr_shVec(m_fillarrp(0)); fillarr_setFill(rf, m_f64(0)); - B z = taga(rf); - fillarr_setFill(r, z); - - TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; - // Both cases needed to make sure wia>0 for ip[wia-1] below - if (ria==0) goto intvec_ret; - if (neg==xia) { - for (usz i = 0; i < ria; i++) rp[i] = inc(z); - goto intvec_ret; - } - - u8 xe = TI(x,elType); - u8 width = elWidth(xe); - u64 xw; - if (xia>64 && (xw=(u64)xia*width)<=I32_MAX && changexia) w = C2(take, m_f64(xia), w); - B c = C2(ne, C2(drop, m_f64(-1), inc(w)), - C2(drop, m_f64( 1), inc(w))); - B ind = C1(slash, C2(join, m_f64(-1!=IGetU(w,0).f), c)); - w = C2(select, inc(ind), w); - #undef C1 - #undef C2 - if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind)); - if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w )); - wia = IA(ind); - - i32* ip = i32any_ptr(ind); - i32* wp = i32any_ptr(w); - usz i0 = ip[0]; - for (usz i=0; i32 && neg>xia/4+xia/8) { - if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); - B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); - w = slash_c2(m_f64(0), inc(m), w); - x = slash_c2(m_f64(0), m, x); xia = IA(x); - neg = 0; - } - if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w)); - i32* wp = i32any_ptr(w); - for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; - for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check - - switch (xe) { default: UD; - case el_i8: case el_c8: - case el_i16: case el_c16: - case el_i32: case el_c32: case el_f64: { - void* xp = tyany_ptr(x); - u8 xt = el2t(xe); - if (sort) { - for (usz j=0, i=neg*width; j=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; - case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; - case 4: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; - case 8: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((f64*)tyarr_ptr(rp[n]))[pos[n]++] = ((f64*)xp)[i]; } break; - } - break; - } - case el_bit: case el_B: { - for (usz i = 0; i < ria; i++) { - Arr* c = m_fillarrp(len[i]); - c->ia = 0; - fillarr_setFill(c, inc(xf)); - arr_shVec(c); - rp[i] = taga(c); - } - SLOW2("๐•จโŠ”๐•ฉ", w, x); - SGet(x) - for (usz i = 0; i < xia; i++) { - i32 n = wp[i]; - if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); - } - for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]; - break; - } - } - intvec_ret: - fillarr_setFill(rf, xf); - decG(w); decG(x); TFREE(pos); - return taga(r); - } else { - SLOW2("๐•จโŠ”๐•ฉ", w, x); - SGetU(w) - i64 ria = wia==xia? 0 : o2i64(GetU(w, xia)); - if (ria<-1) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); - ria--; - for (usz i = 0; i < xia; i++) { - B cw = GetU(w, i); - if (!q_i64(cw)) goto base; - i64 c = o2i64G(cw); - if (c>ria) ria = c; - if (c<-1) thrM("โŠ”: ๐•จ can't contain elements less than ยฏ1"); - } - if (ria > (i64)(USZ_MAX-1)) thrOOM(); - ria++; - TALLOC(i32, lenO, ria+1); i32* len = lenO+1; - TALLOC(i32, pos, ria); - for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; - for (usz i = 0; i < xia; i++) len[o2i64G(GetU(w, i))]++; - - Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); - B* rp = fillarr_ptr(r); - for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors - B xf = getFillQ(x); - - for (usz i = 0; i < ria; i++) { - Arr* c = m_fillarrp(len[i]); - c->ia = 0; - fillarr_setFill(c, inc(xf)); - arr_shVec(c); - rp[i] = taga(c); - } - Arr* rf = m_fillarrp(0); arr_shVec(rf); - fillarr_setFill(rf, xf); - fillarr_setFill(r, taga(rf)); - SGet(x) - for (usz i = 0; i < xia; i++) { - i64 n = o2i64G(GetU(w, i)); - if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); - } - for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]; - decG(w); decG(x); TFREE(lenO); TFREE(pos); - return taga(r); - } - } - base: - return c2(rt_group, w, x); -} -B ud_c1(B, B); -B group_c1(B t, B x) { - if (isArr(x) && RNK(x)==1 && TI(x,arrD1)) { - usz ia = IA(x); - B range = ud_c1(t, m_f64(ia)); - return group_c2(m_f64(0), x, range); - } - return c1(rt_group, x); -} - extern B rt_reverse; B reverse_c1(B t, B x) { if (isAtm(x) || RNK(x)==0) thrM("โŒฝ: Argument cannot be a unit"); @@ -1194,54 +978,6 @@ B pick_ucw(B t, B o, B w, B x) { return qWithFill(mut_fcd(r, x), xf); } -B slash_ucw(B t, B o, B w, B x) { - if (isAtm(w) || isAtm(x) || RNK(w)!=1 || RNK(x)!=1 || IA(w)!=IA(x)) return def_fn_ucw(t, o, w, x); - usz ia = IA(x); - SGetU(w) - if (!elInt(TI(w,elType))) for (usz i = 0; i < ia; i++) if (!q_i32(GetU(w,i))) return def_fn_ucw(t, o, w, x); - B arg = slash_c2(t, inc(w), inc(x)); - usz argIA = IA(arg); - B rep = c1(o, arg); - if (isAtm(rep) || RNK(rep)!=1 || IA(rep) != argIA) thrF("๐”ฝโŒพ(aโŠธ/)๐•ฉ: Result of ๐”ฝ must have the same shape as a/๐•ฉ (expected โŸจ%sโŸฉ, got %H)", argIA, rep); - MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), TI(rep,elType))); - SGet(x) - SGet(rep) - usz repI = 0; - if (TY(w) == t_bitarr) { - u64* d = bitarr_ptr(w); - if (elInt(TI(x,elType)) && elInt(TI(rep,elType))) { - if (r->fns->elType!=el_i32) mut_to(r, el_i32); - i32* rp = r->ai32; - x = toI32Any(x); i32* xp = i32any_ptr(x); - rep = toI32Any(rep); i32* np = i32any_ptr(rep); - for (usz i = 0; i < ia; i++) { - bool v = bitp_get(d, i); - i32 nc = np[repI]; - i32 xc = xp[i]; - rp[i] = v? nc : xc; - repI+= v; - } - } else { - MUTG_INIT(r); - for (usz i = 0; i < ia; i++) mut_setG(r, i, bitp_get(d, i)? Get(rep,repI++) : Get(x,i)); - } - } else { - SGetU(rep) - MUTG_INIT(r); - for (usz i = 0; i < ia; i++) { - i32 cw = o2iG(GetU(w, i)); - if (cw) { - B cr = Get(rep,repI); - if (CHECK_VALID) for (i32 j = 1; j < cw; j++) if (!equal(GetU(rep,repI+j), cr)) { mut_pfree(r,i); thrM("๐”ฝโŒพ(aโŠธ/): Incompatible result elements"); } - mut_setG(r, i, cr); - repI+= cw; - } else mut_setG(r, i, Get(x,i)); - } - } - decG(w); decG(rep); - return mut_fcd(r, x); -} - static B takedrop_ucw(i64 wi, B o, u64 am, B x, size_t xr) { usz xia = IA(x); usz csz = arr_csz(x); @@ -1327,7 +1063,6 @@ void sfns_init() { c(BFn,bi_pick)->uc1 = pick_uc1; c(BFn,bi_reverse)->uc1 = reverse_uc1; c(BFn,bi_pick)->ucw = pick_ucw; - c(BFn,bi_slash)->ucw = slash_ucw; c(BFn,bi_select)->ucw = select_ucw; // TODO move to new init fn c(BFn,bi_shape)->uc1 = shape_uc1; c(BFn,bi_transp)->uc1 = transp_uc1; diff --git a/src/builtins/slash.c b/src/builtins/slash.c index 437f9480..208aa15d 100644 --- a/src/builtins/slash.c +++ b/src/builtins/slash.c @@ -617,6 +617,55 @@ B slash_im(B t, B x) { } } +B slash_ucw(B t, B o, B w, B x) { + if (isAtm(w) || isAtm(x) || RNK(w)!=1 || RNK(x)!=1 || IA(w)!=IA(x)) return def_fn_ucw(t, o, w, x); + usz ia = IA(x); + SGetU(w) + if (!elInt(TI(w,elType))) for (usz i = 0; i < ia; i++) if (!q_i32(GetU(w,i))) return def_fn_ucw(t, o, w, x); + B arg = slash_c2(t, inc(w), inc(x)); + usz argIA = IA(arg); + B rep = c1(o, arg); + if (isAtm(rep) || RNK(rep)!=1 || IA(rep) != argIA) thrF("๐”ฝโŒพ(aโŠธ/)๐•ฉ: Result of ๐”ฝ must have the same shape as a/๐•ฉ (expected โŸจ%sโŸฉ, got %H)", argIA, rep); + MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), TI(rep,elType))); + SGet(x) + SGet(rep) + usz repI = 0; + if (TY(w) == t_bitarr) { + u64* d = bitarr_ptr(w); + if (elInt(TI(x,elType)) && elInt(TI(rep,elType))) { + if (r->fns->elType!=el_i32) mut_to(r, el_i32); + i32* rp = r->ai32; + x = toI32Any(x); i32* xp = i32any_ptr(x); + rep = toI32Any(rep); i32* np = i32any_ptr(rep); + for (usz i = 0; i < ia; i++) { + bool v = bitp_get(d, i); + i32 nc = np[repI]; + i32 xc = xp[i]; + rp[i] = v? nc : xc; + repI+= v; + } + } else { + MUTG_INIT(r); + for (usz i = 0; i < ia; i++) mut_setG(r, i, bitp_get(d, i)? Get(rep,repI++) : Get(x,i)); + } + } else { + SGetU(rep) + MUTG_INIT(r); + for (usz i = 0; i < ia; i++) { + i32 cw = o2iG(GetU(w, i)); + if (cw) { + B cr = Get(rep,repI); + if (CHECK_VALID) for (i32 j = 1; j < cw; j++) if (!equal(GetU(rep,repI+j), cr)) { mut_pfree(r,i); thrM("๐”ฝโŒพ(aโŠธ/): Incompatible result elements"); } + mut_setG(r, i, cr); + repI+= cw; + } else mut_setG(r, i, Get(x,i)); + } + } + decG(w); decG(rep); + return mut_fcd(r, x); +} + void slash_init() { c(BFn,bi_slash)->im = slash_im; -} \ No newline at end of file + c(BFn,bi_slash)->ucw = slash_ucw; +} diff --git a/src/opt/single.c b/src/opt/single.c index c225896d..f17124e3 100644 --- a/src/opt/single.c +++ b/src/opt/single.c @@ -17,6 +17,7 @@ #include "../builtins/sfns.c" #include "../builtins/select.c" #include "../builtins/slash.c" +#include "../builtins/group.c" #include "../builtins/sysfn.c" #include "../builtins/sort.c" #include "../builtins/selfsearch.c"