klisp

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

kgbooleans.c (6514B)


      1 /*
      2 ** kgbooleans.h
      3 ** Boolean features for the ground environment
      4 ** See Copyright Notice in klisp.h
      5 */
      6 
      7 #include <assert.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <stdbool.h>
     11 #include <stdint.h>
     12 
     13 #include "kobject.h"
     14 #include "klisp.h"
     15 #include "kstate.h"
     16 #include "kpair.h"
     17 #include "ksymbol.h"
     18 #include "kcontinuation.h"
     19 #include "kerror.h"
     20 
     21 #include "kghelpers.h"
     22 #include "kgbooleans.h"
     23 
     24 /* Continuations */
     25 void do_Sandp_Sorp(klisp_State *K);
     26 
     27 /* 4.1.1 boolean? */
     28 /* uses typep */
     29 
     30 /* 6.1.1 not? */
     31 void notp(klisp_State *K)
     32 {
     33     TValue *xparams = K->next_xparams;
     34     TValue ptree = K->next_value;
     35     TValue denv = K->next_env;
     36     klisp_assert(ttisenvironment(K->next_env));
     37     UNUSED(xparams);
     38     UNUSED(denv);
     39 
     40     bind_1tp(K, ptree, "boolean", ttisboolean, tv_b);
     41 
     42     TValue res = kis_true(tv_b)? KFALSE : KTRUE;
     43     kapply_cc(K, res);
     44 }
     45 
     46 /* 6.1.2 and? */
     47 void andp(klisp_State *K)
     48 {
     49     TValue *xparams = K->next_xparams;
     50     TValue ptree = K->next_value;
     51     TValue denv = K->next_env;
     52     klisp_assert(ttisenvironment(K->next_env));
     53     UNUSED(xparams);
     54     UNUSED(denv);
     55     int32_t pairs;
     56     /* don't care about cycle pairs */
     57     check_typed_list(K, kbooleanp, true, ptree, &pairs, NULL);
     58     TValue res = KTRUE;
     59     TValue tail = ptree;
     60     while(pairs--) {
     61         TValue first = kcar(tail);
     62         tail = kcdr(tail);
     63         if (kis_false(first)) {
     64             res = KFALSE;
     65             break;
     66         }
     67     }
     68     kapply_cc(K, res);
     69 }
     70 
     71 /* 6.1.3 or? */
     72 void orp(klisp_State *K)
     73 {
     74     TValue *xparams = K->next_xparams;
     75     TValue ptree = K->next_value;
     76     TValue denv = K->next_env;
     77     klisp_assert(ttisenvironment(K->next_env));
     78     UNUSED(xparams);
     79     UNUSED(denv);
     80     int32_t pairs; 
     81     /* don't care about cycle pairs */
     82     check_typed_list(K, kbooleanp,true, ptree, &pairs, NULL);
     83     TValue res = KFALSE;
     84     TValue tail = ptree;
     85     while(pairs--) {
     86         TValue first = kcar(tail);
     87         tail = kcdr(tail);
     88         if (kis_true(first)) {
     89             res = KTRUE;
     90             break;
     91         }
     92     }
     93     kapply_cc(K, res);
     94 }
     95 
     96 /* Helpers for $and? & $or? */
     97 
     98 /*
     99 ** operands is a list, the other cases are handled before calling 
    100 ** term-bool is the termination boolean, i.e. the boolean that terminates 
    101 ** evaluation early and becomes the result of $and?/$or?
    102 ** it is #t for $or? and #f for $and?
    103 ** both $and? & $or? have to allow boolean checking while performing a tail 
    104 ** call that is acomplished by checking if the current continuation will 
    105 ** perform a boolean check, and in that case, no continuation is created
    106 */
    107 void do_Sandp_Sorp(klisp_State *K)
    108 {
    109     TValue *xparams = K->next_xparams;
    110     TValue obj = K->next_value;
    111     klisp_assert(ttisnil(K->next_env));
    112     /*
    113     ** xparams[0]: symbol name
    114     ** xparams[1]: termination boolean
    115     ** xparams[2]: remaining operands
    116     ** xparams[3]: denv
    117     */
    118     TValue sname = xparams[0];
    119     TValue term_bool = xparams[1];
    120     TValue ls = xparams[2];
    121     TValue denv = xparams[3];
    122 
    123     if (!ttisboolean(obj)) {
    124         klispE_throw_simple_with_irritants(K, "expected boolean", 1, 
    125                                            obj);
    126         return;
    127     } else if (ttisnil(ls) || tv_equal(obj, term_bool)) {
    128         /* in both cases the value to be returned is obj:
    129            if there are no more operands it is obvious otherwise, if
    130            the termination bool is found:
    131            $and? returns #f when it finds #f and $or? returns #t when it 
    132            finds #t */
    133         kapply_cc(K, obj);
    134     } else {
    135         TValue first = kcar(ls);
    136         TValue tail = kcdr(ls);
    137         /* This is the important part of tail context + bool check */
    138         if (!ttisnil(tail) || !kis_bool_check_cont(kget_cc(K))) {
    139             TValue new_cont = 
    140                 kmake_continuation(K, kget_cc(K), do_Sandp_Sorp, 
    141                                    4, sname, term_bool, tail, denv);
    142             /* 
    143             ** Mark as a bool checking cont this is needed in the last operand
    144             ** to allow both tail recursive behaviour and boolean checking.
    145             ** While it is not necessary if this is not the last operand it
    146             ** avoids a continuation in the last evaluation of the inner form 
    147             ** in the common use of 
    148             ** ($and?/$or? ($or?/$and? ...) ...)
    149             */
    150             kset_bool_check_cont(new_cont);
    151             kset_cc(K, new_cont);
    152 #if KTRACK_SI
    153             /* put the source info of the list including the element
    154                that we are about to evaluate */
    155             kset_source_info(K, new_cont, ktry_get_si(K, ls));
    156 #endif
    157         }
    158         ktail_eval(K, first, denv);
    159     }
    160 }
    161 
    162 void Sandp_Sorp(klisp_State *K)
    163 {
    164     TValue *xparams = K->next_xparams;
    165     TValue ptree = K->next_value;
    166     TValue denv = K->next_env;
    167     klisp_assert(ttisenvironment(K->next_env));
    168     /*
    169     ** xparams[0]: symbol name
    170     ** xparams[1]: termination boolean
    171     */
    172     TValue sname = xparams[0];
    173     TValue term_bool = xparams[1];
    174     
    175     TValue ls = check_copy_list(K, ptree, false, NULL, NULL);
    176     /* This will work even if ls is empty */
    177     krooted_tvs_push(K, ls);
    178     TValue new_cont = kmake_continuation(K, kget_cc(K), do_Sandp_Sorp, 4, 
    179                                          sname, term_bool, ls, denv);
    180     krooted_tvs_pop(K);
    181     /* there's no need to mark it as bool checking, no evaluation
    182        is done in the dynamic extent of this cont, no need for 
    183        source info either */
    184     kset_cc(K, new_cont);
    185     kapply_cc(K, knegp(term_bool)); /* pass dummy value to start */
    186 }
    187 
    188 /* 6.1.4 $and? */
    189 /* uses Sandp_Sorp */
    190 
    191 /* 6.1.5 $or? */
    192 /* uses Sandp_Sorp */
    193 
    194 /* init ground */
    195 void kinit_booleans_ground_env(klisp_State *K)
    196 {
    197     TValue ground_env = G(K)->ground_env;
    198     TValue symbol, value;
    199 
    200     /* 4.1.1 boolean? */
    201     add_applicative(K, ground_env, "boolean?", typep, 2, symbol, 
    202                     i2tv(K_TBOOLEAN));
    203     /* 6.1.1 not? */
    204     add_applicative(K, ground_env, "not?", notp, 0);
    205     /* 6.1.2 and? */
    206     add_applicative(K, ground_env, "and?", andp, 0);
    207     /* 6.1.3 or? */
    208     add_applicative(K, ground_env, "or?", orp, 0);
    209     /* 6.1.4 $and? */
    210     add_operative(K, ground_env, "$and?", Sandp_Sorp, 2, symbol, KFALSE);
    211     /* 6.1.5 $or? */
    212     add_operative(K, ground_env, "$or?", Sandp_Sorp, 2, symbol, KTRUE);
    213 }
    214 
    215 /* XXX lock? */
    216 /* init continuation names */
    217 void kinit_booleans_cont_names(klisp_State *K)
    218 {
    219     Table *t = tv2table(G(K)->cont_name_table);
    220     add_cont_name(K, t, do_Sandp_Sorp, "eval-booleans");
    221 }