klisp

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

commit ef0e7549d726b614572214119efa7d03dd86324a
parent be53719119d2892866a395a95c25ce973953ebfe
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sun, 15 May 2011 10:30:09 -0300

Added support for inexact reals to '-'. Bugfix: in '+' when cycle sums zero, don't return #real directly, the stack still isn't popped (and the value could be undefined).

Diffstat:
Msrc/kgnumbers.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 16 deletions(-)

diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -376,6 +376,9 @@ TValue knum_times(klisp_State *K, TValue n1, TValue n2) /* GC: assumes n1 & n2 rooted */ TValue knum_minus(klisp_State *K, TValue n1, TValue n2) { + kensure_same_exactness(K, n1, n2); + TValue res; /* used for results with no primary value */ + switch(max_ttype(n1, n2)) { case K_TFIXINT: { int64_t res = (int64_t) ivalue(n1) - (int64_t) ivalue(n2); @@ -394,20 +397,57 @@ TValue knum_minus(klisp_State *K, TValue n1, TValue n2) kensure_bigrat(n2); return kbigrat_minus(K, n1, n2); } + case K_TDOUBLE: { + /* both are double */ + double res = dvalue(n1) - dvalue(n2); + /* check under & overflow */ + if (kcurr_strict_arithp(K)) { + if (res == 0 && dvalue(n1) != dvalue(n2)) { + klispE_throw_simple(K, "underflow"); + return KINERT; + } else if (isinf(res)) { + klispE_throw_simple(K, "overflow"); + return KINERT; + } + } + /* correctly encapsulate infinities and -0.0 */ + return ktag_double(res); + } case K_TEINF: if (!ttiseinf(n1)) return kneg_inf(n2); else if (!ttiseinf(n2)) return n1; if (tv_equal(n1, n2)) { - klispE_throw_simple(K, "no primary value"); - return KINERT; + /* no primary value; handle error at the end of function */ + res = KRWNPV; + break; } else return n1; + case K_TIINF: + if (!ttisiinf(n1)) + return kneg_inf(n2); + else if (!ttisiinf(n2)) + return n1; + if (tv_equal(n1, n2)) { + /* no primary value; handle error at the end of function */ + res = KRWNPV; + break; + } else + return n1; + case K_TRWNPV: /* no primary value */ + res = KRWNPV; + break; + case K_TUNDEFINED: /* undefined */ + res = KUNDEF; + break; default: klispE_throw_simple(K, "unsupported type"); return KINERT; } + + /* check for no primary value and value of strict arith */ + arith_return(K, res); } /* May throw an error */ @@ -717,10 +757,8 @@ void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) if (ttisnwnpv(cres)) /* #undefined or #real */ ; /* do nothing, check is made later */ else if (kfast_zerop(cres)) { - if (!all_zero) { + if (!all_zero) cres = KRWNPV; /* check is made later */ - return; - } } else if (all_exact) cres = knegativep(K, cres)? KEMINF : KEPINF; else @@ -848,35 +886,43 @@ void kminus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* next the cyclic part */ - TValue cres = i2tv(0); + TValue cres = i2tv(0); /* push it only if needed */ - if (cpairs == 0) { - /* speed things up if there is no cycle */ + if (cpairs == 0 && !ttisnwnpv(ares)) { /* #undefined or #real */ + /* speed things up if there is no cycle and + no possible error (on no primary value) */ res = ares; krooted_vars_pop(K); } else { bool all_zero = true; + bool all_exact = true; krooted_vars_push(K, &cres); while(cpairs--) { TValue first = kcar(tail); tail = kcdr(tail); + all_zero = all_zero && kfast_zerop(first); + all_exact = all_exact && ttisexact(first); + cres = knum_plus(K, cres, first); } - if (kfast_zerop(cres)) { - if (!all_zero) { - /* report */ - klispE_throw_simple(K, "result has no primary value"); - return; - } - } else + if (ttisnwnpv(cres)) /* #undefined or #real */ + ; /* do nothing, check is made later */ + else if (kfast_zerop(cres)) { + if (!all_zero) + cres = KRWNPV; /* check is made later */ + } else if (all_exact) cres = knegativep(K, cres)? KEMINF : KEPINF; + else + cres = knegativep(K, cres)? KIMINF : KIPINF; + + /* here if any of the two has no primary an error is signaled */ res = knum_plus(K, ares, cres); krooted_vars_pop(K); krooted_vars_pop(K); - } + } /* now substract the sum of all the elements in the list to the first value */ krooted_tvs_push(K, res);