altos/lisp: Fix pairp builtin
[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         ao_poly v;
679         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
680                 return AO_LISP_NIL;
681         v = ao_lisp_arg(cons, 0);
682         if (v != AO_LISP_NIL && ao_lisp_poly_type(v) == AO_LISP_CONS)
683                 return _ao_lisp_bool_true;
684         return _ao_lisp_bool_false;
685 }
686
687 ao_poly
688 ao_lisp_do_integerp(struct ao_lisp_cons *cons)
689 {
690         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
691                 return AO_LISP_NIL;
692         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
693         case AO_LISP_INT:
694         case AO_LISP_BIGINT:
695                 return _ao_lisp_bool_true;
696         default:
697                 return _ao_lisp_bool_false;
698         }
699 }
700
701 ao_poly
702 ao_lisp_do_numberp(struct ao_lisp_cons *cons)
703 {
704         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
705                 return AO_LISP_NIL;
706         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
707         case AO_LISP_INT:
708         case AO_LISP_BIGINT:
709         case AO_LISP_FLOAT:
710                 return _ao_lisp_bool_true;
711         default:
712                 return _ao_lisp_bool_false;
713         }
714 }
715
716 ao_poly
717 ao_lisp_do_stringp(struct ao_lisp_cons *cons)
718 {
719         return ao_lisp_do_typep(AO_LISP_STRING, cons);
720 }
721
722 ao_poly
723 ao_lisp_do_symbolp(struct ao_lisp_cons *cons)
724 {
725         return ao_lisp_do_typep(AO_LISP_ATOM, cons);
726 }
727
728 ao_poly
729 ao_lisp_do_booleanp(struct ao_lisp_cons *cons)
730 {
731         return ao_lisp_do_typep(AO_LISP_BOOL, cons);
732 }
733
734 ao_poly
735 ao_lisp_do_procedurep(struct ao_lisp_cons *cons)
736 {
737         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
738                 return AO_LISP_NIL;
739         switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
740         case AO_LISP_BUILTIN:
741         case AO_LISP_LAMBDA:
742                 return _ao_lisp_bool_true;
743         default:
744         return _ao_lisp_bool_false;
745         }
746 }
747
748 /* This one is special -- a list is either nil or
749  * a 'proper' list with only cons cells
750  */
751 ao_poly
752 ao_lisp_do_listp(struct ao_lisp_cons *cons)
753 {
754         ao_poly v;
755         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
756                 return AO_LISP_NIL;
757         v = ao_lisp_arg(cons, 0);
758         for (;;) {
759                 if (v == AO_LISP_NIL)
760                         return _ao_lisp_bool_true;
761                 if (ao_lisp_poly_type(v) != AO_LISP_CONS)
762                         return _ao_lisp_bool_false;
763                 v = ao_lisp_poly_cons(v)->cdr;
764         }
765 }
766
767 ao_poly
768 ao_lisp_do_set_car(struct ao_lisp_cons *cons)
769 {
770         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
771                 return AO_LISP_NIL;
772         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
773                 return AO_LISP_NIL;
774         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->car = ao_lisp_arg(cons, 1);
775 }
776
777 ao_poly
778 ao_lisp_do_set_cdr(struct ao_lisp_cons *cons)
779 {
780         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 2, 2))
781                 return AO_LISP_NIL;
782         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_CONS, 0))
783                 return AO_LISP_NIL;
784         return ao_lisp_poly_cons(ao_lisp_arg(cons, 0))->cdr = ao_lisp_arg(cons, 1);
785 }
786
787 ao_poly
788 ao_lisp_do_symbol_to_string(struct ao_lisp_cons *cons)
789 {
790         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
791                 return AO_LISP_NIL;
792         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_ATOM, 0))
793                 return AO_LISP_NIL;
794         return ao_lisp_string_poly(ao_lisp_string_copy(ao_lisp_poly_atom(ao_lisp_arg(cons, 0))->name));
795 }
796
797 ao_poly
798 ao_lisp_do_string_to_symbol(struct ao_lisp_cons *cons)
799 {
800         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
801                 return AO_LISP_NIL;
802         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_STRING, 0))
803                 return AO_LISP_NIL;
804
805         return ao_lisp_atom_poly(ao_lisp_atom_intern(ao_lisp_poly_string(ao_lisp_arg(cons, 0))));
806 }
807
808 ao_poly
809 ao_lisp_do_read_char(struct ao_lisp_cons *cons)
810 {
811         int     c;
812         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
813                 return AO_LISP_NIL;
814         c = getchar();
815         return ao_lisp_int_poly(c);
816 }
817
818 ao_poly
819 ao_lisp_do_write_char(struct ao_lisp_cons *cons)
820 {
821         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
822                 return AO_LISP_NIL;
823         if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0))
824                 return AO_LISP_NIL;
825         putchar(ao_lisp_poly_integer(ao_lisp_arg(cons, 0)));
826         return _ao_lisp_bool_true;
827 }
828
829 ao_poly
830 ao_lisp_do_exit(struct ao_lisp_cons *cons)
831 {
832         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
833                 return AO_LISP_NIL;
834         ao_lisp_exception |= AO_LISP_EXIT;
835         return _ao_lisp_bool_true;
836 }
837
838 ao_poly
839 ao_lisp_do_current_jiffy(struct ao_lisp_cons *cons)
840 {
841         int     jiffy;
842
843         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
844                 return AO_LISP_NIL;
845         jiffy = ao_lisp_os_jiffy();
846         return (ao_lisp_int_poly(jiffy));
847 }
848
849 ao_poly
850 ao_lisp_do_current_second(struct ao_lisp_cons *cons)
851 {
852         int     second;
853
854         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
855                 return AO_LISP_NIL;
856         second = ao_lisp_os_jiffy() / AO_LISP_JIFFIES_PER_SECOND;
857         return (ao_lisp_int_poly(second));
858 }
859
860 ao_poly
861 ao_lisp_do_jiffies_per_second(struct ao_lisp_cons *cons)
862 {
863         if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 0, 0))
864                 return AO_LISP_NIL;
865         return (ao_lisp_int_poly(AO_LISP_JIFFIES_PER_SECOND));
866 }
867
868 #define AO_LISP_BUILTIN_FUNCS
869 #include "ao_lisp_builtin.h"