#include "ao_lisp.h"
#include <limits.h>
+#include <math.h>
static int
builtin_size(void *addr)
while (cons && argc <= max) {
argc++;
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
if (argc < min || argc > max)
return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name);
while (argc--) {
if (!cons)
return AO_LISP_NIL;
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
return cons->car;
}
ao_poly
ao_lisp_do_last(struct ao_lisp_cons *cons)
{
- ao_poly l;
+ struct ao_lisp_cons *list;
if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1))
return AO_LISP_NIL;
if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1))
return AO_LISP_NIL;
- l = ao_lisp_arg(cons, 0);
- while (l) {
- struct ao_lisp_cons *list = ao_lisp_poly_cons(l);
+ for (list = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
+ list;
+ list = ao_lisp_cons_cdr(list))
+ {
if (!list->cdr)
return list->car;
- l = list->cdr;
}
return AO_LISP_NIL;
}
while (cons) {
val = cons->car;
ao_lisp_poly_write(val);
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
if (cons)
printf(" ");
}
while (cons) {
val = cons->car;
ao_lisp_poly_display(val);
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
return _ao_lisp_bool_true;
}
ao_poly
-ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
+ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)
{
- struct ao_lisp_cons *orig_cons = cons;
+ struct ao_lisp_cons *cons = cons;
ao_poly ret = AO_LISP_NIL;
- while (cons) {
+ for (cons = orig_cons; cons; cons = ao_lisp_cons_cdr(cons)) {
ao_poly car = cons->car;
- ao_poly cdr;
uint8_t rt = ao_lisp_poly_type(ret);
uint8_t ct = ao_lisp_poly_type(car);
if (cons == orig_cons) {
ret = car;
- if (cons->cdr == AO_LISP_NIL && ct == AO_LISP_INT) {
+ if (cons->cdr == AO_LISP_NIL) {
switch (op) {
case builtin_minus:
- ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
+ if (ao_lisp_integer_typep(ct))
+ ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
+ else if (ct == AO_LISP_FLOAT)
+ ret = ao_lisp_float_get(-ao_lisp_poly_number(ret));
break;
case builtin_divide:
- switch (ao_lisp_poly_integer(ret)) {
- case 0:
- return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
- case 1:
- break;
- default:
- ret = ao_lisp_int_poly(0);
- break;
+ if (ao_lisp_integer_typep(ct) && ao_lisp_poly_integer(ret) == 1)
+ ;
+ else if (ao_lisp_number_typep(ct)) {
+ float v = ao_lisp_poly_number(ret);
+ ret = ao_lisp_float_get(1/v);
}
break;
default:
r *= c;
break;
case builtin_divide:
+ if (c != 0 && (r % c) == 0)
+ r /= c;
+ else {
+ ret = ao_lisp_float_get((float) r / (float) c);
+ continue;
+ }
+ break;
+ case builtin_quotient:
+ if (c == 0)
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
+ if (r % c != 0 && (c < 0) != (r < 0))
+ r = r / c - 1;
+ else
+ r = r / c;
+ break;
+ case builtin_remainder:
if (c == 0)
- return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
+ r %= c;
+ break;
+ case builtin_modulo:
+ if (c == 0)
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
+ r %= c;
+ if ((r < 0) != (c < 0))
+ r += c;
+ break;
+ default:
+ break;
+ }
+ ret = ao_lisp_integer_poly(r);
+ } else if (ao_lisp_number_typep(rt) && ao_lisp_number_typep(ct)) {
+ float r = ao_lisp_poly_number(ret);
+ float c = ao_lisp_poly_number(car);
+ switch(op) {
+ case builtin_plus:
+ r += c;
+ break;
+ case builtin_minus:
+ r -= c;
+ break;
+ case builtin_times:
+ r *= c;
+ break;
+ case builtin_divide:
r /= c;
break;
+#if 0
case builtin_quotient:
if (c == 0)
return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
if ((r < 0) != (c < 0))
r += c;
break;
+#endif
default:
break;
}
- ret = ao_lisp_integer_poly(r);
+ ret = ao_lisp_float_get(r);
}
else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
ao_lisp_poly_string(car)));
else
return ao_lisp_error(AO_LISP_INVALID, "invalid args");
-
- cdr = cons->cdr;
- if (cdr != AO_LISP_NIL && ao_lisp_poly_type(cdr) != AO_LISP_CONS)
- return ao_lisp_error(AO_LISP_INVALID, "improper list");
- cons = ao_lisp_poly_cons(cdr);
}
return ret;
}
return _ao_lisp_bool_true;
left = cons->car;
- cons = ao_lisp_poly_cons(cons->cdr);
- while (cons) {
+ for (cons = ao_lisp_cons_cdr(cons); cons; cons = ao_lisp_cons_cdr(cons)) {
ao_poly right = cons->car;
if (op == builtin_equal) {
}
}
left = right;
- cons = ao_lisp_poly_cons(cons->cdr);
}
return _ao_lisp_bool_true;
}
return ao_lisp_do_typep(AO_LISP_CONS, cons);
}
+ao_poly
+ao_lisp_do_integerp(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
+ case AO_LISP_INT:
+ case AO_LISP_BIGINT:
+ return _ao_lisp_bool_true;
+ default:
+ return _ao_lisp_bool_false;
+ }
+}
+
ao_poly
ao_lisp_do_numberp(struct ao_lisp_cons *cons)
{
switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
case AO_LISP_INT:
case AO_LISP_BIGINT:
+ case AO_LISP_FLOAT:
return _ao_lisp_bool_true;
default:
return _ao_lisp_bool_false;