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 }