klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 1708898b996f5f0d23ef866d7eeb0548898e8ffc
parent 39d7a61e63fbeaf527e2bc9e20841456dc911c3e
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sat, 18 Aug 2012 17:05:14 -0300

Added continuation capturing awareness to filter. TODO tests

Diffstat:
Msrc/kghelpers.c | 35+++++++++++++++++++++++++++++++++++
Msrc/kghelpers.h | 6+++++-
Msrc/kgpairs_lists.c | 167+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/tests/pairs-and-lists.k | 3+++
4 files changed, 113 insertions(+), 98 deletions(-)

diff --git a/src/kghelpers.c b/src/kghelpers.c @@ -510,6 +510,41 @@ TValue check_copy_list(klisp_State *K, TValue obj, bool force_copy, } } +/* GC: assumes ls is rooted */ +TValue reverse_copy_and_encycle(klisp_State *K, TValue ls, int32_t pairs, + int32_t cpairs) +{ + if (pairs == 0) + return KNIL; + + int32_t apairs = pairs - cpairs; + TValue last = kcons(K, kcar(ls), KNIL); + ls = kcdr(ls); + krooted_vars_push(K, &last); + + if (cpairs > 0) { + --cpairs; + TValue last_cycle = last; + while (cpairs > 0) { + last = kcons(K, kcar(ls), last); + ls = kcdr(ls); + --cpairs; + } + kset_cdr(last_cycle, last); + } else { + --apairs; + } + + while (apairs > 0) { + last = kcons(K, kcar(ls), last); + ls = kcdr(ls); + --apairs; + } + + krooted_vars_pop(K); + return last; +} + TValue check_copy_env_list(klisp_State *K, TValue obj) { TValue copy = kcons(K, KNIL, KNIL); diff --git a/src/kghelpers.h b/src/kghelpers.h @@ -350,7 +350,6 @@ void check_typed_list(klisp_State *K, bool (*typep)(TValue), bool allow_infp, TValue obj, int32_t *pairs, int32_t *cpairs); /* check that obj is a list, returns the number of pairs */ -/* TODO change the return to void and add int32_t pairs obj */ void check_list(klisp_State *K, bool allow_infp, TValue obj, int32_t *pairs, int32_t *cpairs); @@ -362,6 +361,11 @@ void check_list(klisp_State *K, bool allow_infp, TValue obj, TValue check_copy_list(klisp_State *K, TValue obj, bool force_copy, int32_t *pairs, int32_t *cpairs); +/* Reverse the ls list and encycle the result if needed */ +/* GC: assumes ls is rooted */ +TValue reverse_copy_and_encycle(klisp_State *K, TValue ls, int32_t pairs, + int32_t cpairs); + /* check that obj is a list of environments and make a copy but don't keep the cycles */ /* GC: assume obj is rooted */ diff --git a/src/kgpairs_lists.c b/src/kgpairs_lists.c @@ -23,14 +23,9 @@ #include "kgpairs_lists.h" /* Continuations */ -void do_ret_cdr(klisp_State *K); - void do_memberp(klisp_State *K); void do_assoc(klisp_State *K); - -void do_filter_encycle(klisp_State *K); void do_filter(klisp_State *K); -void do_filter_cycle(klisp_State *K); void do_reduce(klisp_State *K); void do_reduce_prec(klisp_State *K); @@ -598,16 +593,32 @@ void do_filter(klisp_State *K) klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app - ** xparams[1]: (last-obj . rem-ls) - ** xparams[2]: last-pair in result list - ** xparams[3]: n + ** xparams[1]: (last-exp . rem-ls) + ** xparams[2]: acc + ** xparams[3]: rem-apairs (+1?) + ** xparams[4]: rem-cpairs (+1?) + ** xparams[5]: acc-apairs + ** xparams[6]: acc-cpairs */ TValue app = xparams[0]; TValue ls = xparams[1]; - TValue last_obj = kcar(ls); + TValue last_exp = kcar(ls); ls = kcdr(ls); - TValue last_pair = xparams[2]; - int32_t n = ivalue(xparams[3]); + TValue acc = xparams[2]; + int32_t apairs = ivalue(xparams[3]); + int32_t cpairs = ivalue(xparams[4]); + int32_t acc_apairs = ivalue(xparams[5]); + int32_t acc_cpairs = ivalue(xparams[6]); + + bool last_acyclicp; + + if (apairs > 0) { + last_acyclicp = true; + --apairs; + } else { + last_acyclicp = false; + --cpairs; + } if (!ttisboolean(obj)) { klispE_throw_simple(K, "expected boolean result"); @@ -615,68 +626,42 @@ void do_filter(klisp_State *K) } if (kis_true(obj)) { - TValue np = kcons(K, last_obj, KNIL); - kset_cdr(last_pair, np); - last_pair = np; + acc = kcons(K, last_exp, acc); + if (last_acyclicp) + ++acc_apairs; + else + ++acc_cpairs; } - if (n == 0) { - /* pass the rest of the list and last pair for cycle handling */ - kapply_cc(K, kcons(K, ls, last_pair)); + krooted_tvs_push(K, acc); /* push it in case an object was added above */ + + if (apairs > 0 || cpairs > 0) { + /* there is still some work to do */ + TValue new_env = kmake_empty_environment(K); + krooted_tvs_push(K, new_env); + /* have to unwrap the applicative to avoid extra evaluation of first */ + TValue new_expr = klist(K, 2, kunwrap(app), kcar(ls), KNIL); + krooted_tvs_push(K, new_expr); + TValue new_cont = + kmake_continuation(K, kget_cc(K), do_filter, 7, app, + ls, acc, i2tv(apairs), i2tv(cpairs), + i2tv(acc_apairs), i2tv(acc_cpairs)); + krooted_tvs_pop(K); /* acc, new_env & new_expr */ + krooted_tvs_pop(K); + krooted_tvs_pop(K); + + kset_cc(K, new_cont); /* this will avoid GC */ + ktail_eval(K, new_expr, new_env); } else { - TValue new_n = i2tv(n-1); - TValue first = kcar(ls); - TValue new_env = kmake_empty_environment(K); - krooted_tvs_push(K, new_env); - /* have to unwrap the applicative to avoid extra evaluation of first */ - TValue new_expr = klist(K, 2, kunwrap(app), first, KNIL); - krooted_tvs_push(K, new_expr); - TValue new_cont = - kmake_continuation(K, kget_cc(K), do_filter, 4, app, - ls, last_pair, new_n); - kset_cc(K, new_cont); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - ktail_eval(K, new_expr, new_env); + /* reverse-copy the list and encycle if necessary */ + /* GC: acc is already rooted */ + TValue res = reverse_copy_and_encycle(K, acc, acc_apairs + acc_cpairs, + acc_cpairs); + krooted_tvs_pop(K); + kapply_cc(K, res); } } -void do_filter_cycle(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - /* - ** xparams[0]: app - ** xparams[1]: (dummy . res-list) - ** xparams[2]: cpairs - */ - - TValue app = xparams[0]; - TValue dummy = xparams[1]; - TValue cpairs = xparams[2]; - - /* obj: (cycle-part . last-result-pair) */ - TValue ls = kcar(obj); - TValue last_apair = kcdr(obj); - - /* this continuation will close the cycle and return the list */ - TValue encycle_cont = - kmake_continuation(K, kget_cc(K), do_filter_encycle, 2, - dummy, last_apair); - krooted_tvs_push(K, encycle_cont); - /* schedule the filtering of the elements of the cycle */ - /* add inert before first element to be discarded when KFALSE - is received */ - TValue new_cont = - kmake_continuation(K, encycle_cont, do_filter, 4, app, - kcons(K, KINERT, ls), last_apair, cpairs); - kset_cc(K, new_cont); - krooted_tvs_pop(K); - /* this will be like a nop and will continue with do_filter */ - kapply_cc(K, KFALSE); -} - /* 6.3.5 filter */ void filter(klisp_State *K) { @@ -688,36 +673,28 @@ void filter(klisp_State *K) UNUSED(denv); bind_2tp(K, ptree, "applicative", ttisapplicative, app, "any", anytype, ls); + + if (ttisnil(ls)) { + kapply_cc(K, KNIL); + } + /* copy the list to ignore changes made by the applicative */ - /* REFACTOR: do this in a single pass */ - /* ASK John: the semantics when this is mixed with continuations, - isn't all that great..., but what are the expectations considering - there is no prescribed order? */ int32_t pairs, cpairs; check_list(K, true, ls, &pairs, &cpairs); - /* XXX: This was the paradigmatic use case of the force copy flag - in the old implementation, but it caused problems with continuations - Is there any other use case for force copy flag?? */ - ls = check_copy_list(K, ls, false, NULL, NULL); - /* This will be the list to be returned, but it will be copied - before to play a little nicer with continuations */ - TValue dummy = kcons(K, KINERT, KNIL); - krooted_tvs_push(K, dummy); - - TValue ret_cont = (cpairs == 0)? - kmake_continuation(K, kget_cc(K), do_ret_cdr, 1, dummy) - : kmake_continuation(K, kget_cc(K), do_filter_cycle, 3, - app, dummy, i2tv(cpairs)); - - krooted_tvs_pop(K); /* already in cont */ - krooted_tvs_push(K, ret_cont); - /* add inert before first element to be discarded when KFALSE - is received */ + ls = check_copy_list(K, ls, false, &pairs, &cpairs); + int apairs = pairs - cpairs; + + krooted_tvs_push(K, ls); + TValue dummy_ls = kcons(K, KINERT, ls); + krooted_tvs_pop(K); + krooted_tvs_push(K, dummy_ls); TValue new_cont = - kmake_continuation(K, ret_cont, do_filter, 4, app, - kcons(K, KINERT, ls), dummy, i2tv(pairs-cpairs)); + kmake_continuation(K, kget_cc(K), do_filter, 7, app, + dummy_ls, KNIL, i2tv(apairs+1), i2tv(cpairs), i2tv(0), i2tv(0)); + /* pass apairs + 1 to allow do_filter to tell whether the last evaluation was from + the acyclic or cyclic part */ + krooted_tvs_pop(K); kset_cc(K, new_cont); - krooted_tvs_pop(K); /* this will be a nop, and will continue with do_filter */ kapply_cc(K, KFALSE); } @@ -1352,14 +1329,10 @@ void kinit_pairs_lists_cont_names(klisp_State *K) { Table *t = tv2table(K->cont_name_table); - add_cont_name(K, t, do_ret_cdr, "return-cdr"); - add_cont_name(K, t, do_memberp, "member?-search"); add_cont_name(K, t, do_assoc, "assoc-search"); - add_cont_name(K, t, do_filter, "filter-acyclic-part"); - add_cont_name(K, t, do_filter_encycle, "filter-encycle!"); - add_cont_name(K, t, do_filter_cycle, "filter-cyclic-part"); + add_cont_name(K, t, do_filter, "filter"); add_cont_name(K, t, do_reduce, "reduce-acyclic-part"); add_cont_name(K, t, do_reduce_prec, "reduce-precycle"); diff --git a/src/tests/pairs-and-lists.k b/src/tests/pairs-and-lists.k @@ -235,6 +235,9 @@ (list 1 2 3)) ()) +;; filter + continuation capturing and mutation +;; TODO + ;; assoc ($check equal? (assoc #inert ()) ()) ($check equal? (assoc 3 (list (list 1 10) (list 2 20))) ())