/* * Copyright © 2016 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include "ao_lisp.h" enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; ao_lisp_poly ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) { ao_lisp_poly ret = AO_LISP_NIL; while (cons) { ao_lisp_poly car = cons->car; uint8_t rt = ao_lisp_poly_type(ret); uint8_t ct = ao_lisp_poly_type(car); cons = cons->cdr; if (rt == AO_LISP_NIL) ret = car; else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { int r = ao_lisp_poly_int(ret); int c = ao_lisp_poly_int(car); switch(op) { case math_plus: r += c; break; case math_minus: r -= c; break; case math_times: r *= c; break; case math_divide: if (c == 0) return AO_LISP_NIL; r /= c; break; case math_mod: if (c == 0) return AO_LISP_NIL; r %= c; break; } ret = ao_lisp_int_poly(r); } else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), ao_lisp_poly_string(car))); else { /* XXX exception */ return AO_LISP_NIL; } } return ret; } ao_lisp_poly ao_lisp_plus(struct ao_lisp_cons *cons) { return ao_lisp_math(cons, math_plus); } ao_lisp_poly ao_lisp_minus(struct ao_lisp_cons *cons) { return ao_lisp_math(cons, math_minus); } ao_lisp_poly ao_lisp_times(struct ao_lisp_cons *cons) { return ao_lisp_math(cons, math_times); } ao_lisp_poly ao_lisp_divide(struct ao_lisp_cons *cons) { return ao_lisp_math(cons, math_divide); } ao_lisp_poly ao_lisp_mod(struct ao_lisp_cons *cons) { return ao_lisp_math(cons, math_mod); } static const struct ao_lisp_builtin builtin_plus = { .type = AO_LISP_BUILTIN, .func = ao_lisp_plus, .name = "+" }; static const struct ao_lisp_atom atom_plus = { .type = AO_LISP_ATOM, .val = AO_LISP_OTHER_POLY(&builtin_plus), .next = AO_LISP_ATOM_CONST, .name = "plus" }; /* static const struct ao_lisp_builtin builtin_minus = { .type = AO_LISP_BUILTIN, .func = ao_lisp_minus }; static const struct ao_lisp_builtin builtin_times = { .type = AO_LISP_BUILTIN, .func = ao_lisp_times }; */ const struct ao_lisp_atom const *ao_lisp_builtins[] = { &atom_plus, 0 };