1855d945d6a920abbe35fabc0de74ddd17a5747d
[fw/altos] / src / lisp / ao_lisp_poly.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_lisp.h"
16
17 enum math_op { math_plus, math_minus, math_times, math_divide, math_mod };
18
19 ao_lisp_poly
20 ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op)
21 {
22         ao_lisp_poly    ret = AO_LISP_NIL;
23
24         while (cons) {
25                 ao_lisp_poly    car = cons->car;
26                 uint8_t         rt = ao_lisp_poly_type(ret);
27                 uint8_t         ct = ao_lisp_poly_type(car);
28
29                 cons = cons->cdr;
30
31                 if (rt == AO_LISP_NIL)
32                         ret = car;
33
34                 else if (rt == AO_LISP_INT && ct == AO_LISP_INT) {
35                         int     r = ao_lisp_poly_int(ret);
36                         int     c = ao_lisp_poly_int(car);
37
38                         switch(op) {
39                         case math_plus:
40                                 r += c;
41                                 break;
42                         case math_minus:
43                                 r -= c;
44                                 break;
45                         case math_times:
46                                 r *= c;
47                                 break;
48                         case math_divide:
49                                 if (c == 0)
50                                         return AO_LISP_NIL;
51                                 r /= c;
52                                 break;
53                         case math_mod:
54                                 if (c == 0)
55                                         return AO_LISP_NIL;
56                                 r %= c;
57                                 break;
58                         }
59                         ret = ao_lisp_int_poly(r);
60                 }
61
62                 else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus)
63                         ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
64                                                                      ao_lisp_poly_string(car)));
65                 else {
66                         /* XXX exception */
67                         return AO_LISP_NIL;
68                 }
69         }
70         return ret;
71 }
72
73 ao_lisp_poly
74 ao_lisp_plus(struct ao_lisp_cons *cons)
75 {
76         return ao_lisp_math(cons, math_plus);
77 }
78
79 ao_lisp_poly
80 ao_lisp_minus(struct ao_lisp_cons *cons)
81 {
82         return ao_lisp_math(cons, math_minus);
83 }
84
85 ao_lisp_poly
86 ao_lisp_times(struct ao_lisp_cons *cons)
87 {
88         return ao_lisp_math(cons, math_times);
89 }
90
91 ao_lisp_poly
92 ao_lisp_divide(struct ao_lisp_cons *cons)
93 {
94         return ao_lisp_math(cons, math_divide);
95 }
96
97 ao_lisp_poly
98 ao_lisp_mod(struct ao_lisp_cons *cons)
99 {
100         return ao_lisp_math(cons, math_mod);
101 }
102
103 static const struct ao_lisp_builtin builtin_plus = {
104         .type = AO_LISP_BUILTIN,
105         .func = ao_lisp_plus,
106         .name = "+"
107 };
108
109 static const struct ao_lisp_atom atom_plus = {
110         .type = AO_LISP_ATOM,
111         .val = AO_LISP_OTHER_POLY(&builtin_plus),
112         .next = AO_LISP_ATOM_CONST,
113         .name = "plus"
114 };
115
116 /*
117 static const struct ao_lisp_builtin builtin_minus = {
118         .type = AO_LISP_BUILTIN,
119         .func = ao_lisp_minus
120 };
121
122 static const struct ao_lisp_builtin builtin_times = {
123         .type = AO_LISP_BUILTIN,
124         .func = ao_lisp_times
125 };
126
127 */
128
129 const struct ao_lisp_atom const *ao_lisp_builtins[] = {
130         &atom_plus,
131         0
132 };