klisp

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

kghelpers.c (62538B)


      1 /*
      2 ** kghelpers.c
      3 ** Helper macros and functions for the ground environment
      4 ** See Copyright Notice in klisp.h
      5 */
      6 
      7 #include <stdlib.h>
      8 #include <stdio.h>
      9 #include <stdbool.h>
     10 #include <stdint.h>
     11 
     12 #include "kghelpers.h"
     13 #include "kstate.h"
     14 #include "kobject.h"
     15 #include "klisp.h"
     16 #include "kerror.h"
     17 #include "ksymbol.h"
     18 #include "kenvironment.h"
     19 #include "kinteger.h"
     20 #include "krational.h"
     21 #include "kapplicative.h"
     22 #include "kbytevector.h"
     23 #include "kvector.h"
     24 #include "kstring.h"
     25 #include "kpair.h"
     26 #include "kcontinuation.h"
     27 #include "kencapsulation.h"
     28 #include "kpromise.h"
     29 
     30 /* XXX lock? */
     31 /* Initialization of continuation names */
     32 void kinit_kghelpers_cont_names(klisp_State *K)
     33 {
     34     Table *t = tv2table(G(K)->cont_name_table);
     35     add_cont_name(K, t, do_seq, "eval-sequence");
     36     add_cont_name(K, t, do_pass_value, "pass-value");
     37     add_cont_name(K, t, do_return_value, "return-value");
     38     add_cont_name(K, t, do_bind, "dynamic-bind");
     39     add_cont_name(K, t, do_bind, "dynamic-access");
     40     add_cont_name(K, t, do_bind, "dynamic-unbind");
     41     add_cont_name(K, t, do_bind, "dynamic-set!-pass");
     42 }
     43 
     44 /* Type predicates */
     45 /* TODO these should be moved to either kobject.h or the corresponding
     46    files (e.g. kbooleanp to kboolean.h */
     47 bool kbooleanp(TValue obj) { return ttisboolean(obj); }
     48 bool kcombinerp(TValue obj) { return ttiscombiner(obj); }
     49 bool knumberp(TValue obj) { return ttisnumber(obj); }
     50 /* TEMP used (as a type predicate) in all predicates that need a primary value
     51    (XXX it's not actually a type error, but it's close enough and otherwise 
     52    should define new predp & bpredp for numeric predicates...) */
     53 bool knumber_wpvp(TValue obj) 
     54 { 
     55     return ttisnumber(obj) && !ttisrwnpv(obj) && !ttisundef(obj); 
     56 }
     57 /* This is used in gcd & lcm */
     58 bool kimp_intp(TValue obj) { return ttisinteger(obj) || ttisinf(obj); }
     59 /* obj is known to be a number */
     60 bool kfinitep(TValue obj) { return !ttisinf(obj); }
     61 /* fixint, bigints & inexact integers */
     62 bool kintegerp(TValue obj) { return ttisinteger(obj); }
     63 /* only exact integers (like for indices), bigints & fixints */
     64 bool keintegerp(TValue obj) { return ttiseinteger(obj); }
     65 /* exact integers between 0 and 255 inclusive */
     66 bool ku8p(TValue obj) { return ttisu8(obj); }
     67 bool krationalp(TValue obj) { return ttisrational(obj); }
     68 bool krealp(TValue obj) { return ttisreal(obj); }
     69 /* TEMP used (as a type predicate) in all predicates that need a real with 
     70    primary value (XXX it's not actually a type error, but it's close enough 
     71    and otherwise should define new predp & bpredp for numeric predicates...) */
     72 bool kreal_wpvp(TValue obj) { return ttisreal(obj) && !ttisrwnpv(obj); }
     73 
     74 bool kexactp(TValue obj) { return ttisexact(obj); }
     75 bool kinexactp(TValue obj) { return ttisinexact(obj); }
     76 bool kundefinedp(TValue obj) { return ttisundef(obj); }
     77 bool krobustp(TValue obj) { return ttisrobust(obj); }
     78 
     79 void enc_typep(klisp_State *K)
     80 {
     81     TValue *xparams = K->next_xparams;
     82     TValue ptree = K->next_value;
     83     TValue denv = K->next_env;
     84     klisp_assert(ttisenvironment(K->next_env));
     85     UNUSED(denv);
     86     /*
     87     ** xparams[0]: encapsulation key
     88     */
     89     TValue key = xparams[0];
     90 
     91     /* check the ptree is a list while checking the predicate.
     92        Keep going even if the result is false to catch errors in 
     93        ptree structure */
     94     bool res = true;
     95 
     96     TValue tail = ptree;
     97     while(ttispair(tail) && kis_unmarked(tail)) {
     98         kmark(tail);
     99         res &= kis_encapsulation_type(kcar(tail), key);
    100         tail = kcdr(tail);
    101     }
    102     unmark_list(K, ptree);
    103 
    104     if (ttispair(tail) || ttisnil(tail)) {
    105         kapply_cc(K, b2tv(res));
    106     } else {
    107         /* try to get name from encapsulation */
    108         klispE_throw_simple(K, "expected list");
    109         return;
    110     }
    111 }
    112 /* /Type predicates */
    113 
    114 /* some number functions */
    115 bool kpositivep(TValue n)
    116 { 
    117     switch (ttype(n)) {
    118     case K_TFIXINT:
    119     case K_TEINF:
    120     case K_TIINF:
    121         return ivalue(n) > 0;
    122     case K_TBIGINT:
    123         return kbigint_positivep(n);
    124     case K_TBIGRAT:
    125         return kbigrat_positivep(n);
    126     case K_TDOUBLE:
    127         return dvalue(n) > 0.0;
    128         /* real with no prim value, complex and undefined should be captured by 
    129            type predicate */
    130     default:
    131         klisp_assert(0);
    132         return false;
    133     }
    134 }
    135 
    136 bool knegativep(TValue n) 
    137 { 
    138     switch (ttype(n)) {
    139     case K_TFIXINT:
    140     case K_TEINF:
    141     case K_TIINF:
    142         return ivalue(n) < 0;
    143     case K_TBIGINT:
    144         return kbigint_negativep(n);
    145     case K_TBIGRAT:
    146         return kbigrat_negativep(n);
    147     case K_TDOUBLE:
    148         return dvalue(n) < 0.0;
    149         /* real with no prim value, complex and undefined should be captured by 
    150            type predicate */
    151     default:
    152         klisp_assert(0);
    153         return false;
    154     }
    155 }
    156 /* /some number functions */
    157 
    158 void typep(klisp_State *K)
    159 {
    160     TValue *xparams = K->next_xparams;
    161     TValue ptree = K->next_value;
    162     TValue denv = K->next_env;
    163     klisp_assert(ttisenvironment(K->next_env));
    164     /*
    165     ** xparams[0]: name symbol
    166     ** xparams[1]: type tag (as by i2tv)
    167     */
    168     UNUSED(denv);
    169     int32_t tag = ivalue(xparams[1]);
    170 
    171     /* check the ptree is a list while checking the predicate.
    172        Keep going even if the result is false to catch errors in 
    173        ptree structure */
    174     bool res = true;
    175 
    176     TValue tail = ptree;
    177     while(ttispair(tail) && kis_unmarked(tail)) {
    178         kmark(tail);
    179         res &= ttype(kcar(tail)) == tag;
    180         tail = kcdr(tail);
    181     }
    182     unmark_list(K, ptree);
    183 
    184     if (ttispair(tail) || ttisnil(tail)) {
    185         kapply_cc(K, b2tv(res));
    186     } else {
    187         klispE_throw_simple(K, "expected list");
    188         return;
    189     }
    190 }
    191 
    192 void ftypep(klisp_State *K)
    193 {
    194     TValue *xparams = K->next_xparams;
    195     TValue ptree = K->next_value;
    196     TValue denv = K->next_env;
    197     klisp_assert(ttisenvironment(K->next_env));
    198     (void) denv;
    199     /*
    200     ** xparams[0]: name symbol
    201     ** xparams[1]: fn pointer (as a void * in a user TValue)
    202     */
    203     bool (*fn)(TValue obj) = pvalue(xparams[1]);
    204 
    205     /* check the ptree is a list while checking the predicate.
    206        Keep going even if the result is false to catch errors in 
    207        ptree structure */
    208     bool res = true;
    209 
    210     TValue tail = ptree;
    211     while(ttispair(tail) && kis_unmarked(tail)) {
    212         kmark(tail);
    213         res &= (*fn)(kcar(tail));
    214         tail = kcdr(tail);
    215     }
    216     unmark_list(K, ptree);
    217 
    218     if (ttispair(tail) || ttisnil(tail)) {
    219         kapply_cc(K, b2tv(res));
    220     } else {
    221         klispE_throw_simple(K, "expected list");
    222         return;
    223     }
    224 }
    225 
    226 /*
    227 ** REFACTOR: Change this to make it a single pass
    228 */
    229 void ftyped_predp(klisp_State *K)
    230 {
    231     TValue *xparams = K->next_xparams;
    232     TValue ptree = K->next_value;
    233     TValue denv = K->next_env;
    234     klisp_assert(ttisenvironment(K->next_env));
    235     (void) denv;
    236     /*
    237     ** xparams[0]: name symbol
    238     ** xparams[1]: type fn pointer (as a void * in a user TValue)
    239     ** xparams[2]: fn pointer (as a void * in a user TValue)
    240     */
    241     bool (*typep)(TValue obj) = pvalue(xparams[1]);
    242     bool (*predp)(TValue obj) = pvalue(xparams[2]);
    243 
    244     /* check the ptree is a list first to allow the structure
    245        errors to take precedence over the type errors. */
    246     int32_t pairs, cpairs;
    247     check_list(K, true, ptree, &pairs, &cpairs);
    248 
    249     TValue tail = ptree;
    250     bool res = true;
    251 
    252     /* check the type while checking the predicate.
    253        Keep going even if the result is false to catch errors in 
    254        type */
    255     while(pairs--) {
    256         TValue first = kcar(tail);
    257 
    258         if (!(*typep)(first)) {
    259             /* TODO show expected type */
    260             klispE_throw_simple(K, "bad argument type");
    261             return;
    262         }
    263         res &= (*predp)(first);
    264         tail = kcdr(tail);
    265     }
    266     kapply_cc(K, b2tv(res));
    267 }
    268 
    269 /*
    270 ** REFACTOR: Change this to make it a single pass
    271 */
    272 void ftyped_bpredp(klisp_State *K)
    273 {
    274     TValue *xparams = K->next_xparams;
    275     TValue ptree = K->next_value;
    276     TValue denv = K->next_env;
    277     klisp_assert(ttisenvironment(K->next_env));
    278     (void) denv;
    279     /*
    280     ** xparams[0]: name symbol
    281     ** xparams[1]: type fn pointer (as a void * in a user TValue)
    282     ** xparams[2]: fn pointer (as a void * in a user TValue)
    283     */
    284     bool (*typep)(TValue obj) = pvalue(xparams[1]);
    285     bool (*predp)(TValue obj1, TValue obj2) = pvalue(xparams[2]);
    286 
    287     /* check the ptree is a list first to allow the structure
    288        errors to take precedence over the type errors. */
    289     int32_t pairs, cpairs;
    290     check_list(K, true, ptree, &pairs, &cpairs);
    291 
    292     /* cyclical list require an extra comparison of the last
    293        & first element of the cycle */
    294     int32_t comps = cpairs? pairs : pairs - 1;
    295 
    296     TValue tail = ptree;
    297     bool res = true;
    298 
    299     /* check the type while checking the predicate.
    300        Keep going even if the result is false to catch errors in 
    301        type */
    302 
    303     if (comps == 0) {
    304         /* this case has to be here because otherwise there is no check
    305            for the type of the lone operand */
    306         TValue first = kcar(tail);
    307         if (!(*typep)(first)) {
    308             /* TODO show expected type */
    309             klispE_throw_simple(K, "bad argument type");
    310             return;
    311         }
    312     }
    313 
    314     while(comps-- > 0) { /* comps could be -1 if ptree is () */
    315         TValue first = kcar(tail);
    316         tail = kcdr(tail); /* tail only advances one place per iteration */
    317         TValue second = kcar(tail);
    318 
    319         if (!(*typep)(first) || !(*typep)(second)) {
    320             /* TODO show expected type */
    321             klispE_throw_simple(K, "bad argument type");
    322             return;
    323         }
    324         res &= (*predp)(first, second);
    325     }
    326     kapply_cc(K, b2tv(res));
    327 }
    328 
    329 /* This is the same, but the comparison predicate takes a klisp_State */
    330 /* TODO unify them */
    331 void ftyped_kbpredp(klisp_State *K)
    332 {
    333     TValue *xparams = K->next_xparams;
    334     TValue ptree = K->next_value;
    335     TValue denv = K->next_env;
    336     klisp_assert(ttisenvironment(K->next_env));
    337     (void) denv;
    338     /*
    339     ** xparams[0]: name symbol
    340     ** xparams[1]: type fn pointer (as a void * in a user TValue)
    341     ** xparams[2]: fn pointer (as a void * in a user TValue)
    342     */
    343     bool (*typep)(TValue obj) = pvalue(xparams[1]);
    344     bool (*predp)(klisp_State *K, TValue obj1, TValue obj2) = 
    345         pvalue(xparams[2]);
    346 
    347     /* check the ptree is a list first to allow the structure
    348        errors to take precedence over the type errors. */
    349     int32_t pairs, cpairs;
    350     check_list(K, true, ptree, &pairs, &cpairs);
    351 
    352     /* cyclical list require an extra comparison of the last
    353        & first element of the cycle */
    354     int32_t comps = cpairs? pairs : pairs - 1;
    355 
    356     TValue tail = ptree;
    357     bool res = true;
    358 
    359     /* check the type while checking the predicate.
    360        Keep going even if the result is false to catch errors in 
    361        type */
    362 
    363     if (comps == 0) {
    364         /* this case has to be here because otherwise there is no check
    365            for the type of the lone operand */
    366         TValue first = kcar(tail);
    367         if (!(*typep)(first)) {
    368             /* TODO show expected type */
    369             klispE_throw_simple(K, "bad argument type");
    370             return;
    371         }
    372     }
    373 
    374     while(comps-- > 0) { /* comps could be -1 if ptree is () */
    375         TValue first = kcar(tail);
    376         tail = kcdr(tail); /* tail only advances one place per iteration */
    377         TValue second = kcar(tail);
    378 
    379         if (!(*typep)(first) || !(*typep)(second)) {
    380             /* TODO show expected type */
    381             klispE_throw_simple(K, "bad argument type");
    382             return;
    383         }
    384         res &= (*predp)(K, first, second);
    385     }
    386     kapply_cc(K, b2tv(res));
    387 }
    388 
    389 /* typed finite list. Structure error should be throw before type errors */
    390 void check_typed_list(klisp_State *K, bool (*typep)(TValue), bool allow_infp, 
    391                       TValue obj, int32_t *pairs, int32_t *cpairs)
    392 {
    393     TValue tail = obj;
    394     int32_t p = 0;
    395     bool type_errorp = false;
    396 
    397     while(ttispair(tail) && !kis_marked(tail)) {
    398         /* even if there is a type error continue checking the structure */
    399         type_errorp |= !(*typep)(kcar(tail));
    400         kset_mark(tail, i2tv(p));
    401         tail = kcdr(tail);
    402         ++p;
    403     }
    404 
    405     if (pairs != NULL) *pairs = p;
    406     if (cpairs != NULL)
    407         *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0;
    408 
    409     unmark_list(K, obj);
    410     
    411     if (!ttispair(tail) && !ttisnil(tail)) {
    412         klispE_throw_simple(K, allow_infp? "expected list" :
    413                             "expected finite list"); 
    414         return;
    415     } else if(ttispair(tail) && !allow_infp) {
    416         klispE_throw_simple(K, "expected finite list"); 
    417         return;
    418     } else if (type_errorp) {
    419         /* TODO put type name too, should be extracted from a
    420            table of type names */
    421         klispE_throw_simple(K, "bad operand type"); 
    422         return;
    423     }
    424 }
    425 
    426 void check_list(klisp_State *K, bool allow_infp, TValue obj, 
    427                 int32_t *pairs, int32_t *cpairs)
    428 {
    429     TValue tail = obj;
    430     int32_t p = 0;
    431 
    432     while(ttispair(tail) && !kis_marked(tail)) {
    433         kset_mark(tail, i2tv(p));
    434         tail = kcdr(tail);
    435         ++p;
    436     }
    437 
    438     if (pairs != NULL) *pairs = p;
    439     if (cpairs != NULL)
    440         *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0;
    441 
    442     unmark_list(K, obj);
    443 
    444     if (!ttispair(tail) && !ttisnil(tail)) {
    445         klispE_throw_simple(K, allow_infp? "expected list" : 
    446                             "expected finite list"); 
    447         return;
    448     } else if(ttispair(tail) && !allow_infp) {
    449         klispE_throw_simple(K, "expected finite list"); 
    450         return;
    451     }
    452 }
    453 
    454 
    455 TValue check_copy_list(klisp_State *K, TValue obj, bool force_copy, 
    456                        int32_t *pairs, int32_t *cpairs)
    457 {
    458     int32_t p = 0;
    459     if (ttisnil(obj)) {
    460         if (pairs != NULL) *pairs = 0;
    461         if (cpairs != NULL) *cpairs = 0;
    462         return obj;
    463     }
    464 
    465     if (ttispair(obj) && kis_immutable(obj) && !force_copy) {
    466         /* this will properly set pairs and cpairs */
    467         check_list(K, true, obj, pairs, cpairs);
    468         return obj;
    469     } else {
    470         TValue copy = kcons(K, KNIL, KNIL);
    471         krooted_vars_push(K, &copy);
    472         TValue last_pair = copy;
    473         TValue tail = obj;
    474     
    475         while(ttispair(tail) && !kis_marked(tail)) {
    476             TValue new_pair = kcons(K, kcar(tail), KNIL);
    477             /* record the corresponding pair to simplify cycle handling */
    478             kset_mark(tail, new_pair);
    479             /* record the pair number in the new pair, to set cpairs */
    480             kset_mark(new_pair, i2tv(p));
    481             /* copy the source code info */
    482             TValue si = ktry_get_si(K, tail);
    483             if (!ttisnil(si))
    484                 kset_source_info(K, new_pair, si);
    485             kset_cdr(last_pair, new_pair);
    486             last_pair = new_pair;
    487             tail = kcdr(tail);
    488             ++p;
    489         }
    490 
    491         if (pairs != NULL) *pairs = p;
    492         if (cpairs != NULL)
    493             *cpairs = ttispair(tail)? 
    494                 (p - ivalue(kget_mark(kget_mark(tail)))) : 
    495                 0;
    496 
    497         if (ttispair(tail)) {
    498             /* complete the cycle */
    499             kset_cdr(last_pair, kget_mark(tail));
    500         }
    501 
    502         unmark_list(K, obj);
    503         unmark_list(K, kcdr(copy));
    504         
    505         if (!ttispair(tail) && !ttisnil(tail)) {
    506             klispE_throw_simple(K, "expected list"); 
    507             return KINERT;
    508         } 
    509         krooted_vars_pop(K);
    510         return kcdr(copy);
    511     }
    512 }
    513 
    514 /* GC: assumes ls is rooted */
    515 /* LOCK: This assumes ls isn't mutated, so no lock is acquired
    516  (except the needed for car, cdr & set-cdr) */
    517 TValue reverse_copy_and_encycle(klisp_State *K, TValue ls, int32_t pairs, 
    518 				int32_t cpairs)
    519 {
    520     if (pairs == 0)
    521         return KNIL;
    522     
    523     int32_t apairs = pairs - cpairs;
    524     TValue last = kcons(K, kcar(ls), KNIL);
    525     ls = kcdr(ls);
    526     krooted_vars_push(K, &last);
    527 
    528     if (cpairs > 0) {
    529         --cpairs;
    530 	TValue last_cycle = last;
    531 	while (cpairs > 0) {
    532 	    last = kcons(K, kcar(ls), last);
    533 	    ls = kcdr(ls);
    534 	    --cpairs;
    535 	}
    536 	kset_cdr(last_cycle, last);
    537     } else {
    538         --apairs;
    539     }
    540     
    541     while (apairs > 0) {
    542 	last = kcons(K, kcar(ls), last);
    543 	ls = kcdr(ls);
    544 	--apairs;
    545     }
    546 
    547     krooted_vars_pop(K);
    548     return last;
    549 }
    550 
    551 TValue check_copy_env_list(klisp_State *K, TValue obj)
    552 {
    553     TValue copy = kcons(K, KNIL, KNIL);
    554     krooted_vars_push(K, &copy);
    555     TValue last_pair = copy;
    556     TValue tail = obj;
    557     
    558     while(ttispair(tail) && !kis_marked(tail)) {
    559         TValue first = kcar(tail);
    560         if (!ttisenvironment(first)) {
    561             klispE_throw_simple(K, "not an environment in parent list");
    562             return KINERT;
    563         }
    564         TValue new_pair = kcons(K, first, KNIL);
    565         kmark(tail);
    566         kset_cdr(last_pair, new_pair);
    567         last_pair = new_pair;
    568         tail = kcdr(tail);
    569     }
    570 
    571     /* even if there was a cycle, the copy ends with nil */
    572     unmark_list(K, obj);
    573 
    574     if (!ttispair(tail) && !ttisnil(tail)) {
    575         klispE_throw_simple(K, "expected list"); 
    576         return KINERT;
    577     } 
    578     krooted_vars_pop(K);
    579     return kcdr(copy);
    580 }
    581 
    582 /* Helpers for string, list->string, and string-map,
    583    bytevector, list->bytevector, bytevector-map, 
    584    vector, list->vector, and vector-map */
    585 /* GC: Assume ls is rooted */
    586 /* ls should a list of length 'length' of the correct type 
    587    (chars for string, u8 for bytevector, any for vector) */
    588 /* these type checks each element */
    589 
    590 TValue list_to_string_h(klisp_State *K, TValue ls, int32_t length)
    591 {
    592     TValue new_str;
    593     /* the if isn't strictly necessary but it's clearer this way */
    594     if (length == 0) {
    595         return G(K)->empty_string; 
    596     } else {
    597         new_str = kstring_new_s(K, length);
    598         char *buf = kstring_buf(new_str);
    599         while(length-- > 0) {
    600             TValue head = kcar(ls);
    601             if (!ttischar(head)) {
    602                 klispE_throw_simple_with_irritants(K, "Bad type (expected "
    603                                                    "char)", 1, head);
    604                 return KINERT;
    605             }
    606             *buf++ = chvalue(head);
    607             ls = kcdr(ls);
    608         }
    609         return new_str;
    610     }
    611 }
    612 
    613 TValue list_to_vector_h(klisp_State *K, TValue ls, int32_t length)
    614 {
    615 
    616     if (length == 0) {
    617         return G(K)->empty_vector;
    618     } else {
    619         TValue new_vec = kvector_new_sf(K, length, KINERT);
    620         TValue *buf = kvector_buf(new_vec);
    621         while(length-- > 0) {
    622             *buf++ = kcar(ls);
    623             ls = kcdr(ls);
    624         }
    625         return new_vec;
    626     }
    627 }
    628 
    629 TValue list_to_bytevector_h(klisp_State *K, TValue ls, int32_t length)
    630 {
    631     TValue new_bb;
    632     /* the if isn't strictly necessary but it's clearer this way */
    633     if (length == 0) {
    634         return G(K)->empty_bytevector; 
    635     } else {
    636         new_bb = kbytevector_new_s(K, length);
    637         uint8_t *buf = kbytevector_buf(new_bb);
    638         while(length-- > 0) {
    639             TValue head = kcar(ls);
    640             if (!ttisu8(head)) {
    641                 klispE_throw_simple_with_irritants(K, "Bad type (expected "
    642                                                    "u8)", 1, head);
    643                 return KINERT;
    644             }
    645             *buf++ = ivalue(head);
    646             ls = kcdr(ls);
    647         }
    648         return new_bb;
    649     }
    650 }
    651 
    652 /* Helpers for string->list, string-map, string-foreach,
    653    bytevector->list, bytevector-map, bytevector-foreach,
    654    vector->list, vector-map, and vector-foreach */
    655 /* GC: Assume array is rooted */
    656 TValue string_to_list_h(klisp_State *K, TValue obj, int32_t *length)
    657 {
    658     if (!ttisstring(obj)) {
    659         klispE_throw_simple_with_irritants(K, "Bad type (expected string)",
    660                                            1, obj);
    661         return KINERT;
    662     }
    663 
    664     int32_t pairs = kstring_size(obj);
    665     if (length != NULL)	*length = pairs;
    666 
    667     char *buf = kstring_buf(obj) + pairs - 1;
    668     TValue tail = KNIL;
    669     krooted_vars_push(K, &tail);
    670     while(pairs-- > 0) {
    671         tail = kcons(K, ch2tv(*buf), tail);
    672         --buf;
    673     }
    674     krooted_vars_pop(K);
    675     return tail;
    676 }
    677 
    678 TValue vector_to_list_h(klisp_State *K, TValue obj, int32_t *length)
    679 {
    680     if (!ttisvector(obj)) {
    681         klispE_throw_simple_with_irritants(K, "Bad type (expected vector)",
    682                                            1, obj);
    683         return KINERT;
    684     }
    685 
    686     int32_t pairs = kvector_size(obj);
    687     if (length != NULL)	*length = pairs;
    688 
    689     TValue *buf = kvector_buf(obj) + pairs - 1;
    690     TValue tail = KNIL;
    691     krooted_vars_push(K, &tail);
    692     while(pairs-- > 0) {
    693         tail = kcons(K, *buf, tail);
    694         --buf;
    695     }
    696     krooted_vars_pop(K);
    697     return tail;
    698 }
    699 
    700 TValue bytevector_to_list_h(klisp_State *K, TValue obj, int32_t *length)
    701 {
    702     if (!ttisbytevector(obj)) {
    703         klispE_throw_simple_with_irritants(K, "Bad type (expected bytevector)",
    704                                            1, obj);
    705         return KINERT;
    706     }
    707 
    708     int32_t pairs = kbytevector_size(obj);
    709     if (length != NULL)	*length = pairs;
    710 
    711     uint8_t *buf = kbytevector_buf(obj) + pairs - 1;
    712     TValue tail = KNIL;
    713     krooted_vars_push(K, &tail);
    714     while(pairs-- > 0) {
    715         tail = kcons(K, i2tv(*buf), tail);
    716         --buf;
    717     }
    718     krooted_vars_pop(K);
    719     return tail;
    720 }
    721 
    722 /* Some helpers for working with fixints (signed 32 bits) */
    723 int64_t kgcd32_64(int32_t a_, int32_t b_)
    724 {
    725     /* this is a vanilla binary gcd algorithm */ 
    726 
    727     /* work with positive numbers, use unsigned numbers to 
    728        allow INT32_MIN to have an absolute value */
    729     uint32_t a = (uint32_t) kabs64(a_);
    730     uint32_t b = (uint32_t) kabs64(b_);
    731 
    732     int powerof2;
    733 
    734     /* the easy cases first, unlike the general kernel gcd the
    735        gcd2 of a number and zero is zero */
    736     if (a == 0)
    737         return (int64_t) b;
    738     else if (b == 0)
    739         return (int64_t) a;
    740  
    741     for (powerof2 = 0; ((a & 1) == 0) && 
    742              ((b & 1) == 0); ++powerof2, a >>= 1, b >>= 1)
    743         ;
    744  
    745     while(a != 0 && b!= 0) {
    746         /* either a or b are odd, make them both odd */
    747         for (; (a & 1) == 0; a >>= 1)
    748             ;
    749         for (; (b & 1) == 0; b >>= 1)
    750             ;
    751 
    752         /* now the difference is sure to be even */
    753         if (a < b) {
    754             b = (b - a) >> 1;
    755         } else {
    756             a = (a - b) >> 1;
    757         }
    758     }
    759  
    760     return ((int64_t) (a == 0? b : a)) << powerof2;
    761 }
    762 
    763 int64_t klcm32_64(int32_t a_, int32_t b_)
    764 {
    765     int64_t gcd = kgcd32_64(a_, b_);
    766     int64_t a = kabs64(a_);
    767     int64_t b = kabs64(b_);
    768     /* divide first to avoid possible overflow */
    769     return (a / gcd) * b;
    770 }
    771 
    772 /* This is needed in kstate & promises */
    773 void memoize(klisp_State *K)
    774 {
    775     TValue *xparams = K->next_xparams;
    776     TValue ptree = K->next_value;
    777     TValue denv = K->next_env;
    778     klisp_assert(ttisenvironment(K->next_env));
    779     UNUSED(xparams);
    780     UNUSED(denv);
    781 
    782     bind_1p(K, ptree, exp);
    783     TValue new_prom = kmake_promise(K, exp, KNIL);
    784     kapply_cc(K, new_prom);
    785 }
    786 
    787 /* list applicative (used in kstate and kgpairs_lists) */
    788 void list(klisp_State *K)
    789 {
    790     TValue *xparams = K->next_xparams;
    791     TValue ptree = K->next_value;
    792     TValue denv = K->next_env;
    793     klisp_assert(ttisenvironment(K->next_env));
    794 /* the underlying combiner of list return the complete ptree, the only list
    795    checking is implicit in the applicative evaluation */
    796     UNUSED(xparams);
    797     UNUSED(denv);
    798     kapply_cc(K, ptree);
    799 }
    800 
    801 /* Helper for get-list-metrics, and list-tail, list-ref and list-set! 
    802    when receiving bigint indexes */
    803 void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, 
    804                           int32_t *a, int32_t *c)
    805 {
    806     TValue tail = obj;
    807     int32_t pairs = 0;
    808 
    809     while(ttispair(tail) && !kis_marked(tail)) {
    810         /* record the pair number to simplify cycle pair counting */
    811         kset_mark(tail, i2tv(pairs));
    812         ++pairs;
    813         tail = kcdr(tail);
    814     }
    815     int32_t apairs, cpairs, nils;
    816     if (ttisnil(tail)) {
    817         /* simple (possibly empty) list */
    818         apairs = pairs;
    819         nils = 1;
    820         cpairs = 0;
    821     } else if (ttispair(tail)) {
    822         /* cyclic (maybe circular) list */
    823         apairs = ivalue(kget_mark(tail));
    824         cpairs = pairs - apairs;
    825         nils = 0;
    826     } else {
    827         apairs = pairs;
    828         cpairs = 0;
    829         nils = 0;
    830     }
    831 
    832     unmark_list(K, obj);
    833 
    834     if (p != NULL) *p = pairs;
    835     if (n != NULL) *n = nils;
    836     if (a != NULL) *a = apairs;
    837     if (c != NULL) *c = cpairs;
    838 }
    839 
    840 /* Helper for list-tail, list-ref and list-set! */
    841 /* Calculate the smallest i such that 
    842    (eq? (list-tail obj i) (list-tail obj tk))
    843    tk is a bigint and all lists have fixint range number of pairs,
    844    so the list should cyclic and we should calculate an index that
    845    doesn't go through the complete cycle not even once */
    846 int32_t ksmallest_index(klisp_State *K, TValue obj, TValue tk)
    847 {
    848     int32_t apairs, cpairs;
    849     get_list_metrics_aux(K, obj, NULL, NULL, &apairs, &cpairs);
    850     if (cpairs == 0) {
    851         klispE_throw_simple(K, "non pair found while traversing "
    852                             "object");
    853         return 0;
    854     }
    855     TValue tv_apairs = i2tv(apairs);
    856     TValue tv_cpairs = i2tv(cpairs);
    857 	
    858     /* all calculations will be done with bigints */
    859     kensure_bigint(tv_apairs);
    860     kensure_bigint(tv_cpairs);
    861 	
    862     TValue idx = kbigint_minus(K, tk, tv_apairs);
    863     krooted_tvs_push(K, idx); /* root idx if it is a bigint */
    864     /* idx may have become a fixint */
    865     kensure_bigint(idx);
    866     UNUSED(kbigint_div_mod(K, idx, tv_cpairs, &idx));
    867     krooted_tvs_pop(K);
    868     /* now idx is less than cpairs so it fits in a fixint */
    869     assert(ttisfixint(idx));
    870     return ivalue(idx) + apairs; 
    871 }
    872 
    873 /* Helper for eq? and equal? */
    874 bool eq2p(klisp_State *K, TValue obj1, TValue obj2)
    875 {
    876     bool res = (tv_equal(obj1, obj2));
    877     if (!res && (ttype(obj1) == ttype(obj2))) {
    878         switch (ttype(obj1)) {
    879         case K_TSYMBOL:
    880             /* symbols can't be compared with tv_equal! */
    881             res = tv_sym_equal(obj1, obj2);
    882             break;
    883         case K_TAPPLICATIVE:
    884             while(ttisapplicative(obj1) && ttisapplicative(obj2)) {
    885                 obj1 = kunwrap(obj1);
    886                 obj2 = kunwrap(obj2);
    887             }
    888             res = (tv_equal(obj1, obj2));
    889             break;
    890         case K_TBIGINT:
    891             /* it's important to know that it can't be the case
    892                that obj1 is bigint and obj is some other type and
    893                (eq? obj1 obj2) */
    894             res = kbigint_eqp(obj1, obj2);
    895             break;
    896         case K_TBIGRAT:
    897             /* it's important to know that it can't be the case
    898                that obj1 is bigrat and obj is some other type and
    899                (eq? obj1 obj2) */
    900             res = kbigrat_eqp(K, obj1, obj2);
    901             break;
    902         } /* immutable strings & bytevectors are interned so they are 
    903              covered already by tv_equalp */
    904 
    905     }
    906     return res;
    907 }
    908 
    909 /*
    910 ** Helpers for equal? algorithm
    911 **
    912 ** See [2] for details of the list merging algorithm. 
    913 ** Here are the implementation details:
    914 ** The marks of the pairs are used to store the nodes of the trees 
    915 ** that represent the set of previous comparations of each pair. 
    916 ** They serve the function of the array in [2].
    917 ** If a pair is unmarked, it was never compared (empty comparison set). 
    918 ** If a pair is marked, the mark object is either (#f . parent-node) 
    919 ** if the node is not the root, and (#t . n) where n is the number 
    920 ** of elements in the set, if the node is the root. 
    921 ** This pair also doubles as the "name" of the set in [2].
    922 **
    923 ** GC: all of these assume that arguments are rooted.
    924 */
    925 
    926 /* find "name" of the set of this obj, if there isn't one create it,
    927    if there is one, flatten its branch */
    928 static inline TValue equal_find(klisp_State *K, TValue obj)
    929 {
    930     /* GC: should root obj */
    931     if (kis_unmarked(obj)) {
    932         /* object wasn't compared before, create new set */
    933         TValue new_node = kcons(K, KTRUE, i2tv(1));
    934         kset_mark(obj, new_node);
    935         return new_node;
    936     } else {		
    937         TValue node = kget_mark(obj);
    938 
    939         /* First obtain the root and a list of all the other objects in this 
    940            branch, as said above the root is the one with #t in its car */
    941         /* NOTE: the stack is being used, so we must remember how many pairs we 
    942            push, we can't just pop 'till is empty */
    943         int np = 0;
    944         while(kis_false(kcar(node))) {
    945             ks_spush(K, node);
    946             node = kcdr(node);
    947             ++np;
    948         }
    949         TValue root = node;
    950 
    951         /* set all parents to root, to flatten the branch */
    952         while(np--) {
    953             node = ks_spop(K);
    954             kset_cdr(node, root);
    955         }
    956         return root;
    957     }
    958 }
    959 
    960 /* merge the smaller set into the big one, if both are equal just pick one */
    961 static inline void equal_merge(klisp_State *K, TValue root1, TValue root2)
    962 {
    963     /* K isn't needed but added for consistency */
    964     UNUSED(K);
    965     int32_t size1 = ivalue(kcdr(root1));
    966     int32_t size2 = ivalue(kcdr(root2));
    967     TValue new_size = i2tv(size1 + size2);
    968     
    969     if (size1 < size2) {
    970         /* add root1 set (the smaller one) to root2 */
    971         kset_cdr(root2, new_size);
    972         kset_car(root1, KFALSE);
    973         kset_cdr(root1, root2);
    974     } else {
    975         /* add root2 set (the smaller one) to root1 */
    976         kset_cdr(root1, new_size);
    977         kset_car(root2, KFALSE);
    978         kset_cdr(root2, root1);
    979     }
    980 }
    981 
    982 /* check to see if two objects were already compared, and return that. If they
    983    weren't compared yet, merge their sets (and flatten their branches) */
    984 static inline bool equal_find2_mergep(klisp_State *K, TValue obj1, TValue obj2)
    985 {
    986     /* GC: should root root1 and root2 */
    987     TValue root1 = equal_find(K, obj1);
    988     TValue root2 = equal_find(K, obj2);
    989     if (tv_equal(root1, root2)) {
    990         /* they are in the same set => they were already compared */
    991         return true;
    992     } else {
    993         equal_merge(K, root1, root2);
    994         return false;
    995     }
    996 }
    997 
    998 /*
    999 ** See [1] for details, in this case the pairs form a possibly infinite "tree" 
   1000 ** structure, and that can be seen as a finite automata, where each node is a 
   1001 ** state, the car and the cdr are the transitions from that state to others, 
   1002 ** and the leaves (the non-pair objects) are the final states.
   1003 ** Other way to see it is that, the key for determining equalness of two pairs 
   1004 ** is: Check to see if they were already compared to each other.
   1005 ** If so, return #t, otherwise, mark them as compared to each other and 
   1006 ** recurse on both cars and both cdrs.
   1007 ** The idea is that if assuming obj1 and obj2 are equal their components are 
   1008 ** equal then they are effectively equal to each other.
   1009 */
   1010 bool equal2p(klisp_State *K, TValue obj1, TValue obj2)
   1011 {
   1012     assert(ks_sisempty(K));
   1013 
   1014     /* the stack has the elements to be compaired, always in pairs.
   1015        So the top should be compared with the one below, the third with
   1016        the fourth and so on */
   1017     ks_spush(K, obj1);
   1018     ks_spush(K, obj2);
   1019 
   1020     /* if the stacks becomes empty, all pairs of elements were equal */
   1021     bool result = true;
   1022     TValue saved_obj1 = obj1;
   1023     TValue saved_obj2 = obj2;
   1024 
   1025     while(!ks_sisempty(K)) {
   1026         obj2 = ks_spop(K);
   1027         obj1 = ks_spop(K);
   1028 
   1029         if (!eq2p(K, obj1, obj2)) {
   1030             /* This type comparison works because we just care about
   1031                pairs, vectors, strings & bytevectors */
   1032             if (ttype(obj1) == ttype(obj2)) {
   1033                 switch(ttype(obj1)) {
   1034                 case K_TPAIR:
   1035                     /* if they were already compaired, consider equal for 
   1036                        now otherwise they are equal if both their cars 
   1037                        and cdrs are */
   1038                     if (!equal_find2_mergep(K, obj1, obj2)) {
   1039                         ks_spush(K, kcdr(obj1));
   1040                         ks_spush(K, kcdr(obj2));
   1041                         ks_spush(K, kcar(obj1));
   1042                         ks_spush(K, kcar(obj2));
   1043                     }
   1044                     break;
   1045                 case K_TVECTOR:
   1046                     if (kvector_size(obj1) == kvector_size(obj2)) {
   1047                         /* if they were already compaired, consider equal for 
   1048                            now otherwise they are equal if all their elements
   1049                            are equal pairwise */
   1050                         if (!equal_find2_mergep(K, obj1, obj2)) {
   1051                             uint32_t i = kvector_size(obj1);
   1052                             TValue *array1 = kvector_buf(obj1);
   1053                             TValue *array2 = kvector_buf(obj2);
   1054                             while(i-- > 0) {
   1055                                 ks_spush(K, array1[i]);
   1056                                 ks_spush(K, array2[i]);
   1057                             }
   1058                         }
   1059                     } else {
   1060                         result = false;
   1061                         goto end;
   1062                     }
   1063                     break;
   1064                 case K_TSTRING:
   1065                     if (!kstring_equalp(obj1, obj2)) {
   1066                         result = false;
   1067                         goto end;
   1068                     }
   1069                     break;
   1070                 case K_TBYTEVECTOR:
   1071                     if (!kbytevector_equalp(K, obj1, obj2)) {
   1072                         result = false;
   1073                         goto end;
   1074                     }
   1075                     break;
   1076                 default:
   1077                     result = false;
   1078                     goto end;
   1079                 }
   1080             } else {
   1081                 result = false;
   1082                 goto end;
   1083             }
   1084         }
   1085     }
   1086 end:
   1087     /* if result is false, the stack may not be empty */
   1088     ks_sclear(K);
   1089 
   1090     unmark_tree(K, saved_obj1);
   1091     unmark_tree(K, saved_obj2);
   1092     
   1093     return result;
   1094 }
   1095 
   1096 /*
   1097 ** This is in a helper method to use it from $lambda, $vau, etc
   1098 **
   1099 ** We mark each seen mutable pair with the corresponding copied 
   1100 ** immutable pair to construct a structure that is isomorphic to 
   1101 ** the original.
   1102 ** All objects that aren't mutable pairs are retained without 
   1103 ** copying
   1104 ** sstack is used to keep track of pairs and tbstack is used
   1105 ** to keep track of which of car or cdr we were copying,
   1106 ** 0 means just pushed, 1 means return from car, 2 means return from cdr
   1107 **
   1108 ** This also copies source code info
   1109 **
   1110 */
   1111 
   1112 /* GC: assumes obj is rooted */
   1113 TValue copy_es_immutable_h(klisp_State *K, TValue obj, bool mut_flag)
   1114 {
   1115     TValue copy = obj;
   1116     krooted_vars_push(K, &copy);
   1117 
   1118     assert(ks_sisempty(K));
   1119     assert(ks_tbisempty(K));
   1120 
   1121     ks_spush(K, obj);
   1122     ks_tbpush(K, ST_PUSH);
   1123 
   1124     while(!ks_sisempty(K)) {
   1125         char state = ks_tbpop(K);
   1126         TValue top = ks_spop(K);
   1127 
   1128         if (state == ST_PUSH) {
   1129             /* if the pair is immutable & we are constructing immutable
   1130                pairs there is no need to copy */
   1131             if (ttispair(top) && (mut_flag || kis_mutable(top))) {
   1132                 if (kis_marked(top)) {
   1133                     /* this pair was already seen, use the same */
   1134                     copy = kget_mark(top);
   1135                 } else {
   1136                     TValue new_pair = kcons_g(K, mut_flag, KINERT, KINERT);
   1137                     kset_mark(top, new_pair);
   1138                     /* save the source code info on the new pair */
   1139                     /* MAYBE: only do it if mutable */
   1140                     TValue si = ktry_get_si(K, top);
   1141                     if (!ttisnil(si))
   1142                         kset_source_info(K, new_pair, si);
   1143                     /* leave the pair in the stack, continue with the car */
   1144                     ks_spush(K, top);
   1145                     ks_tbpush(K, ST_CAR);
   1146 		    
   1147                     ks_spush(K, kcar(top));
   1148                     ks_tbpush(K, ST_PUSH);
   1149                 }
   1150             } else {
   1151                 copy = top;
   1152             }
   1153         } else { /* last action was a pop */
   1154             TValue new_pair = kget_mark(top);
   1155             if (state == ST_CAR) {
   1156                 /* new_pair may be immutable */
   1157                 kset_car_unsafe(K, new_pair, copy);
   1158                 /* leave the pair on the stack, continue with the cdr */
   1159                 ks_spush(K, top);
   1160                 ks_tbpush(K, ST_CDR);
   1161 
   1162                 ks_spush(K, kcdr(top));
   1163                 ks_tbpush(K, ST_PUSH);
   1164             } else {
   1165                 /* new_pair may be immutable */
   1166                 kset_cdr_unsafe(K, new_pair, copy);
   1167                 copy = new_pair;
   1168             }
   1169         }
   1170     }
   1171     unmark_tree(K, obj);
   1172     krooted_vars_pop(K);
   1173     return copy;
   1174 }
   1175 
   1176 /* ptree handling */
   1177 
   1178 /*
   1179 ** Clear all the marks (symbols + pairs) & stacks.
   1180 ** The stack should contain only pairs, sym_ls should be
   1181 ** as above 
   1182 */    
   1183 static inline void ptree_clear_all(klisp_State *K, TValue sym_ls)
   1184 {
   1185     while(!ttisnil(sym_ls)) {
   1186         TValue first = sym_ls;
   1187         sym_ls = kget_symbol_mark(first);
   1188         kunmark_symbol(first);
   1189     }
   1190 
   1191     while(!ks_sisempty(K)) {
   1192         kunmark(ks_sget(K));
   1193         ks_sdpop(K);
   1194     }
   1195 
   1196     ks_tbclear(K);
   1197 }
   1198 
   1199 /* GC: assumes env, ptree & obj are rooted */
   1200 void match(klisp_State *K, TValue env, TValue ptree, TValue obj)
   1201 {
   1202     assert(ks_sisempty(K));
   1203     ks_spush(K, obj);
   1204     ks_spush(K, ptree);
   1205 
   1206     while(!ks_sisempty(K)) {
   1207         ptree = ks_spop(K);
   1208         obj = ks_spop(K);
   1209 
   1210         switch(ttype(ptree)) {
   1211         case K_TNIL:
   1212             if (!ttisnil(obj)) {
   1213                 /* TODO show ptree and arguments */
   1214                 ks_sclear(K);
   1215                 klispE_throw_simple(K, "ptree doesn't match arguments");
   1216                 return;
   1217             }
   1218             break;
   1219         case K_TIGNORE:
   1220             /* do nothing */
   1221             break;
   1222         case K_TSYMBOL:
   1223             kadd_binding(K, env, ptree, obj);
   1224             break;
   1225         case K_TPAIR:
   1226             if (ttispair(obj)) {
   1227                 ks_spush(K, kcdr(obj));
   1228                 ks_spush(K, kcdr(ptree));
   1229                 ks_spush(K, kcar(obj));
   1230                 ks_spush(K, kcar(ptree));
   1231             } else {
   1232                 /* TODO show ptree and arguments */
   1233                 ks_sclear(K);
   1234                 klispE_throw_simple(K, "ptree doesn't match arguments");
   1235                 return;
   1236             }
   1237             break;
   1238         default:
   1239             /* can't really happen */
   1240             break;
   1241         }
   1242     }
   1243 }
   1244 
   1245 /* GC: assumes ptree & penv are rooted */
   1246 TValue check_copy_ptree(klisp_State *K, TValue ptree, TValue penv)
   1247 {
   1248     /* copy is only valid if the state isn't ST_PUSH */
   1249     /* but init anyways for gc (and avoiding warnings) */
   1250     TValue copy = ptree;
   1251     krooted_vars_push(K, &copy);
   1252 
   1253     /* 
   1254     ** NIL terminated singly linked list of symbols 
   1255     ** (using the mark as next pointer) 
   1256     */
   1257     TValue sym_ls = KNIL;
   1258 
   1259     assert(ks_sisempty(K));
   1260     assert(ks_tbisempty(K));
   1261 
   1262     ks_tbpush(K, ST_PUSH);
   1263     ks_spush(K, ptree);
   1264 
   1265     while(!ks_sisempty(K)) {
   1266         char state = ks_tbpop(K);
   1267         TValue top = ks_spop(K);
   1268 
   1269         if (state == ST_PUSH) {
   1270             switch(ttype(top)) {
   1271             case K_TIGNORE:
   1272             case K_TNIL:
   1273                 copy = top;
   1274                 break;
   1275             case K_TSYMBOL: {
   1276                 if (kis_symbol_marked(top)) {
   1277                     ptree_clear_all(K, sym_ls);
   1278                     klispE_throw_simple_with_irritants(K, "repeated symbol "
   1279                                                        "in ptree", 1, top);
   1280                     return KNIL;
   1281                 } else {
   1282                     copy = top;
   1283                     /* add it to the symbol list */
   1284                     kset_symbol_mark(top, sym_ls);
   1285                     sym_ls = top;
   1286                 }
   1287                 break;
   1288             }
   1289             case K_TPAIR: {
   1290                 if (kis_unmarked(top)) {
   1291                     if (kis_immutable(top)) {
   1292                         /* don't copy mutable pairs, just use them */
   1293                         /* NOTE: immutable pairs can't have mutable
   1294                            car or cdr */
   1295                         /* we have to continue thou, because there could be a 
   1296                            cycle */
   1297                         kset_mark(top, top);
   1298                     } else {
   1299                         /* create a new pair as copy, save it in the mark */
   1300                         TValue new_pair = kimm_cons(K, KNIL, KNIL);
   1301                         kset_mark(top, new_pair);
   1302                         /* copy the source code info */
   1303                         TValue si = ktry_get_si(K, top);
   1304                         if (!ttisnil(si))
   1305                             kset_source_info(K, new_pair, si);
   1306                     }
   1307                     /* keep the old pair and continue with the car */
   1308                     ks_tbpush(K, ST_CAR); 
   1309                     ks_spush(K, top); 
   1310 
   1311                     ks_tbpush(K, ST_PUSH); 
   1312                     ks_spush(K, kcar(top)); 
   1313                 } else {
   1314                     /* marked pair means a cycle was found */
   1315                     /* NOTE: the pair should be in the stack already so
   1316                        it isn't necessary to push it again to clear the mark */
   1317                     ptree_clear_all(K, sym_ls);
   1318                     klispE_throw_simple(K, "cycle detected in ptree");
   1319                     /* avoid warning */
   1320                     return KNIL;
   1321                 }
   1322                 break;
   1323             }
   1324             default:
   1325                 ptree_clear_all(K, sym_ls);
   1326                 klispE_throw_simple(K, "bad object type in ptree");
   1327                 /* avoid warning */
   1328                 return KNIL;
   1329             }
   1330         } else { 
   1331             /* last operation was a pop */
   1332             /* top is a marked pair, the mark is the copied obj */
   1333             /* NOTE: if top is immutable the mark is also top 
   1334                we could still do the set-car/set-cdr because the
   1335                copy would be the same as the car/cdr, but why bother */
   1336             if (state == ST_CAR) { 
   1337                 /* only car was checked (not yet copied) */
   1338                 if (kis_mutable(top)) {
   1339                     TValue copied_pair = kget_mark(top);
   1340                     /* copied_pair may be immutable */
   1341                     kset_car_unsafe(K, copied_pair, copy);
   1342                 }
   1343                 /* put the copied pair again, continue with the cdr */
   1344                 ks_tbpush(K, ST_CDR);
   1345                 ks_spush(K, top); 
   1346 
   1347                 ks_tbpush(K, ST_PUSH);
   1348                 ks_spush(K, kcdr(top)); 
   1349             } else { 
   1350                 /* both car & cdr were checked (cdr not yet copied) */
   1351                 TValue copied_pair = kget_mark(top);
   1352                 /* the unmark is needed to allow diamonds */
   1353                 kunmark(top);
   1354 
   1355                 if (kis_mutable(top)) {
   1356                     /* copied_pair may be immutable */
   1357                     kset_cdr_unsafe(K, copied_pair, copy);
   1358                 }
   1359                 copy = copied_pair;
   1360             }
   1361         }
   1362     }
   1363 
   1364     if (ttissymbol(penv)) {
   1365         if (kis_symbol_marked(penv)) {
   1366             ptree_clear_all(K, sym_ls);
   1367             klispE_throw_simple_with_irritants(K, "same symbol in both ptree "
   1368                                                "and environment parameter",
   1369                                                1, sym_ls);
   1370         }
   1371     } else if (!ttisignore(penv)) {
   1372 	    ptree_clear_all(K, sym_ls);
   1373 	    klispE_throw_simple(K, "symbol or #ignore expected as "
   1374                             "environment parmameter");
   1375     }
   1376     ptree_clear_all(K, sym_ls);
   1377     krooted_vars_pop(K);
   1378     return copy;
   1379 }
   1380 
   1381 /* Helpers for map (also used by for each) */
   1382 void map_for_each_get_metrics(klisp_State *K, TValue lss,
   1383                               int32_t *app_apairs_out, int32_t *app_cpairs_out,
   1384                               int32_t *res_apairs_out, int32_t *res_cpairs_out)
   1385 {
   1386     /* avoid warnings (shouldn't happen if _No_return was used in throw) */
   1387     *app_apairs_out = 0;
   1388     *app_cpairs_out = 0;
   1389     *res_apairs_out = 0;
   1390     *res_cpairs_out = 0;
   1391 
   1392     /* get the metrics of the ptree of each call to app */
   1393     int32_t app_pairs, app_cpairs;
   1394     check_list(K, true, lss, &app_pairs, &app_cpairs);
   1395     int32_t app_apairs = app_pairs - app_cpairs;
   1396 
   1397     /* get the metrics of the result list */
   1398     int32_t res_pairs, res_cpairs;
   1399     /* We now that lss has at least one elem */
   1400     check_list(K, true, kcar(lss), &res_pairs, &res_cpairs);
   1401     int32_t res_apairs = res_pairs - res_cpairs;
   1402     
   1403     if (res_cpairs == 0) {
   1404         /* finite list of length res_pairs (all lists should
   1405            have the same structure: acyclic with same length) */
   1406         int32_t pairs = app_pairs - 1;
   1407         TValue tail = kcdr(lss);
   1408         while(pairs--) {
   1409             int32_t first_pairs, first_cpairs;
   1410             check_list(K, true, kcar(tail), &first_pairs, &first_cpairs);
   1411             tail = kcdr(tail);
   1412 
   1413             if (first_cpairs != 0) {
   1414                 klispE_throw_simple(K, "mixed finite and infinite lists");
   1415                 return;
   1416             } else if (first_pairs != res_pairs) {
   1417                 klispE_throw_simple(K, "lists of different length");
   1418                 return;
   1419             }
   1420         }
   1421     } else {
   1422         /* cyclic list: all lists should be cyclic.
   1423            result will have acyclic length equal to the
   1424            max of all the lists and cyclic length equal to the lcm
   1425            of all the lists. res_pairs may be broken but will be 
   1426            restored by after the loop */
   1427         int32_t pairs = app_pairs - 1;
   1428         TValue tail = kcdr(lss);
   1429         while(pairs--) {
   1430             int32_t first_pairs, first_cpairs;
   1431             check_list(K, true, kcar(tail), &first_pairs, &first_cpairs);
   1432             int32_t first_apairs = first_pairs - first_cpairs;
   1433             tail = kcdr(tail);
   1434 
   1435             if (first_cpairs == 0) {
   1436                 klispE_throw_simple(K, "mixed finite and infinite lists");
   1437                 return;
   1438             } 
   1439             res_apairs = kmax32(res_apairs, first_apairs);
   1440             /* this can throw an error if res_cpairs doesn't 
   1441                fit in 32 bits, which is a reasonable implementation
   1442                restriction because the list wouldn't fit in memory 
   1443                anyways */
   1444             res_cpairs = kcheck32(K, "map/for-each: result list is too big", 
   1445                                   klcm32_64(res_cpairs, first_cpairs));
   1446         }
   1447         res_pairs = kcheck32(K, "map/for-each: result list is too big", 
   1448                              (int64_t) res_cpairs + (int64_t) res_apairs);
   1449         UNUSED(res_pairs);
   1450     }
   1451 
   1452     *app_apairs_out = app_apairs;
   1453     *app_cpairs_out = app_cpairs;
   1454     *res_apairs_out = res_apairs;
   1455     *res_cpairs_out = res_cpairs;
   1456 }
   1457 
   1458 /* Return two lists, isomorphic to lss: one list of cars and one list
   1459    of cdrs (replacing the value of lss) */
   1460 
   1461 /* GC: assumes lss is rooted */
   1462 TValue map_for_each_get_cars_cdrs(klisp_State *K, TValue *lss, 
   1463                                   int32_t apairs, int32_t cpairs)
   1464 {
   1465     TValue tail = *lss;
   1466 
   1467     TValue cars = kcons(K, KNIL, KNIL);
   1468     krooted_vars_push(K, &cars);
   1469     TValue lp_cars = cars;
   1470     TValue lap_cars = lp_cars;
   1471 
   1472     TValue cdrs = kcons(K, KNIL, KNIL);
   1473     krooted_vars_push(K, &cdrs);
   1474     TValue lp_cdrs = cdrs;
   1475     TValue lap_cdrs = lp_cdrs;
   1476     
   1477     while(apairs != 0 || cpairs != 0) {
   1478         int32_t pairs;
   1479         if (apairs != 0) {
   1480             pairs = apairs;
   1481         } else {
   1482             /* remember last acyclic pair of both lists to to encycle! later */
   1483             lap_cars = lp_cars;
   1484             lap_cdrs = lp_cdrs;
   1485             pairs = cpairs;
   1486         }
   1487 
   1488         while(pairs--) {
   1489             TValue first = kcar(tail);
   1490             tail = kcdr(tail);
   1491 	 
   1492             /* accumulate both cars and cdrs */
   1493             TValue np;
   1494             np = kcons(K, kcar(first), KNIL);
   1495             kset_cdr(lp_cars, np);
   1496             lp_cars = np;
   1497 
   1498             np = kcons(K, kcdr(first), KNIL);
   1499             kset_cdr(lp_cdrs, np);
   1500             lp_cdrs = np;
   1501         }
   1502 
   1503         if (apairs != 0) {
   1504             apairs = 0;
   1505         } else {
   1506             cpairs = 0;
   1507             /* encycle! the list of cars and the list of cdrs */
   1508             TValue fcp, lcp;
   1509             fcp = kcdr(lap_cars);
   1510             lcp = lp_cars;
   1511             kset_cdr(lcp, fcp);
   1512 
   1513             fcp = kcdr(lap_cdrs);
   1514             lcp = lp_cdrs;
   1515             kset_cdr(lcp, fcp);
   1516         }
   1517     }
   1518 
   1519     krooted_vars_pop(K);
   1520     krooted_vars_pop(K);
   1521     *lss = kcdr(cdrs);
   1522     return kcdr(cars);
   1523 }
   1524 
   1525 /* Transpose lss so that the result is a list of lists, each one having
   1526    metrics (app_apairs, app_cpairs). The metrics of the returned list
   1527    should be (res_apairs, res_cpairs) */
   1528 
   1529 /* GC: assumes lss is rooted */
   1530 TValue map_for_each_transpose(klisp_State *K, TValue lss, 
   1531                               int32_t app_apairs, int32_t app_cpairs, 
   1532                               int32_t res_apairs, int32_t res_cpairs)
   1533 {
   1534     TValue tlist = kcons(K, KNIL, KNIL);
   1535     krooted_vars_push(K, &tlist);    
   1536     TValue lp = tlist;
   1537     TValue lap = lp;
   1538 
   1539     TValue cars = KNIL; /* put something for GC */
   1540     TValue tail = lss;
   1541 
   1542     /* GC: both cars & tail vary in each loop, to protect them we need
   1543        the vars stack */
   1544     krooted_vars_push(K, &cars);
   1545     krooted_vars_push(K, &tail);
   1546     
   1547     /* Loop over list of lists, creating a list of cars and 
   1548        a list of cdrs, accumulate the list of cars and loop
   1549        with the list of cdrs as the new list of lists (lss) */
   1550     while(res_apairs != 0 || res_cpairs != 0) {
   1551         int32_t pairs;
   1552 	
   1553         if (res_apairs != 0) {
   1554             pairs = res_apairs;
   1555         } else {
   1556             pairs = res_cpairs;
   1557             /* remember last acyclic pair to encycle! later */
   1558             lap = lp;
   1559         }
   1560 
   1561         while(pairs--) {
   1562             /* accumulate cars and replace tail with cdrs */
   1563             cars = map_for_each_get_cars_cdrs(K, &tail, app_apairs, app_cpairs);
   1564             TValue np = kcons(K, cars, KNIL);
   1565             kset_cdr(lp, np);
   1566             lp = np;
   1567         }
   1568 
   1569         if (res_apairs != 0) {
   1570             res_apairs = 0;
   1571         } else {
   1572             res_cpairs = 0;
   1573             /* encycle! the list of list of cars */
   1574             TValue fcp = kcdr(lap);
   1575             TValue lcp = lp;
   1576             kset_cdr(lcp, fcp);
   1577         }
   1578     }
   1579 
   1580     krooted_vars_pop(K);
   1581     krooted_vars_pop(K);
   1582     krooted_vars_pop(K);
   1583     return kcdr(tlist);
   1584 }
   1585 
   1586 /* Continuations that are used in more than one file */
   1587 
   1588 /* Helper for $sequence, $vau, $lambda, ... */
   1589 /* the remaining list can't be null, that case is managed before */
   1590 void do_seq(klisp_State *K)
   1591 {
   1592     TValue *xparams = K->next_xparams;
   1593     TValue obj = K->next_value;
   1594     klisp_assert(ttisnil(K->next_env));
   1595 
   1596     UNUSED(obj);
   1597 
   1598     /* 
   1599     ** xparams[0]: remaining list
   1600     ** xparams[1]: dynamic environment
   1601     */
   1602     TValue ls = xparams[0];
   1603     TValue first = kcar(ls);
   1604     TValue tail = kcdr(ls);
   1605     TValue denv = xparams[1];
   1606 
   1607     if (ttispair(tail)) {
   1608         TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, tail, 
   1609                                              denv);
   1610         kset_cc(K, new_cont);
   1611 #if KTRACK_SI
   1612         /* put the source info of the list including the element
   1613            that we are about to evaluate */
   1614         kset_source_info(K, new_cont, ktry_get_si(K, ls));
   1615 #endif
   1616     }
   1617     ktail_eval(K, first, denv);
   1618 }
   1619 
   1620 /* this is used for inner & outer continuations, it just
   1621    passes the value. xparams is not actually empty, it contains
   1622    the entry/exit guards, but they are used only in 
   1623    continuation->applicative (that is during abnormal passes) */
   1624 void do_pass_value(klisp_State *K)
   1625 {
   1626     TValue *xparams = K->next_xparams;
   1627     TValue obj = K->next_value;
   1628     klisp_assert(ttisnil(K->next_env));
   1629     UNUSED(xparams);
   1630     kapply_cc(K, obj);
   1631 }
   1632 
   1633 /* 
   1634 ** Continuation that ignores the value received and instead returns
   1635 ** a previously computed value.
   1636 */
   1637 void do_return_value(klisp_State *K)
   1638 {
   1639     TValue *xparams = K->next_xparams;
   1640     TValue obj = K->next_value;
   1641     klisp_assert(ttisnil(K->next_env));
   1642     /*
   1643     ** xparams[0]: saved_obj
   1644     */
   1645     UNUSED(obj);
   1646     TValue ret_obj = xparams[0];
   1647     kapply_cc(K, ret_obj);
   1648 }
   1649 
   1650 /* binder returned */
   1651 void do_bind(klisp_State *K)
   1652 {
   1653     TValue *xparams = K->next_xparams;
   1654     TValue ptree = K->next_value;
   1655     TValue denv = K->next_env;
   1656     klisp_assert(ttisenvironment(K->next_env));
   1657     /*
   1658     ** xparams[0]: dynamic key 
   1659     */
   1660     bind_2tp(K, ptree, "any", anytype, obj,
   1661 	         "combiner", ttiscombiner, comb);
   1662     UNUSED(denv); /* the combiner is called in an empty environment */
   1663     TValue key = xparams[0];
   1664     /* GC: root intermediate objs */
   1665     TValue new_flag = KTRUE;
   1666     TValue new_value = obj;
   1667     TValue old_flag = kcar(key);
   1668     TValue old_value = kcdr(key);
   1669     /* set the var to the new object */
   1670     kset_car(key, new_flag);
   1671     kset_cdr(key, new_value);
   1672     /* Old value must be protected from GC. It is no longer
   1673        reachable through key and not yet reachable through
   1674        continuation xparams. Boolean flag needn't be rooted,
   1675        because is not heap-allocated. */
   1676     krooted_tvs_push(K, old_value);
   1677     /* create a continuation to set the var to the correct value/flag on both
   1678        normal return and abnormal passes */
   1679     TValue new_cont = make_bind_continuation(K, key, old_flag, old_value,
   1680                                              new_flag, new_value);
   1681     krooted_tvs_pop(K);
   1682     kset_cc(K, new_cont); /* implicit rooting */
   1683     TValue env = kmake_empty_environment(K);
   1684     krooted_tvs_push(K, env);
   1685     TValue expr = kcons(K, comb, KNIL);
   1686     krooted_tvs_pop(K);
   1687     ktail_eval(K, expr, env)
   1688         }
   1689 
   1690 /* accesor returned */
   1691 void do_access(klisp_State *K)
   1692 {
   1693     TValue *xparams = K->next_xparams;
   1694     TValue ptree = K->next_value;
   1695     TValue denv = K->next_env;
   1696     klisp_assert(ttisenvironment(K->next_env));
   1697     /*
   1698     ** xparams[0]: dynamic key 
   1699     */
   1700     check_0p(K, ptree);
   1701     UNUSED(denv);
   1702     TValue key = xparams[0];
   1703 
   1704     if (kis_true(kcar(key))) {
   1705         kapply_cc(K, kcdr(key));
   1706     } else {
   1707         klispE_throw_simple(K, "variable is unbound");
   1708         return;
   1709     }
   1710 }
   1711 
   1712 /* continuation to set the key to the old value on normal return */
   1713 void do_unbind(klisp_State *K)
   1714 {
   1715     TValue *xparams = K->next_xparams;
   1716     TValue obj = K->next_value;
   1717     klisp_assert(ttisnil(K->next_env));
   1718     /*
   1719     ** xparams[0]: dynamic key
   1720     ** xparams[1]: old flag
   1721     ** xparams[2]: old value
   1722     */
   1723 
   1724     TValue key = xparams[0];
   1725     TValue old_flag = xparams[1];
   1726     TValue old_value = xparams[2];
   1727 
   1728     kset_car(key, old_flag);
   1729     kset_cdr(key, old_value);
   1730     /* pass along the value returned to this continuation */
   1731     kapply_cc(K, obj);
   1732 }
   1733 
   1734 /* operative for setting the key to the new/old flag/value */
   1735 void do_set_pass(klisp_State *K)
   1736 {
   1737     TValue *xparams = K->next_xparams;
   1738     TValue ptree = K->next_value;
   1739     TValue denv = K->next_env;
   1740     klisp_assert(ttisenvironment(K->next_env));
   1741     /*
   1742     ** xparams[0]: dynamic key
   1743     ** xparams[1]: flag
   1744     ** xparams[2]: value
   1745     */
   1746     TValue key = xparams[0];
   1747     TValue flag = xparams[1];
   1748     TValue value = xparams[2];
   1749     UNUSED(denv);
   1750 
   1751     kset_car(key, flag);
   1752     kset_cdr(key, value);
   1753 
   1754     /* pass to next interceptor/ final destination */
   1755     /* ptree is as for interceptors: (obj divert) */
   1756     TValue obj = kcar(ptree);
   1757     kapply_cc(K, obj);
   1758 }
   1759 
   1760 /* /Continuations that are used in more than one file */
   1761 
   1762 /* dynamic keys */
   1763 /* create continuation to set the key on both normal return and
   1764    abnormal passes */
   1765 /* TODO: reuse the code for guards in kgcontinuations.c */
   1766 
   1767 /* GC: this assumes that key, old_value and new_value are rooted */
   1768 TValue make_bind_continuation(klisp_State *K, TValue key,
   1769                               TValue old_flag, TValue old_value, 
   1770                               TValue new_flag, TValue new_value)
   1771 {
   1772     TValue unbind_cont = kmake_continuation(K, kget_cc(K), 
   1773                                             do_unbind, 3, key, old_flag, 
   1774                                             old_value);
   1775     krooted_tvs_push(K, unbind_cont);
   1776     /* create the guards to guarantee that the values remain consistent on
   1777        abnormal passes (in both directions) */
   1778     TValue exit_int = kmake_operative(K, do_set_pass, 
   1779                                       3, key, old_flag, old_value);
   1780     krooted_tvs_push(K, exit_int);
   1781     TValue exit_guard = kcons(K, G(K)->root_cont, exit_int);
   1782     krooted_tvs_pop(K); /* already rooted in guard */
   1783     krooted_tvs_push(K, exit_guard);
   1784     TValue exit_guards = kcons(K, exit_guard, KNIL);
   1785     krooted_tvs_pop(K); /* already rooted in guards */
   1786     krooted_tvs_push(K, exit_guards);
   1787 
   1788     TValue entry_int = kmake_operative(K, do_set_pass, 
   1789                                        3, key, new_flag, new_value);
   1790     krooted_tvs_push(K, entry_int);
   1791     TValue entry_guard = kcons(K, G(K)->root_cont, entry_int);
   1792     krooted_tvs_pop(K); /* already rooted in guard */
   1793     krooted_tvs_push(K, entry_guard);
   1794     TValue entry_guards = kcons(K, entry_guard, KNIL);
   1795     krooted_tvs_pop(K); /* already rooted in guards */
   1796     krooted_tvs_push(K, entry_guards);
   1797 
   1798 
   1799     /* NOTE: in the stack now we have the unbind cont & two guard lists */
   1800     /* this is needed for interception code */
   1801     TValue env = kmake_empty_environment(K);
   1802     krooted_tvs_push(K, env);
   1803     TValue outer_cont = kmake_continuation(K, unbind_cont, 
   1804                                            do_pass_value, 2, entry_guards, env);
   1805     kset_outer_cont(outer_cont);
   1806     krooted_tvs_push(K, outer_cont);
   1807     TValue inner_cont = kmake_continuation(K, outer_cont, 
   1808                                            do_pass_value, 2, exit_guards, env);
   1809     kset_inner_cont(inner_cont);
   1810 
   1811     /* unbind_cont & 2 guard_lists */
   1812     krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K);
   1813     /* env & outer_cont */
   1814     krooted_tvs_pop(K); krooted_tvs_pop(K);
   1815     
   1816     return inner_cont;
   1817 }
   1818 
   1819 /* Helpers for guard-continuation (& guard-dynamic-extent) */
   1820 
   1821 #define singly_wrapped(obj_) (ttisapplicative(obj_) &&      \
   1822                               ttisoperative(kunwrap(obj_)))
   1823 
   1824 /* this unmarks root before throwing any error */
   1825 /* TODO: this isn't very clean, refactor */
   1826 
   1827 /* GC: assumes obj & root are rooted */
   1828 static inline TValue check_copy_single_entry(klisp_State *K, char *name,
   1829                                       TValue obj, TValue root)
   1830 {
   1831     if (!ttispair(obj) || !ttispair(kcdr(obj)) || 
   1832 	    !ttisnil(kcddr(obj))) {
   1833         unmark_list(K, root);
   1834         klispE_throw_simple(K, "Bad entry (expected list of length 2)");
   1835         return KINERT;
   1836     } 
   1837     TValue cont = kcar(obj);
   1838     TValue app = kcadr(obj);
   1839 
   1840     if (!ttiscontinuation(cont)) {
   1841         unmark_list(K, root);
   1842         klispE_throw_simple(K, "Bad type on first element (expected " 
   1843                             "continuation)");				        
   1844         return KINERT;
   1845     } else if (!singly_wrapped(app)) { 
   1846         unmark_list(K, root);
   1847         klispE_throw_simple(K, "Bad type on second element (expected " 
   1848                             "singly wrapped applicative)");				        
   1849         return KINERT; 
   1850     }
   1851 
   1852     /* save the operative directly, don't waste space/time
   1853        with a list, use just a pair */
   1854     return kcons(K, cont, kunwrap(app)); 
   1855 }
   1856 
   1857 /* the guards are probably generated on the spot so we don't check
   1858    for immutability and copy it anyways */
   1859 /* GC: Assumes obj is rooted */
   1860 TValue check_copy_guards(klisp_State *K, char *name, TValue obj)
   1861 {
   1862     if (ttisnil(obj)) {
   1863         return obj;
   1864     } else {
   1865         TValue copy = kcons(K, KNIL, KNIL);
   1866         krooted_vars_push(K, &copy);
   1867         TValue last_pair = copy;
   1868         TValue tail = obj;
   1869     
   1870         while(ttispair(tail) && !kis_marked(tail)) {
   1871             /* this will clear the marks and throw an error if the structure
   1872                is incorrect */
   1873             TValue entry = check_copy_single_entry(K, name, kcar(tail), obj);
   1874             krooted_tvs_push(K, entry);
   1875             TValue new_pair = kcons(K, entry, KNIL);
   1876             krooted_tvs_pop(K);
   1877             kmark(tail);
   1878             kset_cdr(last_pair, new_pair);
   1879             last_pair = new_pair;
   1880             tail = kcdr(tail);
   1881         }
   1882 
   1883         /* dont close the cycle (if there is one) */
   1884         unmark_list(K, obj);
   1885         if (!ttispair(tail) && !ttisnil(tail)) {
   1886             klispE_throw_simple(K, "expected list"); 
   1887             return KINERT;
   1888         } 
   1889         krooted_vars_pop(K);
   1890         return kcdr(copy);
   1891     }
   1892 }
   1893 
   1894 void guard_dynamic_extent(klisp_State *K)
   1895 {
   1896     TValue *xparams = K->next_xparams;
   1897     TValue ptree = K->next_value;
   1898     TValue denv = K->next_env;
   1899     klisp_assert(ttisenvironment(K->next_env));
   1900     UNUSED(xparams);
   1901 
   1902     bind_3tp(K, ptree, "any", anytype, entry_guards,
   1903              "combiner", ttiscombiner, comb,
   1904              "any", anytype, exit_guards);
   1905 
   1906     entry_guards = check_copy_guards(K, "guard-dynamic-extent: entry guards", 
   1907                                      entry_guards);
   1908     krooted_tvs_push(K, entry_guards);
   1909     exit_guards = check_copy_guards(K, "guard-dynamic-extent: exit guards", 
   1910                                     exit_guards);
   1911     krooted_tvs_push(K, exit_guards);
   1912     /* GC: root continuations */
   1913     /* The current continuation is guarded */
   1914     TValue outer_cont = kmake_continuation(K, kget_cc(K), do_pass_value, 
   1915                                            2, entry_guards, denv);
   1916     kset_outer_cont(outer_cont);
   1917     kset_cc(K, outer_cont); /* this implicitly roots outer_cont */
   1918 
   1919     TValue inner_cont = kmake_continuation(K, outer_cont, do_pass_value, 2, 
   1920                                            exit_guards, denv);
   1921     kset_inner_cont(inner_cont);
   1922 
   1923     /* call combiner with no operands in the dynamic extent of inner,
   1924        with the dynamic env of this call */
   1925     kset_cc(K, inner_cont); /* this implicitly roots inner_cont */
   1926     TValue expr = kcons(K, comb, KNIL);
   1927 
   1928     krooted_tvs_pop(K);
   1929     krooted_tvs_pop(K);
   1930 
   1931     ktail_eval(K, expr, denv);
   1932 }
   1933 
   1934 
   1935 void do_int_mark_error(klisp_State *K)
   1936 {
   1937     TValue *xparams = K->next_xparams;
   1938     TValue ptree = K->next_value;
   1939     TValue denv = K->next_env;
   1940     klisp_assert(ttisenvironment(K->next_env));
   1941     /*
   1942     ** xparams[0]: errorp pointer
   1943     */
   1944     UNUSED(denv);
   1945     bool *errorp = (bool *) pvalue(xparams[0]);
   1946     *errorp = true;
   1947     /* ptree is (object divert) */
   1948     TValue error_obj = kcar(ptree);
   1949     /* pass the error along after setting the flag */
   1950     kapply_cc(K, error_obj);
   1951 }
   1952 
   1953 void do_int_mark_root(klisp_State *K)
   1954 {
   1955     TValue *xparams = K->next_xparams;
   1956     TValue obj = K->next_value;
   1957     klisp_assert(ttisnil(K->next_env));
   1958     /*
   1959     ** xparams[0]: rootp pointer
   1960     */
   1961     UNUSED(obj); /* ignore obj */
   1962     bool *rootp = (bool *) pvalue(xparams[0]);
   1963     *rootp = false; /* mark that we didn't explicitly call the root cont */
   1964     /* pass #INERT to the root continuation */
   1965     kapply_cc(K, KINERT);
   1966 }