2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
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.
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.
18 builtin_size(void *addr)
21 return sizeof (struct ao_lisp_builtin);
25 builtin_mark(void *addr)
31 builtin_move(void *addr)
36 const struct ao_lisp_type ao_lisp_builtin_type = {
43 ao_lisp_builtin_print(ao_poly b)
50 ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max)
54 while (cons && argc <= max) {
56 cons = ao_lisp_poly_cons(cons->cdr);
58 if (argc < min || argc > max)
59 return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name);
60 return _ao_lisp_atom_t;
64 ao_lisp_arg(struct ao_lisp_cons *cons, int argc)
69 cons = ao_lisp_poly_cons(cons->cdr);
75 ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok)
77 ao_poly car = ao_lisp_arg(cons, argc);
79 if ((!car && !nil_ok) || ao_lisp_poly_type(car) != type)
80 return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", ao_lisp_poly_atom(name)->name, argc);
81 return _ao_lisp_atom_t;
84 enum math_op { math_plus, math_minus, math_times, math_divide, math_mod };
87 ao_lisp_car(struct ao_lisp_cons *cons)
89 if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1))
91 if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0))
93 return ao_lisp_poly_cons(cons->car)->car;
97 ao_lisp_cdr(struct ao_lisp_cons *cons)
99 if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1))
101 if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0))
103 return ao_lisp_poly_cons(cons->car)->cdr;
107 ao_lisp_cons(struct ao_lisp_cons *cons)
110 if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2))
112 if (!ao_lisp_check_argt(_ao_lisp_atom_cons, cons, 1, AO_LISP_CONS, 1))
114 car = ao_lisp_arg(cons, 0);
115 cdr = ao_lisp_arg(cons, 1);
116 return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr)));
120 ao_lisp_quote(struct ao_lisp_cons *cons)
122 if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1))
124 return ao_lisp_arg(cons, 0);
128 ao_lisp_set(struct ao_lisp_cons *cons)
130 if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2))
132 if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0))
135 return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1));
139 ao_lisp_setq(struct ao_lisp_cons *cons)
141 struct ao_lisp_cons *expand = 0;
142 if (!ao_lisp_check_argc(_ao_lisp_atom_setq, cons, 2, 2))
144 expand = ao_lisp_cons_cons(_ao_lisp_atom_set,
145 ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(_ao_lisp_atom_quote,
146 ao_lisp_cons_cons(cons->car, NULL))),
147 ao_lisp_poly_cons(cons->cdr)));
148 return ao_lisp_cons_poly(expand);
152 ao_lisp_cond(struct ao_lisp_cons *cons)
155 struct ao_lisp_cons *arg;
158 for (arg = cons, argc = 0; arg; arg = ao_lisp_poly_cons(arg->cdr), argc++) {
159 if (ao_lisp_poly_type(arg->car) != AO_LISP_CONS)
160 return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d",
161 ao_lisp_poly_atom(_ao_lisp_atom_cond)->name, argc);
163 ao_lisp_set_cond(cons);
168 ao_lisp_print(struct ao_lisp_cons *cons)
170 ao_poly val = AO_LISP_NIL;
173 ao_lisp_poly_print(val);
174 cons = ao_lisp_poly_cons(cons->cdr);
182 ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op)
184 ao_poly ret = AO_LISP_NIL;
187 ao_poly car = cons->car;
188 uint8_t rt = ao_lisp_poly_type(ret);
189 uint8_t ct = ao_lisp_poly_type(car);
191 cons = ao_lisp_poly_cons(cons->cdr);
193 if (rt == AO_LISP_NIL)
196 else if (rt == AO_LISP_INT && ct == AO_LISP_INT) {
197 int r = ao_lisp_poly_int(ret);
198 int c = ao_lisp_poly_int(car);
212 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
217 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero");
221 ret = ao_lisp_int_poly(r);
224 else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus)
225 ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
226 ao_lisp_poly_string(car)));
228 return ao_lisp_error(AO_LISP_INVALID, "invalid args");
234 ao_lisp_plus(struct ao_lisp_cons *cons)
236 return ao_lisp_math(cons, math_plus);
240 ao_lisp_minus(struct ao_lisp_cons *cons)
242 return ao_lisp_math(cons, math_minus);
246 ao_lisp_times(struct ao_lisp_cons *cons)
248 return ao_lisp_math(cons, math_times);
252 ao_lisp_divide(struct ao_lisp_cons *cons)
254 return ao_lisp_math(cons, math_divide);
258 ao_lisp_mod(struct ao_lisp_cons *cons)
260 return ao_lisp_math(cons, math_mod);
263 ao_lisp_func_t ao_lisp_builtins[] = {
264 [builtin_car] = ao_lisp_car,
265 [builtin_cdr] = ao_lisp_cdr,
266 [builtin_cons] = ao_lisp_cons,
267 [builtin_quote] = ao_lisp_quote,
268 [builtin_set] = ao_lisp_set,
269 [builtin_setq] = ao_lisp_setq,
270 [builtin_cond] = ao_lisp_cond,
271 [builtin_print] = ao_lisp_print,
272 [builtin_plus] = ao_lisp_plus,
273 [builtin_minus] = ao_lisp_minus,
274 [builtin_times] = ao_lisp_times,
275 [builtin_divide] = ao_lisp_divide,
276 [builtin_mod] = ao_lisp_mod