klisp

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

commit 1aa0401c3e53c8e3ddaec8133f4d9b505b95812d
parent 6eaca8feb345e6f926c631a90c693e2c2917ccdd
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Wed, 22 Aug 2012 16:38:20 -0300

Some more refactoring in kstate and kcontinuation to move the interception code out of kstate and normalize the initialization of the ground environment.

Diffstat:
Msrc/Makefile | 3++-
Msrc/kcontinuation.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kcontinuation.h | 6++++++
Msrc/kgcontinuations.c | 51++++++++++++++++++++++++++++++++++++++-------------
Msrc/kgerrors.c | 48+++++++++++++++++++++++++++++++++++++++++++-----
Msrc/kgerrors.h | 5-----
Msrc/kground.c | 8+-------
Msrc/kstate.c | 242-------------------------------------------------------------------------------
Msrc/kstate.h | 9+--------
9 files changed, 284 insertions(+), 281 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -148,7 +148,8 @@ kbytevector.o: kbytevector.c kbytevector.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kgc.h kstring.h kchar.o: kchar.c kobject.h klimits.h klisp.h klispconf.h kcontinuation.o: kcontinuation.c kcontinuation.h kobject.h klimits.h \ - klisp.h klispconf.h kstate.h ktoken.h kmem.h kgc.h + klisp.h klispconf.h kstate.h ktoken.h kmem.h kpair.h kgc.h \ + kapplicative.h koperative.h kencapsulation.o: kencapsulation.c kobject.h klimits.h klisp.h \ klispconf.h kmem.h kstate.h ktoken.h kencapsulation.h kpair.h kgc.h kenvironment.o: kenvironment.c kenvironment.h kobject.h klimits.h klisp.h \ diff --git a/src/kcontinuation.c b/src/kcontinuation.c @@ -7,6 +7,8 @@ #include <stdarg.h> #include "kcontinuation.h" +#include "kpair.h" +#include "kapplicative.h" #include "kobject.h" #include "kstate.h" #include "kmem.h" @@ -50,3 +52,194 @@ TValue kmake_continuation(klisp_State *K, TValue parent, klisp_CFunction fn, kset_source_info(K, res, kget_csi(K)); return res; } + +/* +** +** Interception Handling +** +*/ + +/* Helper for continuation->applicative */ +/* this passes the operand tree to the continuation */ +void cont_app(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + TValue cont = xparams[0]; + /* guards and dynamic variables are handled in kcall_cont() */ + kcall_cont(K, cont, ptree); +} + +/* +** This is used to determine if cont is in the dynamic extent of +** some other continuation. That's the case iff that continuation +** was marked by the call to mark_iancestors(cont) +*/ + +/* TODO: maybe add some inlines here, profile first and check size difference */ +static void mark_iancestors(TValue cont) +{ + while(!ttisnil(cont)) { + kmark(cont); + cont = tv2cont(cont)->parent; + } +} + +static void unmark_iancestors(TValue cont) +{ + while(!ttisnil(cont)) { + kunmark(cont); + cont = tv2cont(cont)->parent; + } +} + +/* +** Returns the first interceptor whose dynamic extent includes cont +** or nil if there isn't any. The cont is implicitly passed because +** all of its improper ancestors are marked. +*/ +static TValue select_interceptor(TValue guard_ls) +{ + /* the guard list can't be cyclic, that case is + replaced by a simple list while copyng guards */ + while(!ttisnil(guard_ls)) { + /* entry is (selector . interceptor-op) */ + TValue entry = kcar(guard_ls); + TValue selector = kcar(entry); + if (kis_marked(selector)) + return kcdr(entry); /* only interceptor is important */ + guard_ls = kcdr(guard_ls); + } + return KNIL; +} + +/* +** Returns a list of entries like the following: +** (interceptor-op outer_cont . denv) +*/ + +/* GC: assume src_cont & dst_cont are rooted */ +TValue create_interception_list(klisp_State *K, TValue src_cont, + TValue dst_cont) +{ + mark_iancestors(dst_cont); + TValue ilist = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &ilist); + TValue tail = ilist; + TValue cont = src_cont; + + /* exit guards are from the inside to the outside, and + selected by destination */ + + /* the loop is until we find the common ancestor, that has to be marked */ + while(!kis_marked(cont)) { + /* only inner conts have exit guards */ + if (kis_inner_cont(cont)) { + klisp_assert(tv2cont(cont)->extra_size > 1); + TValue entries = tv2cont(cont)->extra[0]; /* TODO make a macro */ + + TValue interceptor = select_interceptor(entries); + if (!ttisnil(interceptor)) { + /* TODO make macros */ + TValue denv = tv2cont(cont)->extra[1]; + TValue outer = tv2cont(cont)->parent; + TValue outer_denv = kcons(K, outer, denv); + krooted_tvs_push(K, outer_denv); + TValue new_entry = kcons(K, interceptor, outer_denv); + krooted_tvs_pop(K); /* already in entry */ + krooted_tvs_push(K, new_entry); + TValue new_pair = kcons(K, new_entry, KNIL); + krooted_tvs_pop(K); + kset_cdr(tail, new_pair); + tail = new_pair; + } + } + cont = tv2cont(cont)->parent; + } + unmark_iancestors(dst_cont); + + /* entry guards are from the outside to the inside, and + selected by source, we create the list from the outside + by cons and then append it to the exit list to avoid + reversing */ + mark_iancestors(src_cont); + + cont = dst_cont; + TValue entry_int = KNIL; + krooted_vars_push(K, &entry_int); + + while(!kis_marked(cont)) { + /* only outer conts have entry guards */ + if (kis_outer_cont(cont)) { + klisp_assert(tv2cont(cont)->extra_size > 1); + TValue entries = tv2cont(cont)->extra[0]; /* TODO make a macro */ + /* this is rooted because it's a substructure of entries */ + TValue interceptor = select_interceptor(entries); + if (!ttisnil(interceptor)) { + /* TODO make macros */ + TValue denv = tv2cont(cont)->extra[1]; + TValue outer = cont; + TValue outer_denv = kcons(K, outer, denv); + krooted_tvs_push(K, outer_denv); + TValue new_entry = kcons(K, interceptor, outer_denv); + krooted_tvs_pop(K); /* already in entry */ + krooted_tvs_push(K, new_entry); + entry_int = kcons(K, new_entry, entry_int); + krooted_tvs_pop(K); + } + } + cont = tv2cont(cont)->parent; + } + + unmark_iancestors(src_cont); + + /* all interceptions collected, append the two lists and return */ + kset_cdr(tail, entry_int); + krooted_vars_pop(K); + krooted_vars_pop(K); + return kcdr(ilist); +} + +void do_interception(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + /* + ** xparams[0]: + ** xparams[1]: dst cont + */ + TValue ls = xparams[0]; + TValue dst_cont = xparams[1]; + if (ttisnil(ls)) { + /* all interceptors returned normally */ + /* this is a normal pass/not subject to interception */ + kset_cc(K, dst_cont); + kapply_cc(K, obj); + } else { + /* call the operative with the passed obj and applicative + for outer cont as ptree in the dynamic environment of + the corresponding call to guard-continuation in the + dynamic extent of the associated outer continuation. + If the operative normally returns a value, others + interceptions should be scheduled */ + TValue first = kcar(ls); + TValue op = kcar(first); + TValue outer = kcadr(first); + TValue denv = kcddr(first); + TValue app = kmake_applicative(K, cont_app, 1, outer); + krooted_tvs_push(K, app); + TValue ptree = klist(K, 2, obj, app); + krooted_tvs_pop(K); /* already in ptree */ + krooted_tvs_push(K, ptree); + TValue new_cont = kmake_continuation(K, outer, do_interception, + 2, kcdr(ls), dst_cont); + kset_cc(K, new_cont); + krooted_tvs_pop(K); + /* XXX: what to pass as si? */ + ktail_call(K, op, ptree, denv); + } +} diff --git a/src/kcontinuation.h b/src/kcontinuation.h @@ -14,4 +14,10 @@ TValue kmake_continuation(klisp_State *K, TValue parent, klisp_CFunction fn, int xcount, ...); +/* Interceptions */ +void cont_app(klisp_State *K); +TValue create_interception_list(klisp_State *K, TValue src_cont, + TValue dst_cont); +void do_interception(klisp_State *K); + #endif diff --git a/src/kgcontinuations.c b/src/kgcontinuations.c @@ -124,7 +124,6 @@ void guard_continuation(klisp_State *K) kapply_cc(K, inner_cont); } - /* 7.2.5 continuation->applicative */ void continuation_applicative(klisp_State *K) { @@ -138,17 +137,42 @@ void continuation_applicative(klisp_State *K) bind_1tp(K, ptree, "continuation", ttiscontinuation, cont); - /* cont_app is from kstate, it handles dynamic vars & - interceptions */ TValue app = kmake_applicative(K, cont_app, 1, cont); kapply_cc(K, app); } /* 7.2.6 root-continuation */ -/* done in kground.c/krepl.c */ +static void do_root_exit(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(xparams); + + /* TODO/REFACTOR move this to a end_loop function in kstate.c */ + /* Just save the value and end the loop */ + K->next_value = obj; + K->next_func = NULL; /* force the loop to terminate */ + return; +} + + +static void kinit_root_cont(klisp_State *K) +{ + klisp_assert(ttisinert(G(K)->root_cont)); + G(K)->root_cont = kmake_continuation(K, KNIL, do_root_exit, 0); + TValue str, tail, si; +#if KTRACK_SI + /* Add source info to the cont */ + str = kstring_new_b_imm(K, __FILE__); + tail = kcons(K, i2tv(__LINE__), i2tv(0)); + si = kcons(K, str, tail); + kset_source_info(K, G(K)->root_cont, si); +#endif +} /* 7.2.7 error-continuation */ -/* done in kground.c/krepl.c */ +/* done in kgerrors.c */ /* ** 7.3 Library features @@ -234,8 +258,7 @@ void kgexit(klisp_State *K) if (!get_opt_tpar(K, obj, "any", anytype)) obj = KINERT; - /* TODO: look out for guards and dynamic variables */ - /* should be probably handled in kcall_cont() */ + /* guards and dynamic variables are handled in kcall_cont() */ kcall_cont(K, G(K)->root_cont, obj); } @@ -260,13 +283,12 @@ void kinit_continuations_ground_env(klisp_State *K) add_applicative(K, ground_env, "continuation->applicative", continuation_applicative, 0); /* 7.2.6 root-continuation */ - klisp_assert(ttiscontinuation(G(K)->root_cont)); - add_value(K, ground_env, "root-continuation", - G(K)->root_cont); + kinit_root_cont(K); + add_value(K, ground_env, "root-continuation", G(K)->root_cont); + /* 7.2.7 error-continuation */ - klisp_assert(ttiscontinuation(G(K)->error_cont)); - add_value(K, ground_env, "error-continuation", - G(K)->error_cont); + /* done in kgerrors.c */ + /* 7.3.1 apply-continuation */ add_applicative(K, ground_env, "apply-continuation", apply_continuation, 0); @@ -288,4 +310,7 @@ void kinit_continuations_cont_names(klisp_State *K) Table *t = tv2table(G(K)->cont_name_table); add_cont_name(K, t, do_extended_cont, "extended-cont"); + add_cont_name(K, t, do_root_exit, "exit"); + /* this is defined in kcontinuation.c */ + add_cont_name(K, t, do_interception, "do-interception"); } diff --git a/src/kgerrors.c b/src/kgerrors.c @@ -75,8 +75,19 @@ void error_object_irritants(klisp_State *K) kapply_cc(K, err_obj->irritants); } +void do_error_exit(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(xparams); + + /* TEMP Just pass the error to the root continuation */ + kapply_cc(K, obj); +} + /* REFACTOR this is the same as do_pass_value */ -void do_exception_cont(klisp_State *K) +static void do_exception_cont(klisp_State *K) { TValue *xparams = K->next_xparams; TValue obj = K->next_value; @@ -88,13 +99,30 @@ void do_exception_cont(klisp_State *K) /* REFACTOR maybe this should be in kerror.c */ /* Create system-error-continuation. */ -void kinit_error_hierarchy(klisp_State *K) +static void kinit_error_hierarchy(klisp_State *K) { - klisp_assert(ttiscontinuation(G(K)->error_cont)); - klisp_assert(ttisinert(G(K)->system_error_cont)); + klisp_assert(ttisinert(G(K)->error_cont)); + G(K)->error_cont = kmake_continuation(K, G(K)->root_cont, + do_error_exit, 0); + TValue str, tail, si; + +#if KTRACK_SI + str = kstring_new_b_imm(K, __FILE__); + tail = kcons(K, i2tv(__LINE__), i2tv(0)); + si = kcons(K, str, tail); + kset_source_info(K, G(K)->error_cont, si); +#endif + + klisp_assert(ttisinert(G(K)->system_error_cont)); G(K)->system_error_cont = kmake_continuation(K, G(K)->error_cont, do_exception_cont, 0); +#if KTRACK_SI + str = kstring_new_b_imm(K, __FILE__); + tail = kcons(K, i2tv(__LINE__), i2tv(0)); + si = kcons(K, str, tail); + kset_source_info(K, G(K)->system_error_cont, si); +#endif } /* init ground */ @@ -122,6 +150,16 @@ void kinit_error_ground_env(klisp_State *K) See Common Lisp and mit scheme for examples */ - klisp_assert(ttiscontinuation(G(K)->system_error_cont)); + /* 7.2.7 error-continuation */ + kinit_error_hierarchy(K); + add_value(K, ground_env, "error-continuation", G(K)->error_cont); add_value(K, ground_env, "system-error-continuation", G(K)->system_error_cont); } + +void kinit_error_cont_names(klisp_State *K) +{ + Table *t = tv2table(G(K)->cont_name_table); + + add_cont_name(K, t, do_error_exit, "error"); + add_cont_name(K, t, do_exception_cont, "system-error"); +} diff --git a/src/kgerrors.h b/src/kgerrors.h @@ -12,9 +12,4 @@ /* init ground */ void kinit_error_ground_env(klisp_State *K); -/* Second stage of itialization of ground environment. Must be - * called after initializing general error continuation - * K->error_cont. */ -void kinit_error_hierarchy(klisp_State *K); - #endif diff --git a/src/kground.c b/src/kground.c @@ -62,13 +62,6 @@ */ void kinit_cont_names(klisp_State *K) { - /* TEMP root and error continuations are set here (they are in kstate) */ - Table *t = tv2table(G(K)->cont_name_table); - add_cont_name(K, t, do_root_exit, "exit"); - add_cont_name(K, t, do_error_exit, "error"); - /* TEMP this is also in kstate */ - add_cont_name(K, t, do_interception, "do-interception"); - /* TEMP repl ones should be done in the interpreter, and not in the init state */ kinit_repl_cont_names(K); @@ -88,6 +81,7 @@ void kinit_cont_names(klisp_State *K) #if KUSE_LIBFFI kinit_ffi_cont_names(K); #endif + kinit_error_cont_names(K); kinit_libraries_cont_names(K); } diff --git a/src/kstate.c b/src/kstate.c @@ -379,29 +379,6 @@ klisp_State *klisp_newstate(klisp_Alloc f, void *ud) /* TODO si */ g->module_params_sym = ksymbol_new_b(K, "module-parameters", KNIL); - /* Create the root and error continuation (will be added to the - environment in kinit_ground_env) */ - g->root_cont = kmake_continuation(K, KNIL, do_root_exit, 0); - -#if KTRACK_SI - /* Add source info to the cont */ - TValue str = kstring_new_b_imm(K, __FILE__); - TValue tail = kcons(K, i2tv(__LINE__), i2tv(0)); - si = kcons(K, str, tail); - kset_source_info(K, g->root_cont, si); -#endif - - g->error_cont = kmake_continuation(K, g->root_cont, do_error_exit, 0); - -#if KTRACK_SI - str = kstring_new_b_imm(K, __FILE__); - tail = kcons(K, i2tv(__LINE__), i2tv(0)); - si = kcons(K, str, tail); - kset_source_info(K, g->error_cont, si); -#endif - - /* this must be done before calling kinit_ground_env */ - kinit_error_hierarchy(K); kinit_ground_env(K); kinit_cont_names(K); @@ -476,33 +453,6 @@ void klisp_close (klisp_State *K) } /* -** Root and Error continuations -*/ -void do_root_exit(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - UNUSED(xparams); - - /* Just save the value and end the loop */ - K->next_value = obj; - K->next_func = NULL; /* force the loop to terminate */ - return; -} - -void do_error_exit(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - UNUSED(xparams); - - /* TEMP Just pass the error to the root continuation */ - kapply_cc(K, obj); -} - -/* ** Stacks memory management */ @@ -569,198 +519,6 @@ void ks_tbshrink(klisp_State *K, int32_t new_top) ks_tbsize(K) = new_size; } - -/* -** -** This is for handling interceptions -** TODO: move to a different file -** -*/ - -/* -** This is used to determine if cont is in the dynamic extent of -** some other continuation. That's the case iff that continuation -** was marked by the call to mark_iancestors(cont) -*/ - -/* TODO: maybe add some inlines here, profile first and check size difference */ -void mark_iancestors(TValue cont) -{ - while(!ttisnil(cont)) { - kmark(cont); - cont = tv2cont(cont)->parent; - } -} - -void unmark_iancestors(TValue cont) -{ - while(!ttisnil(cont)) { - kunmark(cont); - cont = tv2cont(cont)->parent; - } -} - -/* -** Returns the first interceptor whose dynamic extent includes cont -** or nil if there isn't any. The cont is implicitly passed because -** all of its improper ancestors are marked. -*/ -TValue select_interceptor(TValue guard_ls) -{ - /* the guard list can't be cyclic, that case is - replaced by a simple list while copyng guards */ - while(!ttisnil(guard_ls)) { - /* entry is (selector . interceptor-op) */ - TValue entry = kcar(guard_ls); - TValue selector = kcar(entry); - if (kis_marked(selector)) - return kcdr(entry); /* only interceptor is important */ - guard_ls = kcdr(guard_ls); - } - return KNIL; -} - -/* -** Returns a list of entries like the following: -** (interceptor-op outer_cont . denv) -*/ - -/* GC: assume src_cont & dst_cont are rooted */ -static inline TValue create_interception_list(klisp_State *K, TValue src_cont, - TValue dst_cont) -{ - mark_iancestors(dst_cont); - TValue ilist = kcons(K, KNIL, KNIL); - krooted_vars_push(K, &ilist); - TValue tail = ilist; - TValue cont = src_cont; - - /* exit guards are from the inside to the outside, and - selected by destination */ - - /* the loop is until we find the common ancestor, that has to be marked */ - while(!kis_marked(cont)) { - /* only inner conts have exit guards */ - if (kis_inner_cont(cont)) { - klisp_assert(tv2cont(cont)->extra_size > 1); - TValue entries = tv2cont(cont)->extra[0]; /* TODO make a macro */ - - TValue interceptor = select_interceptor(entries); - if (!ttisnil(interceptor)) { - /* TODO make macros */ - TValue denv = tv2cont(cont)->extra[1]; - TValue outer = tv2cont(cont)->parent; - TValue outer_denv = kcons(K, outer, denv); - krooted_tvs_push(K, outer_denv); - TValue new_entry = kcons(K, interceptor, outer_denv); - krooted_tvs_pop(K); /* already in entry */ - krooted_tvs_push(K, new_entry); - TValue new_pair = kcons(K, new_entry, KNIL); - krooted_tvs_pop(K); - kset_cdr(tail, new_pair); - tail = new_pair; - } - } - cont = tv2cont(cont)->parent; - } - unmark_iancestors(dst_cont); - - /* entry guards are from the outside to the inside, and - selected by source, we create the list from the outside - by cons and then append it to the exit list to avoid - reversing */ - mark_iancestors(src_cont); - - cont = dst_cont; - TValue entry_int = KNIL; - krooted_vars_push(K, &entry_int); - - while(!kis_marked(cont)) { - /* only outer conts have entry guards */ - if (kis_outer_cont(cont)) { - klisp_assert(tv2cont(cont)->extra_size > 1); - TValue entries = tv2cont(cont)->extra[0]; /* TODO make a macro */ - /* this is rooted because it's a substructure of entries */ - TValue interceptor = select_interceptor(entries); - if (!ttisnil(interceptor)) { - /* TODO make macros */ - TValue denv = tv2cont(cont)->extra[1]; - TValue outer = cont; - TValue outer_denv = kcons(K, outer, denv); - krooted_tvs_push(K, outer_denv); - TValue new_entry = kcons(K, interceptor, outer_denv); - krooted_tvs_pop(K); /* already in entry */ - krooted_tvs_push(K, new_entry); - entry_int = kcons(K, new_entry, entry_int); - krooted_tvs_pop(K); - } - } - cont = tv2cont(cont)->parent; - } - - unmark_iancestors(src_cont); - - /* all interceptions collected, append the two lists and return */ - kset_cdr(tail, entry_int); - krooted_vars_pop(K); - krooted_vars_pop(K); - return kcdr(ilist); -} - -/* this passes the operand tree to the continuation */ -void cont_app(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(denv); - TValue cont = xparams[0]; - /* guards and dynamic variables are handled in kcall_cont() */ - kcall_cont(K, cont, ptree); -} - -void do_interception(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - /* - ** xparams[0]: - ** xparams[1]: dst cont - */ - TValue ls = xparams[0]; - TValue dst_cont = xparams[1]; - if (ttisnil(ls)) { - /* all interceptors returned normally */ - /* this is a normal pass/not subject to interception */ - kset_cc(K, dst_cont); - kapply_cc(K, obj); - } else { - /* call the operative with the passed obj and applicative - for outer cont as ptree in the dynamic environment of - the corresponding call to guard-continuation in the - dynamic extent of the associated outer continuation. - If the operative normally returns a value, others - interceptions should be scheduled */ - TValue first = kcar(ls); - TValue op = kcar(first); - TValue outer = kcadr(first); - TValue denv = kcddr(first); - TValue app = kmake_applicative(K, cont_app, 1, outer); - krooted_tvs_push(K, app); - TValue ptree = klist(K, 2, obj, app); - krooted_tvs_pop(K); /* already in ptree */ - krooted_tvs_push(K, ptree); - TValue new_cont = kmake_continuation(K, outer, do_interception, - 2, kcdr(ls), dst_cont); - kset_cc(K, new_cont); - krooted_tvs_pop(K); - /* XXX: what to pass as si? */ - ktail_call(K, op, ptree, denv); - } -} - /* GC: Don't assume anything about obj & dst_cont, they may not be rooted. In the most common case of apply-continuation & continuation->applicative they are rooted, but in general there's no way to protect them, because diff --git a/src/kstate.h b/src/kstate.h @@ -526,19 +526,12 @@ static inline void klispT_tail_call_si(klisp_State *K, TValue top, TValue ptree, ktry_get_si(K__, p__)); \ return; } -/* helper for continuation->applicative & kcall_cont */ -void cont_app(klisp_State *K); +void do_interception(klisp_State *K); void kcall_cont(klisp_State *K, TValue dst_cont, TValue obj); void klispT_init_repl(klisp_State *K); void klispT_run(klisp_State *K); void klisp_close (klisp_State *K); -void do_interception(klisp_State *K); - -/* for root and error continuations */ -void do_root_exit(klisp_State *K); -void do_error_exit(klisp_State *K); - /* simple accessors for dynamic keys */ /* XXX: this is ugly but we can't include kpair.h here so... */