klisp

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

commit 3b841c58a968ec6c43a3d405d2b9bfaaf20dae68
parent eb5be949efeda606d06702034f6bccbebe55772b
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Thu, 31 Mar 2011 17:01:59 -0300

Added $and? & $or? to the ground environment.

Diffstat:
Msrc/Makefile | 2+-
Msrc/kgbooleans.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/kgbooleans.h | 8++++++--
Msrc/kground.c | 4++--
Msrc/kobject.h | 2++
5 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -88,7 +88,7 @@ kghelpers.o: kghelpers.c kghelpers.h kstate.h kstate.h klisp.h kpair.h \ kapplicative.h koperative.h kerror.h kobject.h ksymbol.h \ kcontinuation.h kgbooleans.o: kgbooleans.c kgbooleans.c kghelpers.h kstate.h klisp.h \ - kobject.h kerror.h kpair.h kcontinuation.h + kobject.h kerror.h kpair.h kcontinuation.h ksymbol.h kgeqp.o: kgeqp.c kgeqp.c kghelpers.h kstate.h klisp.h \ kobject.h kerror.h kpair.h kcontinuation.h kgequalp.o: kgequalp.c kgequalp.c kghelpers.h kstate.h klisp.h \ diff --git a/src/kgbooleans.c b/src/kgbooleans.c @@ -14,6 +14,7 @@ #include "klisp.h" #include "kstate.h" #include "kpair.h" +#include "ksymbol.h" #include "kcontinuation.h" #include "kerror.h" #include "kghelpers.h" @@ -78,8 +79,85 @@ void orp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } +/* Helpers for $and? & $or? */ + +/* +** operands is a list, the other cases are handled before calling +** term-bool is the termination boolean, i.e. the boolean that terminates +** evaluation early and becomes the result of $and?/$or? +** it is #t for $or? and #f for $and? +** both $and? & $or? have to allow boolean checking while performing a tail +** call that is acomplished by checking if the current continuation will +** perform a boolean check, and in that case, no continuation is created +*/ +void do_Sandp_Sorp(klisp_State *K, TValue *xparams, TValue obj) +{ + /* + ** xparams[0]: symbol name + ** xparams[1]: termination boolean + ** xparams[2]: remaining operands + ** xparams[3]: denv + */ + TValue sname = xparams[0]; + TValue term_bool = xparams[1]; + TValue ls = xparams[2]; + TValue denv = xparams[3]; + + if (!ttisboolean(obj)) { + klispE_throw_extra(K, ksymbol_buf(sname), ": expected boolean"); + return; + } else if (ttisnil(ls) || tv_equal(obj, term_bool)) { + /* in both cases the value to be returned is obj: + if there are no more operands it is obvious otherwise, if + the termination bool is found: + $and? returns #f when it finds #f and $or? returns #t when it + finds #t */ + kapply_cc(K, obj); + } else { + TValue first = kcar(ls); + ls = kcdr(ls); + /* This is the important part of tail context + bool check */ + if (!ttisnil(ls) || !kis_bool_check_cont(kget_cc(K))) { + TValue new_cont = + kmake_continuation(K, kget_cc(K), KNIL, KNIL, do_Sandp_Sorp, + 4, sname, term_bool, ls, denv); + /* + ** Mark as a bool checking cont this is needed in the last operand + ** to allow both tail recursive behaviour and boolean checking. + ** While it is not necessary if this is not the last operand it + ** avoids a continuation in the last evaluation of the inner form + ** in the common use of + ** ($and?/$or? ($or?/$and? ...) ...) + */ + kset_bool_check_cont(new_cont); + kset_cc(K, new_cont); + } + ktail_eval(K, first, denv); + } +} + +void Sandp_Sorp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +{ + /* + ** xparams[0]: symbol name + ** xparams[1]: termination boolean + */ + TValue sname = xparams[0]; + TValue term_bool = xparams[1]; + + TValue ls = check_copy_list(K, ksymbol_buf(sname), ptree); + /* This will work even if ls is empty */ + TValue new_cont = + kmake_continuation(K, kget_cc(K), KNIL, KNIL, do_Sandp_Sorp, + 4, sname, term_bool, ls, denv); + /* there's no need to mark it as bool checking, no evaluation + is done in the dynamic extent of this cont */ + kset_cc(K, new_cont); + kapply_cc(K, knegp(term_bool)); /* pass dummy value to start */ +} + /* 6.1.4 $and? */ -/* TODO */ +/* uses Sandp_Sorp */ /* 6.1.5 $or? */ -/* TODO */ +/* uses Sandp_Sorp */ diff --git a/src/kgbooleans.h b/src/kgbooleans.h @@ -30,11 +30,15 @@ void andp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); /* 6.1.3 or? */ void orp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +/* Helpers for $and? & $or? */ +void do_Sandp_Sorp(klisp_State *K, TValue *xparams, TValue obj); +void Sandp_Sorp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); + /* 6.1.4 $and? */ -/* TODO */ +/* uses Sandp_Sorp */ /* 6.1.5 $or? */ -/* TODO */ +/* uses Sandp_Sorp */ /* Helper */ bool kbooleanp(TValue obj); diff --git a/src/kground.c b/src/kground.c @@ -359,10 +359,10 @@ void kinit_ground_env(klisp_State *K) add_applicative(K, ground_env, "or?", orp, 0); /* 6.1.4 $and? */ - /* TODO */ + add_operative(K, ground_env, "$and?", Sandp_Sorp, 2, symbol, KFALSE); /* 6.1.5 $or? */ - /* TODO */ + add_operative(K, ground_env, "$or?", Sandp_Sorp, 2, symbol, KTRUE); /* ** 6.2 Combiners diff --git a/src/kobject.h b/src/kobject.h @@ -213,6 +213,8 @@ typedef struct __attribute__ ((__packed__)) GCheader { /* macros to easily check boolean values */ #define kis_true(o_) (tv_equal((o_), KTRUE)) #define kis_false(o_) (tv_equal((o_), KFALSE)) +/* unsafe, doesn't check type */ +#define knegp(o_) (kis_true(o_)? KFALSE : KTRUE) /* ** Union of all Kernel non heap-allocated values (except doubles)