altos/lisp: Rename progn to begin
[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_setq(struct ao_lisp_cons *cons)
212 {
213         ao_poly name;
214         if (!ao_lisp_check_argc(_ao_lisp_atom_set21, cons, 2, 2))
215                 return AO_LISP_NIL;
216         name = cons->car;
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)),
224                                            cons->cdr));
225 }
226
227 ao_poly
228 ao_lisp_do_cond(struct ao_lisp_cons *cons)
229 {
230         ao_lisp_set_cond(cons);
231         return AO_LISP_NIL;
232 }
233
234 ao_poly
235 ao_lisp_do_begin(struct ao_lisp_cons *cons)
236 {
237         ao_lisp_stack->state = eval_begin;
238         ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
239         return AO_LISP_NIL;
240 }
241
242 ao_poly
243 ao_lisp_do_while(struct ao_lisp_cons *cons)
244 {
245         ao_lisp_stack->state = eval_while;
246         ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons);
247         return AO_LISP_NIL;
248 }
249
250 ao_poly
251 ao_lisp_do_write(struct ao_lisp_cons *cons)
252 {
253         ao_poly val = AO_LISP_NIL;
254         while (cons) {
255                 val = cons->car;
256                 ao_lisp_poly_write(val);
257                 cons = ao_lisp_cons_cdr(cons);
258                 if (cons)
259                         printf(" ");
260         }
261         printf("\n");
262         return _ao_lisp_bool_true;
263 }
264
265 ao_poly
266 ao_lisp_do_display(struct ao_lisp_cons *cons)
267 {
268         ao_poly val = AO_LISP_NIL;
269         while (cons) {
270                 val = cons->car;
271                 ao_lisp_poly_display(val);
272                 cons = ao_lisp_cons_cdr(cons);
273         }
274         return _ao_lisp_bool_true;
275 }
276
277 ao_poly
278 ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)
279 {
280         struct ao_lisp_cons *cons = cons;
281         ao_poly ret = AO_LISP_NIL;
282
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);
287
288                 if (cons == orig_cons) {
289                         ret = car;
290                         if (cons->cdr == AO_LISP_NIL) {
291                                 switch (op) {
292                                 case builtin_minus:
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));
297                                         break;
298                                 case builtin_divide:
299                                         if (ao_lisp_integer_typep(ct) && ao_lisp_poly_integer(ret) == 1)
300                                                 ;
301                                         else if (ao_lisp_number_typep(ct)) {
302                                                 float   v = ao_lisp_poly_number(ret);
303                                                 ret = ao_lisp_float_get(1/v);
304                                         }
305                                         break;
306                                 default:
307                                         break;
308                                 }
309                         }
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);
313
314                         switch(op) {
315                         case builtin_plus:
316                                 r += c;
317                                 break;
318                         case builtin_minus:
319                                 r -= c;
320                                 break;
321                         case builtin_times:
322                                 r *= c;
323                                 break;
324                         case builtin_divide:
325                                 if (c != 0 && (r % c) == 0)
326                                         r /= c;
327                                 else {
328                                         ret = ao_lisp_float_get((float) r / (float) c);
329                                         continue;
330                                 }
331                                 break;
332                         case builtin_quotient:
333                                 if (c == 0)
334                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
335                                 if (r % c != 0 && (c < 0) != (r < 0))
336                                         r = r / c - 1;
337                                 else
338                                         r = r / c;
339                                 break;
340                         case builtin_remainder:
341                                 if (c == 0)
342                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
343                                 r %= c;
344                                 break;
345                         case builtin_modulo:
346                                 if (c == 0)
347                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
348                                 r %= c;
349                                 if ((r < 0) != (c < 0))
350                                         r += c;
351                                 break;
352                         default:
353                                 break;
354                         }
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);
359                         switch(op) {
360                         case builtin_plus:
361                                 r += c;
362                                 break;
363                         case builtin_minus:
364                                 r -= c;
365                                 break;
366                         case builtin_times:
367                                 r *= c;
368                                 break;
369                         case builtin_divide:
370                                 r /= c;
371                                 break;
372 #if 0
373                         case builtin_quotient:
374                                 if (c == 0)
375                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
376                                 if (r % c != 0 && (c < 0) != (r < 0))
377                                         r = r / c - 1;
378                                 else
379                                         r = r / c;
380                                 break;
381                         case builtin_remainder:
382                                 if (c == 0)
383                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
384                                 r %= c;
385                                 break;
386                         case builtin_modulo:
387                                 if (c == 0)
388                                         return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
389                                 r %= c;
390                                 if ((r < 0) != (c < 0))
391                                         r += c;
392                                 break;
393 #endif
394                         default:
395                                 break;
396                         }
397                         ret = ao_lisp_float_get(r);
398                 }
399
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)));
403                 else
404                         return ao_lisp_error(AO_LISP_INVALID, "invalid args");
405         }
406         return ret;
407 }
408
409 ao_poly
410 ao_lisp_do_plus(struct ao_lisp_cons *cons)
411 {
412         return ao_lisp_math(cons, builtin_plus);
413 }
414
415 ao_poly
416 ao_lisp_do_minus(struct ao_lisp_cons *cons)
417 {
418         return ao_lisp_math(cons, builtin_minus);
419 }
420
421 ao_poly
422 ao_lisp_do_times(struct ao_lisp_cons *cons)
423 {
424         return ao_lisp_math(cons, builtin_times);
425 }
426
427 ao_poly
428 ao_lisp_do_divide(struct ao_lisp_cons *cons)
429 {
430         return ao_lisp_math(cons, builtin_divide);
431 }
432
433 ao_poly
434 ao_lisp_do_quotient(struct ao_lisp_cons *cons)
435 {
436         return ao_lisp_math(cons, builtin_quotient);
437 }
438
439 ao_poly
440 ao_lisp_do_modulo(struct ao_lisp_cons *cons)
441 {
442         return ao_lisp_math(cons, builtin_modulo);
443 }
444
445 ao_poly
446 ao_lisp_do_remainder(struct ao_lisp_cons *cons)
447 {
448         return ao_lisp_math(cons, builtin_remainder);
449 }
450
451 ao_poly
452 ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
453 {
454         ao_poly left;
455
456         if (!cons)
457                 return _ao_lisp_bool_true;
458
459         left = cons->car;
460         for (cons = ao_lisp_cons_cdr(cons); cons; cons = ao_lisp_cons_cdr(cons)) {
461                 ao_poly right = cons->car;
462
463                 if (op == builtin_equal) {
464                         if (left != right)
465                                 return _ao_lisp_bool_false;
466                 } else {
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);
472
473                                 switch (op) {
474                                 case builtin_less:
475                                         if (!(l < r))
476                                                 return _ao_lisp_bool_false;
477                                         break;
478                                 case builtin_greater:
479                                         if (!(l > r))
480                                                 return _ao_lisp_bool_false;
481                                         break;
482                                 case builtin_less_equal:
483                                         if (!(l <= r))
484                                                 return _ao_lisp_bool_false;
485                                         break;
486                                 case builtin_greater_equal:
487                                         if (!(l >= r))
488                                                 return _ao_lisp_bool_false;
489                                         break;
490                                 default:
491                                         break;
492                                 }
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));
496                                 switch (op) {
497                                 case builtin_less:
498                                         if (!(c < 0))
499                                                 return _ao_lisp_bool_false;
500                                         break;
501                                 case builtin_greater:
502                                         if (!(c > 0))
503                                                 return _ao_lisp_bool_false;
504                                         break;
505                                 case builtin_less_equal:
506                                         if (!(c <= 0))
507                                                 return _ao_lisp_bool_false;
508                                         break;
509                                 case builtin_greater_equal:
510                                         if (!(c >= 0))
511                                                 return _ao_lisp_bool_false;
512                                         break;
513                                 default:
514                                         break;
515                                 }
516                         }
517                 }
518                 left = right;
519         }
520         return _ao_lisp_bool_true;
521 }
522
523 ao_poly
524 ao_lisp_do_equal(struct ao_lisp_cons *cons)
525 {
526         return ao_lisp_compare(cons, builtin_equal);
527 }
528
529 ao_poly
530 ao_lisp_do_less(struct ao_lisp_cons *cons)
531 {
532         return ao_lisp_compare(cons, builtin_less);
533 }
534
535 ao_poly
536 ao_lisp_do_greater(struct ao_lisp_cons *cons)
537 {
538         return ao_lisp_compare(cons, builtin_greater);
539 }
540
541 ao_poly
542 ao_lisp_do_less_equal(struct ao_lisp_cons *cons)
543 {
544         return ao_lisp_compare(cons, builtin_less_equal);
545 }
546
547 ao_poly
548 ao_lisp_do_greater_equal(struct ao_lisp_cons *cons)
549 {
550         return ao_lisp_compare(cons, builtin_greater_equal);
551 }
552
553 ao_poly
554 ao_lisp_do_list_to_string(struct ao_lisp_cons *cons)
555 {
556         if (!ao_lisp_check_argc(_ao_lisp_atom_list2d3estring, cons, 1, 1))
557                 return AO_LISP_NIL;
558         if (!ao_lisp_check_argt(_ao_lisp_atom_list2d3estring, cons, 0, AO_LISP_CONS, 1))
559                 return AO_LISP_NIL;
560         return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)));
561 }
562
563 ao_poly
564 ao_lisp_do_string_to_list(struct ao_lisp_cons *cons)
565 {
566         if (!ao_lisp_check_argc(_ao_lisp_atom_string2d3elist, cons, 1, 1))
567                 return AO_LISP_NIL;
568         if (!ao_lisp_check_argt(_ao_lisp_atom_string2d3elist, cons, 0, AO_LISP_STRING, 0))
569                 return AO_LISP_NIL;
570         return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0)));
571 }
572
573 ao_poly
574 ao_lisp_do_flush_output(struct ao_lisp_cons *cons)
575 {
576         if (!ao_lisp_check_argc(_ao_lisp_atom_flush2doutput, cons, 0, 0))
577                 return AO_LISP_NIL;
578         ao_lisp_os_flush();
579         return _ao_lisp_bool_true;
580 }
581
582 ao_poly
583 ao_lisp_do_led(struct ao_lisp_cons *cons)
584 {
585         ao_poly led;
586         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
587                 return AO_LISP_NIL;
588         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
589                 return AO_LISP_NIL;
590         led = ao_lisp_arg(cons, 0);
591         ao_lisp_os_led(ao_lisp_poly_int(led));
592         return led;
593 }
594
595 ao_poly
596 ao_lisp_do_delay(struct ao_lisp_cons *cons)
597 {
598         ao_poly delay;
599         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
600                 return AO_LISP_NIL;
601         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
602                 return AO_LISP_NIL;
603         delay = ao_lisp_arg(cons, 0);
604         ao_lisp_os_delay(ao_lisp_poly_int(delay));
605         return delay;
606 }
607
608 ao_poly
609 ao_lisp_do_eval(struct ao_lisp_cons *cons)
610 {
611         if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1))
612                 return AO_LISP_NIL;
613         ao_lisp_stack->state = eval_sexpr;
614         return cons->car;
615 }
616
617 ao_poly
618 ao_lisp_do_apply(struct ao_lisp_cons *cons)
619 {
620         if (!ao_lisp_check_argc(_ao_lisp_atom_apply, cons, 2, INT_MAX))
621                 return AO_LISP_NIL;
622         ao_lisp_stack->state = eval_apply;
623         return ao_lisp_cons_poly(cons);
624 }
625
626 ao_poly
627 ao_lisp_do_read(struct ao_lisp_cons *cons)
628 {
629         if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0))
630                 return AO_LISP_NIL;
631         return ao_lisp_read();
632 }
633
634 ao_poly
635 ao_lisp_do_collect(struct ao_lisp_cons *cons)
636 {
637         int     free;
638         (void) cons;
639         free = ao_lisp_collect(AO_LISP_COLLECT_FULL);
640         return ao_lisp_int_poly(free);
641 }
642
643 ao_poly
644 ao_lisp_do_nullp(struct ao_lisp_cons *cons)
645 {
646         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
647                 return AO_LISP_NIL;
648         if (ao_lisp_arg(cons, 0) == AO_LISP_NIL)
649                 return _ao_lisp_bool_true;
650         else
651                 return _ao_lisp_bool_false;
652 }
653
654 ao_poly
655 ao_lisp_do_not(struct ao_lisp_cons *cons)
656 {
657         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
658                 return AO_LISP_NIL;
659         if (ao_lisp_arg(cons, 0) == _ao_lisp_bool_false)
660                 return _ao_lisp_bool_true;
661         else
662                 return _ao_lisp_bool_false;
663 }
664
665 static ao_poly
666 ao_lisp_do_typep(int type, struct ao_lisp_cons *cons)
667 {
668         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
669                 return AO_LISP_NIL;
670         if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == type)
671                 return _ao_lisp_bool_true;
672         return _ao_lisp_bool_false;
673 }
674
675 ao_poly
676 ao_lisp_do_pairp(struct ao_lisp_cons *cons)
677 {
678         return ao_lisp_do_typep(AO_LISP_CONS, cons);
679 }
680
681 ao_poly
682 ao_lisp_do_integerp(struct ao_lisp_cons *cons)
683 {
684         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
685                 return AO_LISP_NIL;
686         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
687         case AO_LISP_INT:
688         case AO_LISP_BIGINT:
689                 return _ao_lisp_bool_true;
690         default:
691                 return _ao_lisp_bool_false;
692         }
693 }
694
695 ao_poly
696 ao_lisp_do_numberp(struct ao_lisp_cons *cons)
697 {
698         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
699                 return AO_LISP_NIL;
700         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
701         case AO_LISP_INT:
702         case AO_LISP_BIGINT:
703         case AO_LISP_FLOAT:
704                 return _ao_lisp_bool_true;
705         default:
706                 return _ao_lisp_bool_false;
707         }
708 }
709
710 ao_poly
711 ao_lisp_do_stringp(struct ao_lisp_cons *cons)
712 {
713         return ao_lisp_do_typep(AO_LISP_STRING, cons);
714 }
715
716 ao_poly
717 ao_lisp_do_symbolp(struct ao_lisp_cons *cons)
718 {
719         return ao_lisp_do_typep(AO_LISP_ATOM, cons);
720 }
721
722 ao_poly
723 ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
724 {
725         return ao_lisp_do_typep(AO_LISP_BOOL, cons);
726 }
727
728 ao_poly
729 ao_lisp_do_procedurep(struct ao_lisp_cons *cons)
730 {
731         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
732                 return AO_LISP_NIL;
733         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
734         case AO_LISP_BUILTIN:
735         case AO_LISP_LAMBDA:
736                 return _ao_lisp_bool_true;
737         default:
738         return _ao_lisp_bool_false;
739         }
740 }
741
742 /* This one is special -- a list is either nil or
743  * a 'proper' list with only cons cells
744  */
745 ao_poly
746 ao_lisp_do_listp(struct ao_lisp_cons *cons)
747 {
748         ao_poly v;
749         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
750                 return AO_LISP_NIL;
751         v = ao_lisp_arg(cons, 0);
752         for (;;) {
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;
758         }
759 }
760
761 ao_poly
762 ao_lisp_do_set_car(struct ao_lisp_cons *cons)
763 {
764         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
765                 return AO_LISP_NIL;
766         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
767                 return AO_LISP_NIL;
768         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
769 }
770
771 ao_poly
772 ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
773 {
774         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
775                 return AO_LISP_NIL;
776         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
777                 return AO_LISP_NIL;
778         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
779 }
780
781 ao_poly
782 ao_lisp_do_symbol_to_string(struct ao_lisp_cons *cons)
783 {
784         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
785                 return AO_LISP_NIL;
786         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_ATOM, 0))
787                 return AO_LISP_NIL;
788         return ao_lisp_string_poly(ao_lisp_string_copy(ao_lisp_poly_atom(ao_lisp_arg(cons, 0))->name));
789 }
790
791 ao_poly
792 ao_lisp_do_string_to_symbol(struct ao_lisp_cons *cons)
793 {
794         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
795                 return AO_LISP_NIL;
796         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_STRING, 0))
797                 return AO_LISP_NIL;
798
799         return ao_lisp_atom_poly(ao_lisp_atom_intern(ao_lisp_poly_string(ao_lisp_arg(cons, 0))));
800 }
801
802 ao_poly
803 ao_lisp_do_read_char(struct ao_lisp_cons *cons)
804 {
805         int     c;
806         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
807                 return AO_LISP_NIL;
808         c = getchar();
809         return ao_lisp_int_poly(c);
810 }
811
812 ao_poly
813 ao_lisp_do_write_char(struct ao_lisp_cons *cons)
814 {
815         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
816                 return AO_LISP_NIL;
817         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
818                 return AO_LISP_NIL;
819         putchar(ao_lisp_poly_integer(ao_lisp_arg(cons, 0)));
820         return _ao_lisp_bool_true;
821 }
822
823 ao_poly
824 ao_lisp_do_exit(struct ao_lisp_cons *cons)
825 {
826         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
827                 return AO_LISP_NIL;
828         ao_lisp_exception |= AO_LISP_EXIT;
829         return _ao_lisp_bool_true;
830 }
831
832 ao_poly
833 ao_lisp_do_current_jiffy(struct ao_lisp_cons *cons)
834 {
835         int     jiffy;
836
837         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
838                 return AO_LISP_NIL;
839         jiffy = ao_lisp_os_jiffy();
840         return (ao_lisp_int_poly(jiffy));
841 }
842
843 ao_poly
844 ao_lisp_do_current_second(struct ao_lisp_cons *cons)
845 {
846         int     second;
847
848         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
849                 return AO_LISP_NIL;
850         second = ao_lisp_os_jiffy() / AO_LISP_JIFFIES_PER_SECOND;
851         return (ao_lisp_int_poly(second));
852 }
853
854 ao_poly
855 ao_lisp_do_jiffies_per_second(struct ao_lisp_cons *cons)
856 {
857         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
858                 return AO_LISP_NIL;
859         return (ao_lisp_int_poly(AO_LISP_JIFFIES_PER_SECOND));
860 }
861
862 #define AO_LISP_BUILTIN_FUNCS
863 #include "ao_lisp_builtin.h"