commit 6333adde499e501eb7d18bcb720420122b4aa261
parent d19e10b9bc8e5529d8a84587955828162e3c0cec
Author: Andres Navarro <canavarro82@gmail.com>
Date: Tue, 22 Mar 2011 17:20:31 -0300
Modified - to allow a list of arguments (of length at least 2).
Diffstat:
M | src/kgnumbers.c | | | 140 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
1 file changed, 118 insertions(+), 22 deletions(-)
diff --git a/src/kgnumbers.c b/src/kgnumbers.c
@@ -115,7 +115,6 @@ bool knum_gep(TValue n1, TValue n2)
}
/* 12.5.4 + */
-/* TEMP: for now only accept two arguments */
void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
{
UNUSED(denv);
@@ -256,40 +255,137 @@ void ktimes(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
}
/* 12.5.6 - */
-/* TEMP: for now only accept two arguments */
void kminus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv)
{
UNUSED(denv);
UNUSED(xparams);
+ /* cycles are allowed, loop counting pairs */
+ int32_t cpairs;
+
+ /* - in kernel (and unlike in scheme) requires at least 2 arguments */
+ if (!ttispair(ptree) || !ttispair(kcdr(ptree))) {
+ klispE_throw(K, "-: at least two values are required");
+ return;
+ } else if (!knumberp(kcar(ptree))) {
+ klispE_throw(K, "-: bad type on first argument (expected number)");
+ return;
+ }
+ TValue first_val = kcar(ptree);
- bind_2tp(K, "-", ptree, "number", knumberp, n1, "number", knumberp, n2);
+ int32_t pairs = check_typed_list(K, "-", "number", knumberp, true,
+ kcdr(ptree), &cpairs);
+ int32_t apairs = pairs - cpairs;
- switch(max_ttype(n1, n2)) {
- case K_TFIXINT: {
- int32_t i1 = ivalue(n1);
- int32_t i2 = ivalue(n2);
- /* TODO: check for overflow and create bigint */
- kapply_cc(K, i2tv(i1-i2));
- }
- case K_TEINF: {
- if (ttiseinf(n1) && ttiseinf(n2)) {
- if (tv_equal(n1, n2)) {
- /* TEMP: we don't have reals with no prim value yet */
- /* also no strict arithmetic variable for now */
+ TValue res;
+
+ /* first the acyclic part */
+ TValue ares = i2tv(0);
+ int32_t accum = 0;
+ bool seen_infinity = false;
+ TValue tail = kcdr(ptree);
+
+ while(apairs--) {
+ TValue first = kcar(tail);
+ tail = kcdr(tail);
+
+ if (ttiseinf(first)) {
+ if (seen_infinity && !tv_equal(first, ares)) {
+ /* report: #e+infinity + #e-infinity has no primary value */
klispE_throw(K, "-: result has no primary value");
return;
} else {
- kapply_cc(K, n1);
+ /* record which infinity we have seen */
+ seen_infinity = true;
+ ares = first;
}
- } else {
- kapply_cc(K, ttiseinf(n1)? n1 : kneg_inf(n2));
+ } else if (!seen_infinity) {
+ accum += ivalue(first);
}
}
- default:
- /* shouldn't happen */
- assert(0);
- return;
+
+ if (!seen_infinity)
+ ares = i2tv(accum);
+
+ /* next the acyclic part */
+ TValue cres = i2tv(0);
+
+ if (cpairs == 0) {
+ res = ares;
+ } else {
+ bool all_zero = true;
+
+ seen_infinity = false;
+ accum = 0;
+
+ while(cpairs--) {
+ TValue first = kcar(tail);
+ tail = kcdr(tail);
+
+ all_zero = all_zero && kfast_zerop(first);
+
+ if (ttiseinf(first)) {
+ if (seen_infinity && !tv_equal(first, cres)) {
+ /* report: #e+infinity + #e-infinity has no primary value */
+ klispE_throw(K, "-: result has no primary value");
+ return;
+ } else {
+ /* record which infinity we have seen */
+ seen_infinity = true;
+ cres = first;
+ }
+ } else if (!seen_infinity) {
+ accum += ivalue(first);
+ }
+ }
+
+ if (!seen_infinity) {
+ if (accum == 0) {
+ if (!all_zero) {
+ /* report */
+ klispE_throw(K, "-: result has no primary value");
+ return;
+ } else {
+ cres = i2tv(accum);
+ }
+ } else {
+ cres = accum < 0? KEMINF : KEPINF;
+ }
+ }
+
+ if (ttiseinf(ares)) {
+ if (!ttiseinf(cres) || tv_equal(ares, cres))
+ res = ares;
+ else {
+ /* report */
+ klispE_throw(K, "-: result has no primary value");
+ return;
+ }
+ } else {
+ if (ttiseinf(cres))
+ res = cres;
+ else
+ res = i2tv(ivalue(ares) + ivalue(cres));
+ }
+ }
+
+ /* now substract the sum of all the elements in the list to the first
+ value */
+ if (ttiseinf(first_val)) {
+ if (!ttiseinf(res) || !tv_equal(first_val, res)) {
+ res = first_val;
+ } else {
+ /* report */
+ klispE_throw(K, "-: result has no primary value");
+ return;
+ }
+ } else {
+ if (ttiseinf(res))
+ res = kneg_inf(res);
+ else
+ res = i2tv(ivalue(first_val) - ivalue(res));
}
+
+ kapply_cc(K, res);
}
/* 12.5.7 zero? */