klisp

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

commit 6750277b5ae2368e58286b0374c4cd28b7bfa8a2
parent 3632133315cb26ecedcf0a3c1cf8d8804d37bb94
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Fri, 11 Mar 2011 06:04:12 -0300

Bugfix: in both check_list and check_copy_list cyclic list weren't being handled. It affected $vau which uses check_list to check the body.

Diffstat:
Msrc/kground.c | 50++++++++++++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/src/kground.c b/src/kground.c @@ -152,17 +152,23 @@ inline void unmark_tree(klisp_State *K, TValue obj) } } -/* check that obj is a list */ -inline void check_list(klisp_State *K, char *name, TValue obj) +/* check that obj is a list, returns the number of pairs */ +inline int32_t check_list(klisp_State *K, char *name, TValue obj) { - while(!ttisnil(obj)) { - if (!ttispair(obj)) { - klispE_throw_extra(K, name , ": expected list"); - return; - } - obj = kcdr(obj); + TValue tail = obj; + int pairs = 0; + while(ttispair(tail) && !kis_marked(tail)) { + kmark(tail); + tail = kcdr(tail); + ++pairs; + } + unmark_list(K, obj); + + if (!ttispair(tail) && !ttisnil(tail)) { + klispE_throw_extra(K, name , ": expected list"); + return 0; } - return; + return pairs; } /* check that obj is a list and make a copy if it is not immutable */ @@ -172,21 +178,33 @@ inline TValue check_copy_list(klisp_State *K, char *name, TValue obj) return obj; if (ttispair(obj) && kis_immutable(obj)) { - check_list(K, name, obj); + (void)check_list(K, name, obj); return obj; } else { TValue dummy = kcons(K, KINERT, KNIL); TValue last = dummy; - while(!ttisnil(obj)) { - if (!ttispair(obj)) { - klispE_throw_extra(K, name , ": expected list"); - return KINERT; - } + TValue tail = obj; + + while(ttispair(tail) && !kis_marked(tail)) { TValue new_pair = kcons(K, kcar(obj), KNIL); + /* record the corresponding pair to simplify cycle handling */ + kset_mark(tail, new_pair); kset_cdr(last, new_pair); last = new_pair; obj = kcdr(obj); } + + if (ttispair(tail)) { + /* complete the cycle */ + kset_cdr(last, kget_mark(tail)); + } + + unmark_list(K, obj); + + if (!ttispair(tail) && !ttisnil(tail)) { + klispE_throw_extra(K, name , ": expected list"); + return KINERT; + } return kcdr(dummy); } } @@ -983,7 +1001,7 @@ void Svau(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* The ptree & body are copied to avoid mutation */ vptree = check_copy_ptree(K, "$vau", vptree, vpenv); /* the body should be a list */ - check_list(K, "$vau", vbody); + (void)check_list(K, "$vau", vbody); vbody = copy_es_immutable_h(K, "$vau", vbody); TValue new_op = make_operative(K, do_vau, 4, vptree, vpenv, vbody, denv);