ad8f4125ff8ba1f777d065fe03faa9bcc7e4fb53
[fw/altos] / src / lisp / ao_lisp_builtin.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 #include <limits.h>
17 #include <math.h>
18
19 static int
20 builtin_size(void *addr)
21 {
22         (void) addr;
23         return sizeof (struct ao_lisp_builtin);
24 }
25
26 static void
27 builtin_mark(void *addr)
28 {
29         (void) addr;
30 }
31
32 static void
33 builtin_move(void *addr)
34 {
35         (void) addr;
36 }
37
38 const struct ao_lisp_type ao_lisp_builtin_type = {
39         .size = builtin_size,
40         .mark = builtin_mark,
41         .move = builtin_move
42 };
43
44 #ifdef AO_LISP_MAKE_CONST
45
46 #define AO_LISP_BUILTIN_CASENAME
47 #include "ao_lisp_builtin.h"
48
49 char *ao_lisp_args_name(uint8_t args) {
50         args &= AO_LISP_FUNC_MASK;
51         switch (args) {
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 "???";
57         }
58 }
59 #else
60
61 #define AO_LISP_BUILTIN_ARRAYNAME
62 #include "ao_lisp_builtin.h"
63
64 static char *
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;
68         return "???";
69 }
70
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,
76 };
77
78 char *
79 ao_lisp_args_name(uint8_t args)
80 {
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;
84         return "(unknown)";
85 }
86 #endif
87
88 void
89 ao_lisp_builtin_write(ao_poly b)
90 {
91         struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b);
92         printf("%s", ao_lisp_builtin_name(builtin->func));
93 }
94
95 ao_poly
96 ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max)
97 {
98         int     argc = 0;
99
100         while (cons && argc <= max) {
101                 argc++;
102                 cons = ao_lisp_cons_cdr(cons);
103         }
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;
107 }
108
109 ao_poly
110 ao_lisp_arg(struct ao_lisp_cons *cons, int argc)
111 {
112         if (!cons)
113                 return AO_LISP_NIL;
114         while (argc--) {
115                 if (!cons)
116                         return AO_LISP_NIL;
117                 cons = ao_lisp_cons_cdr(cons);
118         }
119         return cons->car;
120 }
121
122 ao_poly
123 ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok)
124 {
125         ao_poly car = ao_lisp_arg(cons, argc);
126
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;
130 }
131
132 ao_poly
133 ao_lisp_do_car(struct ao_lisp_cons *cons)
134 {
135         if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1))
136                 return AO_LISP_NIL;
137         if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0))
138                 return AO_LISP_NIL;
139         return ao_lisp_poly_cons(cons->car)->car;
140 }
141
142 ao_poly
143 ao_lisp_do_cdr(struct ao_lisp_cons *cons)
144 {
145         if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1))
146                 return AO_LISP_NIL;
147         if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0))
148                 return AO_LISP_NIL;
149         return ao_lisp_poly_cons(cons->car)->cdr;
150 }
151
152 ao_poly
153 ao_lisp_do_cons(struct ao_lisp_cons *cons)
154 {
155         ao_poly car, cdr;
156         if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2))
157                 return AO_LISP_NIL;
158         car = ao_lisp_arg(cons, 0);
159         cdr = ao_lisp_arg(cons, 1);
160         return ao_lisp__cons(car, cdr);
161 }
162
163 ao_poly
164 ao_lisp_do_last(struct ao_lisp_cons *cons)
165 {
166         struct ao_lisp_cons     *list;
167         if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1))
168                 return AO_LISP_NIL;
169         if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1))
170                 return AO_LISP_NIL;
171         for (list = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
172              list;
173              list = ao_lisp_cons_cdr(list))
174         {
175                 if (!list->cdr)
176                         return list->car;
177         }
178         return AO_LISP_NIL;
179 }
180
181 ao_poly
182 ao_lisp_do_length(struct ao_lisp_cons *cons)
183 {
184         if (!ao_lisp_check_argc(_ao_lisp_atom_length, cons, 1, 1))
185                 return AO_LISP_NIL;
186         if (!ao_lisp_check_argt(_ao_lisp_atom_length, cons, 0, AO_LISP_CONS, 1))
187                 return AO_LISP_NIL;
188         return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))));
189 }
190
191 ao_poly
192 ao_lisp_do_quote(struct ao_lisp_cons *cons)
193 {
194         if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1))
195                 return AO_LISP_NIL;
196         return ao_lisp_arg(cons, 0);
197 }
198
199 ao_poly
200 ao_lisp_do_set(struct ao_lisp_cons *cons)
201 {
202         if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2))
203                 return AO_LISP_NIL;
204         if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0))
205                 return AO_LISP_NIL;
206
207         return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1));
208 }
209
210 ao_poly
211 ao_lisp_do_def(struct ao_lisp_cons *cons)
212 {
213         if (!ao_lisp_check_argc(_ao_lisp_atom_def, cons, 2, 2))
214                 return AO_LISP_NIL;
215         if (!ao_lisp_check_argt(_ao_lisp_atom_def, cons, 0, AO_LISP_ATOM, 0))
216                 return AO_LISP_NIL;
217
218         return ao_lisp_atom_def(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1));
219 }
220
221 ao_poly
222 ao_lisp_do_setq(struct ao_lisp_cons *cons)
223 {
224         ao_poly name;
225         if (!ao_lisp_check_argc(_ao_lisp_atom_set21, cons, 2, 2))
226                 return AO_LISP_NIL;
227         name = cons->car;
228         if (ao_lisp_poly_type(name) != AO_LISP_ATOM)
229                 return ao_lisp_error(AO_LISP_INVALID, "set! of non-atom");
230         if (!ao_lisp_atom_ref(name))
231                 return ao_lisp_error(AO_LISP_INVALID, "atom not defined");
232         return ao_lisp__cons(_ao_lisp_atom_set,
233                              ao_lisp__cons(ao_lisp__cons(_ao_lisp_atom_quote,
234                                                          ao_lisp__cons(name, AO_LISP_NIL)),
235                                            cons->cdr));
236 }
237
238 ao_poly
239 ao_lisp_do_cond(struct ao_lisp_cons *cons)
240 {
241         ao_lisp_set_cond(cons);
242         return AO_LISP_NIL;
243 }
244
245 ao_poly
246 ao_lisp_do_begin(struct ao_lisp_cons *cons)
247 {
248         ao_lisp_stack->state = eval_begin;
249         ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
250         return AO_LISP_NIL;
251 }
252
253 ao_poly
254 ao_lisp_do_while(struct ao_lisp_cons *cons)
255 {
256         ao_lisp_stack->state = eval_while;
257         ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
258         return AO_LISP_NIL;
259 }
260
261 ao_poly
262 ao_lisp_do_write(struct ao_lisp_cons *cons)
263 {
264         ao_poly val = AO_LISP_NIL;
265         while (cons) {
266                 val = cons->car;
267                 ao_lisp_poly_write(val);
268                 cons = ao_lisp_cons_cdr(cons);
269                 if (cons)
270                         printf(" ");
271         }
272         printf("\n");
273         return _ao_lisp_bool_true;
274 }
275
276 ao_poly
277 ao_lisp_do_display(struct ao_lisp_cons *cons)
278 {
279         ao_poly val = AO_LISP_NIL;
280         while (cons) {
281                 val = cons->car;
282                 ao_lisp_poly_display(val);
283                 cons = ao_lisp_cons_cdr(cons);
284         }
285         return _ao_lisp_bool_true;
286 }
287
288 ao_poly
289 ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)
290 {
291         struct ao_lisp_cons *cons = cons;
292         ao_poly ret = AO_LISP_NIL;
293
294         for (cons = orig_cons; cons; cons = ao_lisp_cons_cdr(cons)) {
295                 ao_poly         car = cons->car;
296                 uint8_t         rt = ao_lisp_poly_type(ret);
297                 uint8_t         ct = ao_lisp_poly_type(car);
298
299                 if (cons == orig_cons) {
300                         ret = car;
301                         if (cons->cdr == AO_LISP_NIL) {
302                                 switch (op) {
303                                 case builtin_minus:
304                                         if (ao_lisp_integer_typep(ct))
305                                                 ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
306                                         else if (ct == AO_LISP_FLOAT)
307                                                 ret = ao_lisp_float_get(-ao_lisp_poly_number(ret));
308                                         break;
309                                 case builtin_divide:
310                                         if (ao_lisp_integer_typep(ct) && ao_lisp_poly_integer(ret) == 1)
311                                                 ;
312                                         else if (ao_lisp_number_typep(ct)) {
313                                                 float   v = ao_lisp_poly_number(ret);
314                                                 ret = ao_lisp_float_get(1/v);
315                                         }
316                                         break;
317                                 default:
318                                         break;
319                                 }
320                         }
321                 } else if (ao_lisp_integer_typep(rt) && ao_lisp_integer_typep(ct)) {
322                         int32_t r = ao_lisp_poly_integer(ret);
323                         int32_t c = ao_lisp_poly_integer(car);
324                         int64_t t;
325
326                         switch(op) {
327                         case builtin_plus:
328                                 r += c;
329                         check_overflow:
330                                 if (r < AO_LISP_MIN_BIGINT || AO_LISP_MAX_BIGINT < r)
331                                         goto inexact;
332                                 break;
333                         case builtin_minus:
334                                 r -= c;
335                                 goto check_overflow;
336                                 break;
337                         case builtin_times:
338                                 t = (int64_t) r * (int64_t) c;
339                                 if (t < AO_LISP_MIN_BIGINT || AO_LISP_MAX_BIGINT < t)
340                                         goto inexact;
341                                 r = (int32_t) t;
342                                 break;
343                         case builtin_divide:
344                                 if (c != 0 && (r % c) == 0)
345                                         r /= c;
346                                 else
347                                         goto inexact;
348                                 break;
349                         case builtin_quotient:
350                                 if (c == 0)
351                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
352                                 if (r % c != 0 && (c < 0) != (r < 0))
353                                         r = r / c - 1;
354                                 else
355                                         r = r / c;
356                                 break;
357                         case builtin_remainder:
358                                 if (c == 0)
359                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
360                                 r %= c;
361                                 break;
362                         case builtin_modulo:
363                                 if (c == 0)
364                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
365                                 r %= c;
366                                 if ((r < 0) != (c < 0))
367                                         r += c;
368                                 break;
369                         default:
370                                 break;
371                         }
372                         ret = ao_lisp_integer_poly(r);
373                 } else if (ao_lisp_number_typep(rt) && ao_lisp_number_typep(ct)) {
374                         float r, c;
375                 inexact:
376                         r = ao_lisp_poly_number(ret);
377                         c = ao_lisp_poly_number(car);
378                         switch(op) {
379                         case builtin_plus:
380                                 r += c;
381                                 break;
382                         case builtin_minus:
383                                 r -= c;
384                                 break;
385                         case builtin_times:
386                                 r *= c;
387                                 break;
388                         case builtin_divide:
389                                 r /= c;
390                                 break;
391                         case builtin_quotient:
392                         case builtin_remainder:
393                         case builtin_modulo:
394                                 return ao_lisp_error(AO_LISP_INVALID, "non-integer value in integer divide");
395                         default:
396                                 break;
397                         }
398                         ret = ao_lisp_float_get(r);
399                 }
400
401                 else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
402                         ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret),
403                                                                      ao_lisp_poly_string(car)));
404                 else
405                         return ao_lisp_error(AO_LISP_INVALID, "invalid args");
406         }
407         return ret;
408 }
409
410 ao_poly
411 ao_lisp_do_plus(struct ao_lisp_cons *cons)
412 {
413         return ao_lisp_math(cons, builtin_plus);
414 }
415
416 ao_poly
417 ao_lisp_do_minus(struct ao_lisp_cons *cons)
418 {
419         return ao_lisp_math(cons, builtin_minus);
420 }
421
422 ao_poly
423 ao_lisp_do_times(struct ao_lisp_cons *cons)
424 {
425         return ao_lisp_math(cons, builtin_times);
426 }
427
428 ao_poly
429 ao_lisp_do_divide(struct ao_lisp_cons *cons)
430 {
431         return ao_lisp_math(cons, builtin_divide);
432 }
433
434 ao_poly
435 ao_lisp_do_quotient(struct ao_lisp_cons *cons)
436 {
437         return ao_lisp_math(cons, builtin_quotient);
438 }
439
440 ao_poly
441 ao_lisp_do_modulo(struct ao_lisp_cons *cons)
442 {
443         return ao_lisp_math(cons, builtin_modulo);
444 }
445
446 ao_poly
447 ao_lisp_do_remainder(struct ao_lisp_cons *cons)
448 {
449         return ao_lisp_math(cons, builtin_remainder);
450 }
451
452 ao_poly
453 ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
454 {
455         ao_poly left;
456
457         if (!cons)
458                 return _ao_lisp_bool_true;
459
460         left = cons->car;
461         for (cons = ao_lisp_cons_cdr(cons); cons; cons = ao_lisp_cons_cdr(cons)) {
462                 ao_poly right = cons->car;
463
464                 if (op == builtin_equal) {
465                         if (left != right)
466                                 return _ao_lisp_bool_false;
467                 } else {
468                         uint8_t lt = ao_lisp_poly_type(left);
469                         uint8_t rt = ao_lisp_poly_type(right);
470                         if (ao_lisp_integer_typep(lt) && ao_lisp_integer_typep(rt)) {
471                                 int32_t l = ao_lisp_poly_integer(left);
472                                 int32_t r = ao_lisp_poly_integer(right);
473
474                                 switch (op) {
475                                 case builtin_less:
476                                         if (!(l < r))
477                                                 return _ao_lisp_bool_false;
478                                         break;
479                                 case builtin_greater:
480                                         if (!(l > r))
481                                                 return _ao_lisp_bool_false;
482                                         break;
483                                 case builtin_less_equal:
484                                         if (!(l <= r))
485                                                 return _ao_lisp_bool_false;
486                                         break;
487                                 case builtin_greater_equal:
488                                         if (!(l >= r))
489                                                 return _ao_lisp_bool_false;
490                                         break;
491                                 default:
492                                         break;
493                                 }
494                         } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) {
495                                 int c = strcmp(ao_lisp_poly_string(left),
496                                                ao_lisp_poly_string(right));
497                                 switch (op) {
498                                 case builtin_less:
499                                         if (!(c < 0))
500                                                 return _ao_lisp_bool_false;
501                                         break;
502                                 case builtin_greater:
503                                         if (!(c > 0))
504                                                 return _ao_lisp_bool_false;
505                                         break;
506                                 case builtin_less_equal:
507                                         if (!(c <= 0))
508                                                 return _ao_lisp_bool_false;
509                                         break;
510                                 case builtin_greater_equal:
511                                         if (!(c >= 0))
512                                                 return _ao_lisp_bool_false;
513                                         break;
514                                 default:
515                                         break;
516                                 }
517                         }
518                 }
519                 left = right;
520         }
521         return _ao_lisp_bool_true;
522 }
523
524 ao_poly
525 ao_lisp_do_equal(struct ao_lisp_cons *cons)
526 {
527         return ao_lisp_compare(cons, builtin_equal);
528 }
529
530 ao_poly
531 ao_lisp_do_less(struct ao_lisp_cons *cons)
532 {
533         return ao_lisp_compare(cons, builtin_less);
534 }
535
536 ao_poly
537 ao_lisp_do_greater(struct ao_lisp_cons *cons)
538 {
539         return ao_lisp_compare(cons, builtin_greater);
540 }
541
542 ao_poly
543 ao_lisp_do_less_equal(struct ao_lisp_cons *cons)
544 {
545         return ao_lisp_compare(cons, builtin_less_equal);
546 }
547
548 ao_poly
549 ao_lisp_do_greater_equal(struct ao_lisp_cons *cons)
550 {
551         return ao_lisp_compare(cons, builtin_greater_equal);
552 }
553
554 ao_poly
555 ao_lisp_do_list_to_string(struct ao_lisp_cons *cons)
556 {
557         if (!ao_lisp_check_argc(_ao_lisp_atom_list2d3estring, cons, 1, 1))
558                 return AO_LISP_NIL;
559         if (!ao_lisp_check_argt(_ao_lisp_atom_list2d3estring, cons, 0, AO_LISP_CONS, 1))
560                 return AO_LISP_NIL;
561         return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
562 }
563
564 ao_poly
565 ao_lisp_do_string_to_list(struct ao_lisp_cons *cons)
566 {
567         if (!ao_lisp_check_argc(_ao_lisp_atom_string2d3elist, cons, 1, 1))
568                 return AO_LISP_NIL;
569         if (!ao_lisp_check_argt(_ao_lisp_atom_string2d3elist, cons, 0, AO_LISP_STRING, 0))
570                 return AO_LISP_NIL;
571         return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
572 }
573
574 ao_poly
575 ao_lisp_do_flush_output(struct ao_lisp_cons *cons)
576 {
577         if (!ao_lisp_check_argc(_ao_lisp_atom_flush2doutput, cons, 0, 0))
578                 return AO_LISP_NIL;
579         ao_lisp_os_flush();
580         return _ao_lisp_bool_true;
581 }
582
583 ao_poly
584 ao_lisp_do_led(struct ao_lisp_cons *cons)
585 {
586         ao_poly led;
587         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
588                 return AO_LISP_NIL;
589         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
590                 return AO_LISP_NIL;
591         led = ao_lisp_arg(cons, 0);
592         ao_lisp_os_led(ao_lisp_poly_int(led));
593         return led;
594 }
595
596 ao_poly
597 ao_lisp_do_delay(struct ao_lisp_cons *cons)
598 {
599         ao_poly delay;
600         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
601                 return AO_LISP_NIL;
602         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
603                 return AO_LISP_NIL;
604         delay = ao_lisp_arg(cons, 0);
605         ao_lisp_os_delay(ao_lisp_poly_int(delay));
606         return delay;
607 }
608
609 ao_poly
610 ao_lisp_do_eval(struct ao_lisp_cons *cons)
611 {
612         if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
613                 return AO_LISP_NIL;
614         ao_lisp_stack->state = eval_sexpr;
615         return cons->car;
616 }
617
618 ao_poly
619 ao_lisp_do_apply(struct ao_lisp_cons *cons)
620 {
621         if (!ao_lisp_check_argc(_ao_lisp_atom_apply, cons, 2, INT_MAX))
622                 return AO_LISP_NIL;
623         ao_lisp_stack->state = eval_apply;
624         return ao_lisp_cons_poly(cons);
625 }
626
627 ao_poly
628 ao_lisp_do_read(struct ao_lisp_cons *cons)
629 {
630         if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
631                 return AO_LISP_NIL;
632         return ao_lisp_read();
633 }
634
635 ao_poly
636 ao_lisp_do_collect(struct ao_lisp_cons *cons)
637 {
638         int     free;
639         (void) cons;
640         free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
641         return ao_lisp_int_poly(free);
642 }
643
644 ao_poly
645 ao_lisp_do_nullp(struct ao_lisp_cons *cons)
646 {
647         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
648                 return AO_LISP_NIL;
649         if (ao_lisp_arg(cons, 0) == AO_LISP_NIL)
650                 return _ao_lisp_bool_true;
651         else
652                 return _ao_lisp_bool_false;
653 }
654
655 ao_poly
656 ao_lisp_do_not(struct ao_lisp_cons *cons)
657 {
658         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
659                 return AO_LISP_NIL;
660         if (ao_lisp_arg(cons, 0) == _ao_lisp_bool_false)
661                 return _ao_lisp_bool_true;
662         else
663                 return _ao_lisp_bool_false;
664 }
665
666 static ao_poly
667 ao_lisp_do_typep(int type, struct ao_lisp_cons *cons)
668 {
669         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
670                 return AO_LISP_NIL;
671         if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == type)
672                 return _ao_lisp_bool_true;
673         return _ao_lisp_bool_false;
674 }
675
676 ao_poly
677 ao_lisp_do_pairp(struct ao_lisp_cons *cons)
678 {
679         ao_poly v;
680         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
681                 return AO_LISP_NIL;
682         v = ao_lisp_arg(cons, 0);
683         if (v != AO_LISP_NIL && ao_lisp_poly_type(v) == AO_LISP_CONS)
684                 return _ao_lisp_bool_true;
685         return _ao_lisp_bool_false;
686 }
687
688 ao_poly
689 ao_lisp_do_integerp(struct ao_lisp_cons *cons)
690 {
691         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
692                 return AO_LISP_NIL;
693         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
694         case AO_LISP_INT:
695         case AO_LISP_BIGINT:
696                 return _ao_lisp_bool_true;
697         default:
698                 return _ao_lisp_bool_false;
699         }
700 }
701
702 ao_poly
703 ao_lisp_do_numberp(struct ao_lisp_cons *cons)
704 {
705         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
706                 return AO_LISP_NIL;
707         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
708         case AO_LISP_INT:
709         case AO_LISP_BIGINT:
710         case AO_LISP_FLOAT:
711                 return _ao_lisp_bool_true;
712         default:
713                 return _ao_lisp_bool_false;
714         }
715 }
716
717 ao_poly
718 ao_lisp_do_stringp(struct ao_lisp_cons *cons)
719 {
720         return ao_lisp_do_typep(AO_LISP_STRING, cons);
721 }
722
723 ao_poly
724 ao_lisp_do_symbolp(struct ao_lisp_cons *cons)
725 {
726         return ao_lisp_do_typep(AO_LISP_ATOM, cons);
727 }
728
729 ao_poly
730 ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
731 {
732         return ao_lisp_do_typep(AO_LISP_BOOL, cons);
733 }
734
735 ao_poly
736 ao_lisp_do_procedurep(struct ao_lisp_cons *cons)
737 {
738         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
739                 return AO_LISP_NIL;
740         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
741         case AO_LISP_BUILTIN:
742         case AO_LISP_LAMBDA:
743                 return _ao_lisp_bool_true;
744         default:
745         return _ao_lisp_bool_false;
746         }
747 }
748
749 /* This one is special -- a list is either nil or
750  * a 'proper' list with only cons cells
751  */
752 ao_poly
753 ao_lisp_do_listp(struct ao_lisp_cons *cons)
754 {
755         ao_poly v;
756         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
757                 return AO_LISP_NIL;
758         v = ao_lisp_arg(cons, 0);
759         for (;;) {
760                 if (v == AO_LISP_NIL)
761                         return _ao_lisp_bool_true;
762                 if (ao_lisp_poly_type(v) != AO_LISP_CONS)
763                         return _ao_lisp_bool_false;
764                 v = ao_lisp_poly_cons(v)->cdr;
765         }
766 }
767
768 ao_poly
769 ao_lisp_do_set_car(struct ao_lisp_cons *cons)
770 {
771         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
772                 return AO_LISP_NIL;
773         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
774                 return AO_LISP_NIL;
775         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
776 }
777
778 ao_poly
779 ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
780 {
781         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
782                 return AO_LISP_NIL;
783         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
784                 return AO_LISP_NIL;
785         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
786 }
787
788 ao_poly
789 ao_lisp_do_symbol_to_string(struct ao_lisp_cons *cons)
790 {
791         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
792                 return AO_LISP_NIL;
793         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_ATOM, 0))
794                 return AO_LISP_NIL;
795         return ao_lisp_string_poly(ao_lisp_string_copy(ao_lisp_poly_atom(ao_lisp_arg(cons, 0))->name));
796 }
797
798 ao_poly
799 ao_lisp_do_string_to_symbol(struct ao_lisp_cons *cons)
800 {
801         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
802                 return AO_LISP_NIL;
803         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_STRING, 0))
804                 return AO_LISP_NIL;
805
806         return ao_lisp_atom_poly(ao_lisp_atom_intern(ao_lisp_poly_string(ao_lisp_arg(cons, 0))));
807 }
808
809 ao_poly
810 ao_lisp_do_read_char(struct ao_lisp_cons *cons)
811 {
812         int     c;
813         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
814                 return AO_LISP_NIL;
815         c = getchar();
816         return ao_lisp_int_poly(c);
817 }
818
819 ao_poly
820 ao_lisp_do_write_char(struct ao_lisp_cons *cons)
821 {
822         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
823                 return AO_LISP_NIL;
824         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
825                 return AO_LISP_NIL;
826         putchar(ao_lisp_poly_integer(ao_lisp_arg(cons, 0)));
827         return _ao_lisp_bool_true;
828 }
829
830 ao_poly
831 ao_lisp_do_exit(struct ao_lisp_cons *cons)
832 {
833         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
834                 return AO_LISP_NIL;
835         ao_lisp_exception |= AO_LISP_EXIT;
836         return _ao_lisp_bool_true;
837 }
838
839 ao_poly
840 ao_lisp_do_current_jiffy(struct ao_lisp_cons *cons)
841 {
842         int     jiffy;
843
844         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
845                 return AO_LISP_NIL;
846         jiffy = ao_lisp_os_jiffy();
847         return (ao_lisp_int_poly(jiffy));
848 }
849
850 ao_poly
851 ao_lisp_do_current_second(struct ao_lisp_cons *cons)
852 {
853         int     second;
854
855         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
856                 return AO_LISP_NIL;
857         second = ao_lisp_os_jiffy() / AO_LISP_JIFFIES_PER_SECOND;
858         return (ao_lisp_int_poly(second));
859 }
860
861 ao_poly
862 ao_lisp_do_jiffies_per_second(struct ao_lisp_cons *cons)
863 {
864         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
865                 return AO_LISP_NIL;
866         return (ao_lisp_int_poly(AO_LISP_JIFFIES_PER_SECOND));
867 }
868
869 #define AO_LISP_BUILTIN_FUNCS
870 #include "ao_lisp_builtin.h"