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.
20 builtin_size(void *addr)
23 return sizeof (struct ao_lisp_builtin);
27 builtin_mark(void *addr)
33 builtin_move(void *addr)
38 const struct ao_lisp_type ao_lisp_builtin_type = {
44 #ifdef AO_LISP_MAKE_CONST
46 #define AO_LISP_BUILTIN_CASENAME
47 #include "ao_lisp_builtin.h"
49 char *ao_lisp_args_name(uint8_t args) {
50 args &= AO_LISP_FUNC_MASK;
52 case AO_LISP_FUNC_LAMBDA: return ao_lisp_poly_atom(_ao_lisp_atom_lambda)->name;
53 case AO_LISP_FUNC_LEXPR: return ao_lisp_poly_atom(_ao_lisp_atom_lexpr)->name;
54 case AO_LISP_FUNC_NLAMBDA: return ao_lisp_poly_atom(_ao_lisp_atom_nlambda)->name;
55 case AO_LISP_FUNC_MACRO: return ao_lisp_poly_atom(_ao_lisp_atom_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_write(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_cons_cdr(cons);
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_cons_cdr(cons);
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)
166 struct ao_lisp_cons *list;
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 for (list = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
173 list = ao_lisp_cons_cdr(list))
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_set21, 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_begin(struct ao_lisp_cons *cons)
237 ao_lisp_stack->state = eval_begin;
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_write(struct ao_lisp_cons *cons)
253 ao_poly val = AO_LISP_NIL;
256 ao_lisp_poly_write(val);
257 cons = ao_lisp_cons_cdr(cons);
262 return _ao_lisp_bool_true;
266 ao_lisp_do_display(struct ao_lisp_cons *cons)
268 ao_poly val = AO_LISP_NIL;
271 ao_lisp_poly_display(val);
272 cons = ao_lisp_cons_cdr(cons);
274 return _ao_lisp_bool_true;
278 ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)
280 struct ao_lisp_cons *cons = cons;
281 ao_poly ret = AO_LISP_NIL;
283 for (cons = orig_cons; cons; cons = ao_lisp_cons_cdr(cons)) {
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) {
293 if (ao_lisp_integer_typep(ct))
294 ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
295 else if (ct == AO_LISP_FLOAT)
296 ret = ao_lisp_float_get(-ao_lisp_poly_number(ret));
299 if (ao_lisp_integer_typep(ct) && ao_lisp_poly_integer(ret) == 1)
301 else if (ao_lisp_number_typep(ct)) {
302 float v = ao_lisp_poly_number(ret);
303 ret = ao_lisp_float_get(1/v);
310 } else if (ao_lisp_integer_typep(rt) && ao_lisp_integer_typep(ct)) {
311 int32_t r = ao_lisp_poly_integer(ret);
312 int32_t c = ao_lisp_poly_integer(car);
325 if (c != 0 && (r % c) == 0)
328 ret = ao_lisp_float_get((float) r / (float) c);
332 case builtin_quotient:
334 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
335 if (r % c != 0 && (c < 0) != (r < 0))
340 case builtin_remainder:
342 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
347 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
349 if ((r < 0) != (c < 0))
355 ret = ao_lisp_integer_poly(r);
356 } else if (ao_lisp_number_typep(rt) && ao_lisp_number_typep(ct)) {
357 float r = ao_lisp_poly_number(ret);
358 float c = ao_lisp_poly_number(car);
373 case builtin_quotient:
375 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
376 if (r % c != 0 && (c < 0) != (r < 0))
381 case builtin_remainder:
383 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
388 return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
390 if ((r < 0) != (c < 0))
397 ret = ao_lisp_float_get(r);
400 else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
401 ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
402 ao_lisp_poly_string(car)));
404 return ao_lisp_error(AO_LISP_INVALID, "invalid args");
410 ao_lisp_do_plus(struct ao_lisp_cons *cons)
412 return ao_lisp_math(cons, builtin_plus);
416 ao_lisp_do_minus(struct ao_lisp_cons *cons)
418 return ao_lisp_math(cons, builtin_minus);
422 ao_lisp_do_times(struct ao_lisp_cons *cons)
424 return ao_lisp_math(cons, builtin_times);
428 ao_lisp_do_divide(struct ao_lisp_cons *cons)
430 return ao_lisp_math(cons, builtin_divide);
434 ao_lisp_do_quotient(struct ao_lisp_cons *cons)
436 return ao_lisp_math(cons, builtin_quotient);
440 ao_lisp_do_modulo(struct ao_lisp_cons *cons)
442 return ao_lisp_math(cons, builtin_modulo);
446 ao_lisp_do_remainder(struct ao_lisp_cons *cons)
448 return ao_lisp_math(cons, builtin_remainder);
452 ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
457 return _ao_lisp_bool_true;
460 for (cons = ao_lisp_cons_cdr(cons); cons; cons = ao_lisp_cons_cdr(cons)) {
461 ao_poly right = cons->car;
463 if (op == builtin_equal) {
465 return _ao_lisp_bool_false;
467 uint8_t lt = ao_lisp_poly_type(left);
468 uint8_t rt = ao_lisp_poly_type(right);
469 if (ao_lisp_integer_typep(lt) && ao_lisp_integer_typep(rt)) {
470 int32_t l = ao_lisp_poly_integer(left);
471 int32_t r = ao_lisp_poly_integer(right);
476 return _ao_lisp_bool_false;
478 case builtin_greater:
480 return _ao_lisp_bool_false;
482 case builtin_less_equal:
484 return _ao_lisp_bool_false;
486 case builtin_greater_equal:
488 return _ao_lisp_bool_false;
493 } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) {
494 int c = strcmp(ao_lisp_poly_string(left),
495 ao_lisp_poly_string(right));
499 return _ao_lisp_bool_false;
501 case builtin_greater:
503 return _ao_lisp_bool_false;
505 case builtin_less_equal:
507 return _ao_lisp_bool_false;
509 case builtin_greater_equal:
511 return _ao_lisp_bool_false;
520 return _ao_lisp_bool_true;
524 ao_lisp_do_equal(struct ao_lisp_cons *cons)
526 return ao_lisp_compare(cons, builtin_equal);
530 ao_lisp_do_less(struct ao_lisp_cons *cons)
532 return ao_lisp_compare(cons, builtin_less);
536 ao_lisp_do_greater(struct ao_lisp_cons *cons)
538 return ao_lisp_compare(cons, builtin_greater);
542 ao_lisp_do_less_equal(struct ao_lisp_cons *cons)
544 return ao_lisp_compare(cons, builtin_less_equal);
548 ao_lisp_do_greater_equal(struct ao_lisp_cons *cons)
550 return ao_lisp_compare(cons, builtin_greater_equal);
554 ao_lisp_do_list_to_string(struct ao_lisp_cons *cons)
556 if (!ao_lisp_check_argc(_ao_lisp_atom_list2d3estring, cons, 1, 1))
558 if (!ao_lisp_check_argt(_ao_lisp_atom_list2d3estring, cons, 0, AO_LISP_CONS, 1))
560 return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
564 ao_lisp_do_string_to_list(struct ao_lisp_cons *cons)
566 if (!ao_lisp_check_argc(_ao_lisp_atom_string2d3elist, cons, 1, 1))
568 if (!ao_lisp_check_argt(_ao_lisp_atom_string2d3elist, cons, 0, AO_LISP_STRING, 0))
570 return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
574 ao_lisp_do_flush_output(struct ao_lisp_cons *cons)
576 if (!ao_lisp_check_argc(_ao_lisp_atom_flush2doutput, cons, 0, 0))
579 return _ao_lisp_bool_true;
583 ao_lisp_do_led(struct ao_lisp_cons *cons)
586 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
588 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
590 led = ao_lisp_arg(cons, 0);
591 ao_lisp_os_led(ao_lisp_poly_int(led));
596 ao_lisp_do_delay(struct ao_lisp_cons *cons)
599 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
601 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
603 delay = ao_lisp_arg(cons, 0);
604 ao_lisp_os_delay(ao_lisp_poly_int(delay));
609 ao_lisp_do_eval(struct ao_lisp_cons *cons)
611 if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
613 ao_lisp_stack->state = eval_sexpr;
618 ao_lisp_do_apply(struct ao_lisp_cons *cons)
620 if (!ao_lisp_check_argc(_ao_lisp_atom_apply, cons, 2, INT_MAX))
622 ao_lisp_stack->state = eval_apply;
623 return ao_lisp_cons_poly(cons);
627 ao_lisp_do_read(struct ao_lisp_cons *cons)
629 if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
631 return ao_lisp_read();
635 ao_lisp_do_collect(struct ao_lisp_cons *cons)
639 free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
640 return ao_lisp_int_poly(free);
644 ao_lisp_do_nullp(struct ao_lisp_cons *cons)
646 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
648 if (ao_lisp_arg(cons, 0) == AO_LISP_NIL)
649 return _ao_lisp_bool_true;
651 return _ao_lisp_bool_false;
655 ao_lisp_do_not(struct ao_lisp_cons *cons)
657 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
659 if (ao_lisp_arg(cons, 0) == _ao_lisp_bool_false)
660 return _ao_lisp_bool_true;
662 return _ao_lisp_bool_false;
666 ao_lisp_do_typep(int type, struct ao_lisp_cons *cons)
668 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
670 if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == type)
671 return _ao_lisp_bool_true;
672 return _ao_lisp_bool_false;
676 ao_lisp_do_pairp(struct ao_lisp_cons *cons)
678 return ao_lisp_do_typep(AO_LISP_CONS, cons);
682 ao_lisp_do_integerp(struct ao_lisp_cons *cons)
684 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
686 switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
689 return _ao_lisp_bool_true;
691 return _ao_lisp_bool_false;
696 ao_lisp_do_numberp(struct ao_lisp_cons *cons)
698 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
700 switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
704 return _ao_lisp_bool_true;
706 return _ao_lisp_bool_false;
711 ao_lisp_do_stringp(struct ao_lisp_cons *cons)
713 return ao_lisp_do_typep(AO_LISP_STRING, cons);
717 ao_lisp_do_symbolp(struct ao_lisp_cons *cons)
719 return ao_lisp_do_typep(AO_LISP_ATOM, cons);
723 ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
725 return ao_lisp_do_typep(AO_LISP_BOOL, cons);
729 ao_lisp_do_procedurep(struct ao_lisp_cons *cons)
731 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
733 switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
734 case AO_LISP_BUILTIN:
736 return _ao_lisp_bool_true;
738 return _ao_lisp_bool_false;
742 /* This one is special -- a list is either nil or
743 * a 'proper' list with only cons cells
746 ao_lisp_do_listp(struct ao_lisp_cons *cons)
749 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
751 v = ao_lisp_arg(cons, 0);
753 if (v == AO_LISP_NIL)
754 return _ao_lisp_bool_true;
755 if (ao_lisp_poly_type(v) != AO_LISP_CONS)
756 return _ao_lisp_bool_false;
757 v = ao_lisp_poly_cons(v)->cdr;
762 ao_lisp_do_set_car(struct ao_lisp_cons *cons)
764 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
766 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
768 return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
772 ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
774 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
776 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
778 return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
782 ao_lisp_do_symbol_to_string(struct ao_lisp_cons *cons)
784 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
786 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_ATOM, 0))
788 return ao_lisp_string_poly(ao_lisp_string_copy(ao_lisp_poly_atom(ao_lisp_arg(cons, 0))->name));
792 ao_lisp_do_string_to_symbol(struct ao_lisp_cons *cons)
794 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
796 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_STRING, 0))
799 return ao_lisp_atom_poly(ao_lisp_atom_intern(ao_lisp_poly_string(ao_lisp_arg(cons, 0))));
803 ao_lisp_do_read_char(struct ao_lisp_cons *cons)
806 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
809 return ao_lisp_int_poly(c);
813 ao_lisp_do_write_char(struct ao_lisp_cons *cons)
815 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
817 if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
819 putchar(ao_lisp_poly_integer(ao_lisp_arg(cons, 0)));
820 return _ao_lisp_bool_true;
824 ao_lisp_do_exit(struct ao_lisp_cons *cons)
826 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
828 ao_lisp_exception |= AO_LISP_EXIT;
829 return _ao_lisp_bool_true;
833 ao_lisp_do_current_jiffy(struct ao_lisp_cons *cons)
837 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
839 jiffy = ao_lisp_os_jiffy();
840 return (ao_lisp_int_poly(jiffy));
844 ao_lisp_do_current_second(struct ao_lisp_cons *cons)
848 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
850 second = ao_lisp_os_jiffy() / AO_LISP_JIFFIES_PER_SECOND;
851 return (ao_lisp_int_poly(second));
855 ao_lisp_do_jiffies_per_second(struct ao_lisp_cons *cons)
857 if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
859 return (ao_lisp_int_poly(AO_LISP_JIFFIES_PER_SECOND));
862 #define AO_LISP_BUILTIN_FUNCS
863 #include "ao_lisp_builtin.h"