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 = {
42 #ifdef AO_LISP_MAKE_CONST
44 #define AO_LISP_BUILTIN_CASENAME
45 #include "ao_lisp_builtin.h"
47 #define _atomn(n) ao_lisp_poly_atom(_atom(n))
49 char *ao_lisp_args_name(uint8_t args) {
50 args &= AO_LISP_FUNC_MASK;
52 case AO_LISP_FUNC_LAMBDA: return _atomn(lambda)->name;
53 case AO_LISP_FUNC_LEXPR: return _atomn(lexpr)->name;
54 case AO_LISP_FUNC_NLAMBDA: return _atomn(nlambda)->name;
55 case AO_LISP_FUNC_MACRO: return _atomn(macro)->name;
56 default: return "???";
61 #define AO_LISP_BUILTIN_ARRAYNAME
62 #include "ao_lisp_builtin.h"
65 ao_lisp_builtin_name(enum ao_lisp_builtin_id b) {
66 if (b < _builtin_last)
67 return ao_lisp_poly_atom(builtin_names[b])->name;
71 static const ao_poly ao_lisp_args_atoms[] = {
72 [AO_LISP_FUNC_LAMBDA] = _ao_lisp_atom_lambda,
73 [AO_LISP_FUNC_LEXPR] = _ao_lisp_atom_lexpr,
74 [AO_LISP_FUNC_NLAMBDA] = _ao_lisp_atom_nlambda,
75 [AO_LISP_FUNC_MACRO] = _ao_lisp_atom_macro,
79 ao_lisp_args_name(uint8_t args)
81 args &= AO_LISP_FUNC_MASK;
82 if (args < sizeof ao_lisp_args_atoms / sizeof ao_lisp_args_atoms[0])
83 return ao_lisp_poly_atom(ao_lisp_args_atoms[args])->name;
89 ao_lisp_builtin_print(ao_poly b)
91 struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b);
92 printf("%s", ao_lisp_builtin_name(builtin->func));
96 ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max)
100 while (cons && argc <= max) {
102 cons = ao_lisp_poly_cons(cons->cdr);
104 if (argc < min || argc > max)
105 return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name);
106 return _ao_lisp_bool_true;
110 ao_lisp_arg(struct ao_lisp_cons *cons, int argc)
117 cons = ao_lisp_poly_cons(cons->cdr);
123 ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok)
125 ao_poly car = ao_lisp_arg(cons, argc);
127 if ((!car && !nil_ok) || ao_lisp_poly_type(car) != type)
128 return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", ao_lisp_poly_atom(name)->name, argc);
129 return _ao_lisp_bool_true;
133 ao_lisp_do_car(struct ao_lisp_cons *cons)
135 if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1))
137 if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0))
139 return ao_lisp_poly_cons(cons->car)->car;
143 ao_lisp_do_cdr(struct ao_lisp_cons *cons)
145 if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1))
147 if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0))
149 return ao_lisp_poly_cons(cons->car)->cdr;
153 ao_lisp_do_cons(struct ao_lisp_cons *cons)
156 if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2))
158 car = ao_lisp_arg(cons, 0);
159 cdr = ao_lisp_arg(cons, 1);
160 return ao_lisp__cons(car, cdr);
164 ao_lisp_do_last(struct ao_lisp_cons *cons)
167 if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1))
169 if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1))
171 l = ao_lisp_arg(cons, 0);
173 struct ao_lisp_cons *list = ao_lisp_poly_cons(l);
182 ao_lisp_do_length(struct ao_lisp_cons *cons)
184 if (!ao_lisp_check_argc(_ao_lisp_atom_length, cons, 1, 1))
186 if (!ao_lisp_check_argt(_ao_lisp_atom_length, cons, 0, AO_LISP_CONS, 1))
188 return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))));
192 ao_lisp_do_quote(struct ao_lisp_cons *cons)
194 if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1))
196 return ao_lisp_arg(cons, 0);
200 ao_lisp_do_set(struct ao_lisp_cons *cons)
202 if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2))
204 if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0))
207 return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1));
211 ao_lisp_do_setq(struct ao_lisp_cons *cons)
214 if (!ao_lisp_check_argc(_ao_lisp_atom_setq, cons, 2, 2))
217 if (ao_lisp_poly_type(name) != AO_LISP_ATOM)
218 return ao_lisp_error(AO_LISP_INVALID, "set! of non-atom");
219 if (!ao_lisp_atom_ref(ao_lisp_frame_current, name))
220 return ao_lisp_error(AO_LISP_INVALID, "atom not defined");
221 return ao_lisp__cons(_ao_lisp_atom_set,
222 ao_lisp__cons(ao_lisp__cons(_ao_lisp_atom_quote,
223 ao_lisp__cons(name, AO_LISP_NIL)),
228 ao_lisp_do_cond(struct ao_lisp_cons *cons)
230 ao_lisp_set_cond(cons);
235 ao_lisp_do_progn(struct ao_lisp_cons *cons)
237 ao_lisp_stack->state = eval_progn;
238 ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
243 ao_lisp_do_while(struct ao_lisp_cons *cons)
245 ao_lisp_stack->state = eval_while;
246 ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
251 ao_lisp_do_print(struct ao_lisp_cons *cons)
253 ao_poly val = AO_LISP_NIL;
256 ao_lisp_poly_print(val);
257 cons = ao_lisp_poly_cons(cons->cdr);
266 ao_lisp_do_patom(struct ao_lisp_cons *cons)
268 ao_poly val = AO_LISP_NIL;
271 ao_lisp_poly_patom(val);
272 cons = ao_lisp_poly_cons(cons->cdr);
278 ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
280 struct ao_lisp_cons *orig_cons = cons;
281 ao_poly ret = AO_LISP_NIL;
284 ao_poly car = cons->car;
285 uint8_t rt = ao_lisp_poly_type(ret);
286 uint8_t ct = ao_lisp_poly_type(car);
288 if (cons == orig_cons) {
290 if (cons->cdr == AO_LISP_NIL && ct == AO_LISP_INT) {
293 ret = ao_lisp_int_poly(-ao_lisp_poly_int(ret));
296 switch (ao_lisp_poly_int(ret)) {
298 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
302 ret = ao_lisp_int_poly(0);
310 } else if (rt == AO_LISP_INT && ct == AO_LISP_INT) {
311 int r = ao_lisp_poly_int(ret);
312 int c = ao_lisp_poly_int(car);
326 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
329 case builtin_quotient:
331 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
332 if (r % c != 0 && (c < 0) != (r < 0))
337 case builtin_remainder:
339 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
344 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
346 if ((r < 0) != (c < 0))
352 ret = ao_lisp_int_poly(r);
355 else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
356 ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
357 ao_lisp_poly_string(car)));
359 return ao_lisp_error(AO_LISP_INVALID, "invalid args");
361 cons = ao_lisp_poly_cons(cons->cdr);
367 ao_lisp_do_plus(struct ao_lisp_cons *cons)
369 return ao_lisp_math(cons, builtin_plus);
373 ao_lisp_do_minus(struct ao_lisp_cons *cons)
375 return ao_lisp_math(cons, builtin_minus);
379 ao_lisp_do_times(struct ao_lisp_cons *cons)
381 return ao_lisp_math(cons, builtin_times);
385 ao_lisp_do_divide(struct ao_lisp_cons *cons)
387 return ao_lisp_math(cons, builtin_divide);
391 ao_lisp_do_quotient(struct ao_lisp_cons *cons)
393 return ao_lisp_math(cons, builtin_quotient);
397 ao_lisp_do_modulo(struct ao_lisp_cons *cons)
399 return ao_lisp_math(cons, builtin_modulo);
403 ao_lisp_do_remainder(struct ao_lisp_cons *cons)
405 return ao_lisp_math(cons, builtin_remainder);
409 ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
414 return _ao_lisp_bool_true;
417 cons = ao_lisp_poly_cons(cons->cdr);
419 ao_poly right = cons->car;
421 if (op == builtin_equal) {
423 return _ao_lisp_bool_false;
425 uint8_t lt = ao_lisp_poly_type(left);
426 uint8_t rt = ao_lisp_poly_type(right);
427 if (lt == AO_LISP_INT && rt == AO_LISP_INT) {
428 int l = ao_lisp_poly_int(left);
429 int r = ao_lisp_poly_int(right);
434 return _ao_lisp_bool_false;
436 case builtin_greater:
438 return _ao_lisp_bool_false;
440 case builtin_less_equal:
442 return _ao_lisp_bool_false;
444 case builtin_greater_equal:
446 return _ao_lisp_bool_false;
451 } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) {
452 int c = strcmp(ao_lisp_poly_string(left),
453 ao_lisp_poly_string(right));
457 return _ao_lisp_bool_false;
459 case builtin_greater:
461 return _ao_lisp_bool_false;
463 case builtin_less_equal:
465 return _ao_lisp_bool_false;
467 case builtin_greater_equal:
469 return _ao_lisp_bool_false;
477 cons = ao_lisp_poly_cons(cons->cdr);
479 return _ao_lisp_bool_true;
483 ao_lisp_do_equal(struct ao_lisp_cons *cons)
485 return ao_lisp_compare(cons, builtin_equal);
489 ao_lisp_do_less(struct ao_lisp_cons *cons)
491 return ao_lisp_compare(cons, builtin_less);
495 ao_lisp_do_greater(struct ao_lisp_cons *cons)
497 return ao_lisp_compare(cons, builtin_greater);
501 ao_lisp_do_less_equal(struct ao_lisp_cons *cons)
503 return ao_lisp_compare(cons, builtin_less_equal);
507 ao_lisp_do_greater_equal(struct ao_lisp_cons *cons)
509 return ao_lisp_compare(cons, builtin_greater_equal);
513 ao_lisp_do_pack(struct ao_lisp_cons *cons)
515 if (!ao_lisp_check_argc(_ao_lisp_atom_pack, cons, 1, 1))
517 if (!ao_lisp_check_argt(_ao_lisp_atom_pack, cons, 0, AO_LISP_CONS, 1))
519 return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
523 ao_lisp_do_unpack(struct ao_lisp_cons *cons)
525 if (!ao_lisp_check_argc(_ao_lisp_atom_unpack, cons, 1, 1))
527 if (!ao_lisp_check_argt(_ao_lisp_atom_unpack, cons, 0, AO_LISP_STRING, 0))
529 return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
533 ao_lisp_do_flush(struct ao_lisp_cons *cons)
535 if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0))
538 return _ao_lisp_bool_true;
542 ao_lisp_do_led(struct ao_lisp_cons *cons)
545 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
547 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
549 led = ao_lisp_arg(cons, 0);
550 ao_lisp_os_led(ao_lisp_poly_int(led));
555 ao_lisp_do_delay(struct ao_lisp_cons *cons)
558 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
560 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
562 delay = ao_lisp_arg(cons, 0);
563 ao_lisp_os_delay(ao_lisp_poly_int(delay));
568 ao_lisp_do_eval(struct ao_lisp_cons *cons)
570 if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
572 ao_lisp_stack->state = eval_sexpr;
577 ao_lisp_do_read(struct ao_lisp_cons *cons)
579 if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
581 return ao_lisp_read();
585 ao_lisp_do_collect(struct ao_lisp_cons *cons)
589 free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
590 return ao_lisp_int_poly(free);
594 ao_lisp_do_nullp(struct ao_lisp_cons *cons)
596 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
598 if (ao_lisp_arg(cons, 0) == AO_LISP_NIL)
599 return _ao_lisp_bool_true;
601 return _ao_lisp_bool_false;
605 ao_lisp_do_not(struct ao_lisp_cons *cons)
607 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
609 if (ao_lisp_arg(cons, 0) == _ao_lisp_bool_false)
610 return _ao_lisp_bool_true;
612 return _ao_lisp_bool_false;
616 ao_lisp_do_listp(struct ao_lisp_cons *cons)
619 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
621 v = ao_lisp_arg(cons, 0);
623 if (v == AO_LISP_NIL)
624 return _ao_lisp_bool_true;
625 if (ao_lisp_poly_type(v) != AO_LISP_CONS)
626 return _ao_lisp_bool_false;
627 v = ao_lisp_poly_cons(v)->cdr;
632 ao_lisp_do_pairp(struct ao_lisp_cons *cons)
635 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
637 v = ao_lisp_arg(cons, 0);
638 if (ao_lisp_poly_type(v) == AO_LISP_CONS)
639 return _ao_lisp_bool_true;
640 return _ao_lisp_bool_false;
644 ao_lisp_do_numberp(struct ao_lisp_cons *cons)
646 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
648 if (AO_LISP_IS_INT(ao_lisp_arg(cons, 0)))
649 return _ao_lisp_bool_true;
650 return _ao_lisp_bool_false;
654 ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
656 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
658 if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == AO_LISP_BOOL)
659 return _ao_lisp_bool_true;
660 return _ao_lisp_bool_false;
664 ao_lisp_do_set_car(struct ao_lisp_cons *cons)
666 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
668 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
670 return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
674 ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
676 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
678 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
680 return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
683 #define AO_LISP_BUILTIN_FUNCS
684 #include "ao_lisp_builtin.h"