diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-10-05 06:20:08 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-10-05 06:20:08 -0700 |
commit | 7f7379793f4732b09350798c22d9ed22dd2f11ba (patch) | |
tree | de85d0c9cf8927395b3bb64b38272b261d6a8c4a /lib.c | |
parent | c17054aa390ce42e867d9ce7b5fd821e0c666d45 (diff) | |
download | txr-7f7379793f4732b09350798c22d9ed22dd2f11ba.tar.gz txr-7f7379793f4732b09350798c22d9ed22dd2f11ba.tar.bz2 txr-7f7379793f4732b09350798c22d9ed22dd2f11ba.zip |
New functions take, drop, {take,drop}-{while,until}.
* lib.c (take_list_fun, take_while_list_fun,
take_until_list_fun): New static functions.
(take, take_while, take_until, drop, drop_while,
drop_until): New functions.
* eval.c (eval_init): Register intrinsics take,
take-while, take-until, drop, drop-while, drop-until.
* txr.1: Documented.
Diffstat (limited to 'lib.c')
-rw-r--r-- | lib.c | 187 |
1 files changed, 187 insertions, 0 deletions
@@ -6625,6 +6625,193 @@ val pos_min(val seq, val testfun, val keyfun) return pos_max(seq, default_arg(testfun, less_f), keyfun); } +static val take_list_fun(val env, val lcons) +{ + cons_bind (list, count, env); + + rplaca(lcons, pop(&list)); + + if3(le((count = pred(count)), zero) || list == nil, + rplacd(lcons, nil), + rplacd(lcons, make_lazy_cons(lcons_fun(lcons)))); + + rplaca(env, list); + rplacd(env, count); + return nil; +} + +val take(val count, val seq) +{ + switch (type(seq)) { + case NIL: + return nil; + case CONS: + case LCONS: + if (le(count, zero)) + return nil; + return make_lazy_cons(func_f1(cons(seq, count), take_list_fun)); + case LSTR: + case LIT: + case STR: + case VEC: + return sub(seq, zero, count); + default: + type_mismatch(lit("take: ~s is not a sequence"), seq, nao); + } +} + +static val take_while_list_fun(val env, val lcons) +{ + cons_bind (list, cell, env); + cons_bind (pred, keyfun, cell); + + rplaca(lcons, pop(&list)); + + if (!funcall1(pred, funcall1(keyfun, car(list)))) + rplacd(lcons, nil); + else + rplacd(lcons, make_lazy_cons(lcons_fun(lcons))); + + rplaca(env, list); + return nil; +} + +val take_while(val pred, val seq, val keyfun) +{ + switch (type(seq)) { + case NIL: + return nil; + case CONS: + case LCONS: + keyfun = default_arg(keyfun, identity_f); + if (!funcall1(pred, funcall1(keyfun, (car(seq))))) + return nil; + return make_lazy_cons(func_f1(cons(seq, cons(pred, keyfun)), + take_while_list_fun)); + case LSTR: + case LIT: + case STR: + case VEC: + { + val pos = pos_if(notf(pred), seq, keyfun); + if (!pos) + return seq; + return sub(seq, zero, pos); + } + default: + type_mismatch(lit("take-while: ~s is not a sequence"), seq, nao); + } +} + +static val take_until_list_fun(val env, val lcons) +{ + cons_bind (list, cell, env); + cons_bind (pred, keyfun, cell); + val item = pop(&list); + + rplaca(lcons, item); + + if (funcall1(pred, funcall1(keyfun, item))) + rplacd(lcons, nil); + else + rplacd(lcons, make_lazy_cons(lcons_fun(lcons))); + + rplaca(env, list); + return nil; +} + +val take_until(val pred, val seq, val keyfun) +{ + switch (type(seq)) { + case NIL: + return nil; + case CONS: + case LCONS: + return make_lazy_cons(func_f1(cons(seq, cons(pred, keyfun)), + take_until_list_fun)); + case LSTR: + case LIT: + case STR: + case VEC: + { + val key = default_arg(keyfun, identity_f); + val pos = pos_if(pred, seq, key); + if (!pos) + return seq; + return sub(seq, zero, succ(pos)); + } + default: + type_mismatch(lit("take-until: ~s is not a sequence"), seq, nao); + } +} + +val drop(val count, val seq) +{ + if (le(count, zero)) + return seq; + return sub(seq, count, t); +} + +val drop_while(val pred, val seq, val keyfun) +{ + switch (type(seq)) { + case NIL: + return nil; + case CONS: + case LCONS: + keyfun = default_arg(keyfun, identity_f); + while (seq && funcall1(pred, funcall1(keyfun, car(seq)))) + pop(&seq); + return seq; + case LSTR: + case LIT: + case STR: + case VEC: + { + val key = default_arg(keyfun, identity_f); + val pos = pos_if(notf(pred), seq, key); + if (!pos) + return make_like(nil, seq); + return sub(seq, pos, t); + } + default: + type_mismatch(lit("drop-while: ~s is not a sequence"), seq, nao); + } +} + +val drop_until(val pred, val seq, val keyfun) +{ + switch (type(seq)) { + case NIL: + return nil; + case CONS: + case LCONS: + { + val key = default_arg(keyfun, identity_f); + val item; + + do { + item = pop(&seq); + } while (!funcall1(pred, funcall1(key, item))); + + return seq; + } + case LSTR: + case LIT: + case STR: + case VEC: + { + val key = default_arg(keyfun, identity_f); + val pos = pos_if(pred, seq, key); + if (!pos) + return seq; + return sub(seq, succ(pos), t); + } + default: + type_mismatch(lit("drop-until: ~s is not a sequence"), seq, nao); + } +} + val in(val seq, val item, val testfun, val keyfun) { switch (type(seq)) { |