Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
[fw/altos] / src / scheme / ao_scheme_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_scheme.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_scheme_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_scheme_type ao_scheme_builtin_type = {
39         .size = builtin_size,
40         .mark = builtin_mark,
41         .move = builtin_move
42 };
43
44 #ifdef AO_SCHEME_MAKE_CONST
45
46 #define AO_SCHEME_BUILTIN_CASENAME
47 #include "ao_scheme_builtin.h"
48
49 char *ao_scheme_args_name(uint8_t args) {
50         args &= AO_SCHEME_FUNC_MASK;
51         switch (args) {
52         case AO_SCHEME_FUNC_LAMBDA: return ao_scheme_poly_atom(_ao_scheme_atom_lambda)->name;
53         case AO_SCHEME_FUNC_NLAMBDA: return ao_scheme_poly_atom(_ao_scheme_atom_nlambda)->name;
54         case AO_SCHEME_FUNC_MACRO: return ao_scheme_poly_atom(_ao_scheme_atom_macro)->name;
55         default: return "???";
56         }
57 }
58 #else
59
60 #define AO_SCHEME_BUILTIN_ARRAYNAME
61 #include "ao_scheme_builtin.h"
62
63 static char *
64 ao_scheme_builtin_name(enum ao_scheme_builtin_id b) {
65         if (b < _builtin_last)
66                 return ao_scheme_poly_atom(builtin_names[b])->name;
67         return "???";
68 }
69
70 static const ao_poly ao_scheme_args_atoms[] = {
71         [AO_SCHEME_FUNC_LAMBDA] = _ao_scheme_atom_lambda,
72         [AO_SCHEME_FUNC_NLAMBDA] = _ao_scheme_atom_nlambda,
73         [AO_SCHEME_FUNC_MACRO] = _ao_scheme_atom_macro,
74 };
75
76 char *
77 ao_scheme_args_name(uint8_t args)
78 {
79         args &= AO_SCHEME_FUNC_MASK;
80         if (args < sizeof ao_scheme_args_atoms / sizeof ao_scheme_args_atoms[0])
81                 return ao_scheme_poly_atom(ao_scheme_args_atoms[args])->name;
82         return "(unknown)";
83 }
84 #endif
85
86 void
87 ao_scheme_builtin_write(ao_poly b)
88 {
89         struct ao_scheme_builtin *builtin = ao_scheme_poly_builtin(b);
90         printf("%s", ao_scheme_builtin_name(builtin->func));
91 }
92
93 ao_poly
94 ao_scheme_check_argc(ao_poly name, struct ao_scheme_cons *cons, int min, int max)
95 {
96         int     argc = 0;
97
98         while (cons && argc <= max) {
99                 argc++;
100                 cons = ao_scheme_cons_cdr(cons);
101         }
102         if (argc < min || argc > max)
103                 return ao_scheme_error(AO_SCHEME_INVALID, "%s: invalid arg count", ao_scheme_poly_atom(name)->name);
104         return _ao_scheme_bool_true;
105 }
106
107 ao_poly
108 ao_scheme_arg(struct ao_scheme_cons *cons, int argc)
109 {
110         if (!cons)
111                 return AO_SCHEME_NIL;
112         while (argc--) {
113                 if (!cons)
114                         return AO_SCHEME_NIL;
115                 cons = ao_scheme_cons_cdr(cons);
116         }
117         return cons->car;
118 }
119
120 ao_poly
121 ao_scheme_check_argt(ao_poly name, struct ao_scheme_cons *cons, int argc, int type, int nil_ok)
122 {
123         ao_poly car = ao_scheme_arg(cons, argc);
124
125         if ((!car && !nil_ok) || ao_scheme_poly_type(car) != type)
126                 return ao_scheme_error(AO_SCHEME_INVALID, "%s: arg %d invalid type %v", ao_scheme_poly_atom(name)->name, argc, car);
127         return _ao_scheme_bool_true;
128 }
129
130 ao_poly
131 ao_scheme_do_car(struct ao_scheme_cons *cons)
132 {
133         if (!ao_scheme_check_argc(_ao_scheme_atom_car, cons, 1, 1))
134                 return AO_SCHEME_NIL;
135         if (!ao_scheme_check_argt(_ao_scheme_atom_car, cons, 0, AO_SCHEME_CONS, 0))
136                 return AO_SCHEME_NIL;
137         return ao_scheme_poly_cons(cons->car)->car;
138 }
139
140 ao_poly
141 ao_scheme_do_cdr(struct ao_scheme_cons *cons)
142 {
143         if (!ao_scheme_check_argc(_ao_scheme_atom_cdr, cons, 1, 1))
144                 return AO_SCHEME_NIL;
145         if (!ao_scheme_check_argt(_ao_scheme_atom_cdr, cons, 0, AO_SCHEME_CONS, 0))
146                 return AO_SCHEME_NIL;
147         return ao_scheme_poly_cons(cons->car)->cdr;
148 }
149
150 ao_poly
151 ao_scheme_do_cons(struct ao_scheme_cons *cons)
152 {
153         ao_poly car, cdr;
154         if(!ao_scheme_check_argc(_ao_scheme_atom_cons, cons, 2, 2))
155                 return AO_SCHEME_NIL;
156         car = ao_scheme_arg(cons, 0);
157         cdr = ao_scheme_arg(cons, 1);
158         return ao_scheme__cons(car, cdr);
159 }
160
161 ao_poly
162 ao_scheme_do_last(struct ao_scheme_cons *cons)
163 {
164         struct ao_scheme_cons   *list;
165         if (!ao_scheme_check_argc(_ao_scheme_atom_last, cons, 1, 1))
166                 return AO_SCHEME_NIL;
167         if (!ao_scheme_check_argt(_ao_scheme_atom_last, cons, 0, AO_SCHEME_CONS, 1))
168                 return AO_SCHEME_NIL;
169         for (list = ao_scheme_poly_cons(ao_scheme_arg(cons, 0));
170              list;
171              list = ao_scheme_cons_cdr(list))
172         {
173                 if (!list->cdr)
174                         return list->car;
175         }
176         return AO_SCHEME_NIL;
177 }
178
179 ao_poly
180 ao_scheme_do_length(struct ao_scheme_cons *cons)
181 {
182         if (!ao_scheme_check_argc(_ao_scheme_atom_length, cons, 1, 1))
183                 return AO_SCHEME_NIL;
184         if (!ao_scheme_check_argt(_ao_scheme_atom_length, cons, 0, AO_SCHEME_CONS, 1))
185                 return AO_SCHEME_NIL;
186         return ao_scheme_int_poly(ao_scheme_cons_length(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
187 }
188
189 ao_poly
190 ao_scheme_do_quote(struct ao_scheme_cons *cons)
191 {
192         if (!ao_scheme_check_argc(_ao_scheme_atom_quote, cons, 1, 1))
193                 return AO_SCHEME_NIL;
194         return ao_scheme_arg(cons, 0);
195 }
196
197 ao_poly
198 ao_scheme_do_set(struct ao_scheme_cons *cons)
199 {
200         if (!ao_scheme_check_argc(_ao_scheme_atom_set, cons, 2, 2))
201                 return AO_SCHEME_NIL;
202         if (!ao_scheme_check_argt(_ao_scheme_atom_set, cons, 0, AO_SCHEME_ATOM, 0))
203                 return AO_SCHEME_NIL;
204
205         return ao_scheme_atom_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
206 }
207
208 ao_poly
209 ao_scheme_do_def(struct ao_scheme_cons *cons)
210 {
211         if (!ao_scheme_check_argc(_ao_scheme_atom_def, cons, 2, 2))
212                 return AO_SCHEME_NIL;
213         if (!ao_scheme_check_argt(_ao_scheme_atom_def, cons, 0, AO_SCHEME_ATOM, 0))
214                 return AO_SCHEME_NIL;
215
216         return ao_scheme_atom_def(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
217 }
218
219 ao_poly
220 ao_scheme_do_setq(struct ao_scheme_cons *cons)
221 {
222         ao_poly name;
223         if (!ao_scheme_check_argc(_ao_scheme_atom_set21, cons, 2, 2))
224                 return AO_SCHEME_NIL;
225         name = cons->car;
226         if (ao_scheme_poly_type(name) != AO_SCHEME_ATOM)
227                 return ao_scheme_error(AO_SCHEME_INVALID, "set! of non-atom %v", name);
228         if (!ao_scheme_atom_ref(name, NULL))
229                 return ao_scheme_error(AO_SCHEME_INVALID, "atom %v not defined", name);
230         return ao_scheme__cons(_ao_scheme_atom_set,
231                              ao_scheme__cons(ao_scheme__cons(_ao_scheme_atom_quote,
232                                                          ao_scheme__cons(name, AO_SCHEME_NIL)),
233                                            cons->cdr));
234 }
235
236 ao_poly
237 ao_scheme_do_cond(struct ao_scheme_cons *cons)
238 {
239         ao_scheme_set_cond(cons);
240         return AO_SCHEME_NIL;
241 }
242
243 ao_poly
244 ao_scheme_do_begin(struct ao_scheme_cons *cons)
245 {
246         ao_scheme_stack->state = eval_begin;
247         ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
248         return AO_SCHEME_NIL;
249 }
250
251 ao_poly
252 ao_scheme_do_while(struct ao_scheme_cons *cons)
253 {
254         ao_scheme_stack->state = eval_while;
255         ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
256         return AO_SCHEME_NIL;
257 }
258
259 ao_poly
260 ao_scheme_do_write(struct ao_scheme_cons *cons)
261 {
262         ao_poly val = AO_SCHEME_NIL;
263         while (cons) {
264                 val = cons->car;
265                 ao_scheme_poly_write(val);
266                 cons = ao_scheme_cons_cdr(cons);
267                 if (cons)
268                         printf(" ");
269         }
270         return _ao_scheme_bool_true;
271 }
272
273 ao_poly
274 ao_scheme_do_display(struct ao_scheme_cons *cons)
275 {
276         ao_poly val = AO_SCHEME_NIL;
277         while (cons) {
278                 val = cons->car;
279                 ao_scheme_poly_display(val);
280                 cons = ao_scheme_cons_cdr(cons);
281         }
282         return _ao_scheme_bool_true;
283 }
284
285 ao_poly
286 ao_scheme_math(struct ao_scheme_cons *orig_cons, enum ao_scheme_builtin_id op)
287 {
288         struct ao_scheme_cons *cons = cons;
289         ao_poly ret = AO_SCHEME_NIL;
290
291         for (cons = orig_cons; cons; cons = ao_scheme_cons_cdr(cons)) {
292                 ao_poly         car = cons->car;
293                 uint8_t         rt = ao_scheme_poly_type(ret);
294                 uint8_t         ct = ao_scheme_poly_type(car);
295
296                 if (cons == orig_cons) {
297                         ret = car;
298                         if (cons->cdr == AO_SCHEME_NIL) {
299                                 switch (op) {
300                                 case builtin_minus:
301                                         if (ao_scheme_integer_typep(ct))
302                                                 ret = ao_scheme_integer_poly(-ao_scheme_poly_integer(ret));
303                                         else if (ct == AO_SCHEME_FLOAT)
304                                                 ret = ao_scheme_float_get(-ao_scheme_poly_number(ret));
305                                         break;
306                                 case builtin_divide:
307                                         if (ao_scheme_integer_typep(ct) && ao_scheme_poly_integer(ret) == 1)
308                                                 ;
309                                         else if (ao_scheme_number_typep(ct)) {
310                                                 float   v = ao_scheme_poly_number(ret);
311                                                 ret = ao_scheme_float_get(1/v);
312                                         }
313                                         break;
314                                 default:
315                                         break;
316                                 }
317                         }
318                 } else if (ao_scheme_integer_typep(rt) && ao_scheme_integer_typep(ct)) {
319                         int32_t r = ao_scheme_poly_integer(ret);
320                         int32_t c = ao_scheme_poly_integer(car);
321                         int64_t t;
322
323                         switch(op) {
324                         case builtin_plus:
325                                 r += c;
326                         check_overflow:
327                                 if (r < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < r)
328                                         goto inexact;
329                                 break;
330                         case builtin_minus:
331                                 r -= c;
332                                 goto check_overflow;
333                                 break;
334                         case builtin_times:
335                                 t = (int64_t) r * (int64_t) c;
336                                 if (t < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < t)
337                                         goto inexact;
338                                 r = (int32_t) t;
339                                 break;
340                         case builtin_divide:
341                                 if (c != 0 && (r % c) == 0)
342                                         r /= c;
343                                 else
344                                         goto inexact;
345                                 break;
346                         case builtin_quotient:
347                                 if (c == 0)
348                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "quotient by zero");
349                                 if (r % c != 0 && (c < 0) != (r < 0))
350                                         r = r / c - 1;
351                                 else
352                                         r = r / c;
353                                 break;
354                         case builtin_remainder:
355                                 if (c == 0)
356                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "remainder by zero");
357                                 r %= c;
358                                 break;
359                         case builtin_modulo:
360                                 if (c == 0)
361                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "modulo by zero");
362                                 r %= c;
363                                 if ((r < 0) != (c < 0))
364                                         r += c;
365                                 break;
366                         default:
367                                 break;
368                         }
369                         ret = ao_scheme_integer_poly(r);
370                 } else if (ao_scheme_number_typep(rt) && ao_scheme_number_typep(ct)) {
371                         float r, c;
372                 inexact:
373                         r = ao_scheme_poly_number(ret);
374                         c = ao_scheme_poly_number(car);
375                         switch(op) {
376                         case builtin_plus:
377                                 r += c;
378                                 break;
379                         case builtin_minus:
380                                 r -= c;
381                                 break;
382                         case builtin_times:
383                                 r *= c;
384                                 break;
385                         case builtin_divide:
386                                 r /= c;
387                                 break;
388                         case builtin_quotient:
389                         case builtin_remainder:
390                         case builtin_modulo:
391                                 return ao_scheme_error(AO_SCHEME_INVALID, "non-integer value in integer divide");
392                         default:
393                                 break;
394                         }
395                         ret = ao_scheme_float_get(r);
396                 }
397
398                 else if (rt == AO_SCHEME_STRING && ct == AO_SCHEME_STRING && op == builtin_plus)
399                         ret = ao_scheme_string_poly(ao_scheme_string_cat(ao_scheme_poly_string(ret),
400                                                                      ao_scheme_poly_string(car)));
401                 else
402                         return ao_scheme_error(AO_SCHEME_INVALID, "invalid args");
403         }
404         return ret;
405 }
406
407 ao_poly
408 ao_scheme_do_plus(struct ao_scheme_cons *cons)
409 {
410         return ao_scheme_math(cons, builtin_plus);
411 }
412
413 ao_poly
414 ao_scheme_do_minus(struct ao_scheme_cons *cons)
415 {
416         return ao_scheme_math(cons, builtin_minus);
417 }
418
419 ao_poly
420 ao_scheme_do_times(struct ao_scheme_cons *cons)
421 {
422         return ao_scheme_math(cons, builtin_times);
423 }
424
425 ao_poly
426 ao_scheme_do_divide(struct ao_scheme_cons *cons)
427 {
428         return ao_scheme_math(cons, builtin_divide);
429 }
430
431 ao_poly
432 ao_scheme_do_quotient(struct ao_scheme_cons *cons)
433 {
434         return ao_scheme_math(cons, builtin_quotient);
435 }
436
437 ao_poly
438 ao_scheme_do_modulo(struct ao_scheme_cons *cons)
439 {
440         return ao_scheme_math(cons, builtin_modulo);
441 }
442
443 ao_poly
444 ao_scheme_do_remainder(struct ao_scheme_cons *cons)
445 {
446         return ao_scheme_math(cons, builtin_remainder);
447 }
448
449 ao_poly
450 ao_scheme_compare(struct ao_scheme_cons *cons, enum ao_scheme_builtin_id op)
451 {
452         ao_poly left;
453
454         if (!cons)
455                 return _ao_scheme_bool_true;
456
457         left = cons->car;
458         for (cons = ao_scheme_cons_cdr(cons); cons; cons = ao_scheme_cons_cdr(cons)) {
459                 ao_poly right = cons->car;
460
461                 if (op == builtin_equal) {
462                         if (left != right)
463                                 return _ao_scheme_bool_false;
464                 } else {
465                         uint8_t lt = ao_scheme_poly_type(left);
466                         uint8_t rt = ao_scheme_poly_type(right);
467                         if (ao_scheme_integer_typep(lt) && ao_scheme_integer_typep(rt)) {
468                                 int32_t l = ao_scheme_poly_integer(left);
469                                 int32_t r = ao_scheme_poly_integer(right);
470
471                                 switch (op) {
472                                 case builtin_less:
473                                         if (!(l < r))
474                                                 return _ao_scheme_bool_false;
475                                         break;
476                                 case builtin_greater:
477                                         if (!(l > r))
478                                                 return _ao_scheme_bool_false;
479                                         break;
480                                 case builtin_less_equal:
481                                         if (!(l <= r))
482                                                 return _ao_scheme_bool_false;
483                                         break;
484                                 case builtin_greater_equal:
485                                         if (!(l >= r))
486                                                 return _ao_scheme_bool_false;
487                                         break;
488                                 default:
489                                         break;
490                                 }
491                         } else if (lt == AO_SCHEME_STRING && rt == AO_SCHEME_STRING) {
492                                 int c = strcmp(ao_scheme_poly_string(left),
493                                                ao_scheme_poly_string(right));
494                                 switch (op) {
495                                 case builtin_less:
496                                         if (!(c < 0))
497                                                 return _ao_scheme_bool_false;
498                                         break;
499                                 case builtin_greater:
500                                         if (!(c > 0))
501                                                 return _ao_scheme_bool_false;
502                                         break;
503                                 case builtin_less_equal:
504                                         if (!(c <= 0))
505                                                 return _ao_scheme_bool_false;
506                                         break;
507                                 case builtin_greater_equal:
508                                         if (!(c >= 0))
509                                                 return _ao_scheme_bool_false;
510                                         break;
511                                 default:
512                                         break;
513                                 }
514                         }
515                 }
516                 left = right;
517         }
518         return _ao_scheme_bool_true;
519 }
520
521 ao_poly
522 ao_scheme_do_equal(struct ao_scheme_cons *cons)
523 {
524         return ao_scheme_compare(cons, builtin_equal);
525 }
526
527 ao_poly
528 ao_scheme_do_less(struct ao_scheme_cons *cons)
529 {
530         return ao_scheme_compare(cons, builtin_less);
531 }
532
533 ao_poly
534 ao_scheme_do_greater(struct ao_scheme_cons *cons)
535 {
536         return ao_scheme_compare(cons, builtin_greater);
537 }
538
539 ao_poly
540 ao_scheme_do_less_equal(struct ao_scheme_cons *cons)
541 {
542         return ao_scheme_compare(cons, builtin_less_equal);
543 }
544
545 ao_poly
546 ao_scheme_do_greater_equal(struct ao_scheme_cons *cons)
547 {
548         return ao_scheme_compare(cons, builtin_greater_equal);
549 }
550
551 ao_poly
552 ao_scheme_do_list_to_string(struct ao_scheme_cons *cons)
553 {
554         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3estring, cons, 1, 1))
555                 return AO_SCHEME_NIL;
556         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3estring, cons, 0, AO_SCHEME_CONS, 1))
557                 return AO_SCHEME_NIL;
558         return ao_scheme_string_pack(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
559 }
560
561 ao_poly
562 ao_scheme_do_string_to_list(struct ao_scheme_cons *cons)
563 {
564         if (!ao_scheme_check_argc(_ao_scheme_atom_string2d3elist, cons, 1, 1))
565                 return AO_SCHEME_NIL;
566         if (!ao_scheme_check_argt(_ao_scheme_atom_string2d3elist, cons, 0, AO_SCHEME_STRING, 0))
567                 return AO_SCHEME_NIL;
568         return ao_scheme_string_unpack(ao_scheme_poly_string(ao_scheme_arg(cons, 0)));
569 }
570
571 ao_poly
572 ao_scheme_do_flush_output(struct ao_scheme_cons *cons)
573 {
574         if (!ao_scheme_check_argc(_ao_scheme_atom_flush2doutput, cons, 0, 0))
575                 return AO_SCHEME_NIL;
576         ao_scheme_os_flush();
577         return _ao_scheme_bool_true;
578 }
579
580 ao_poly
581 ao_scheme_do_led(struct ao_scheme_cons *cons)
582 {
583         ao_poly led;
584         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
585                 return AO_SCHEME_NIL;
586         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
587                 return AO_SCHEME_NIL;
588         led = ao_scheme_arg(cons, 0);
589         ao_scheme_os_led(ao_scheme_poly_int(led));
590         return led;
591 }
592
593 ao_poly
594 ao_scheme_do_delay(struct ao_scheme_cons *cons)
595 {
596         ao_poly delay;
597         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
598                 return AO_SCHEME_NIL;
599         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
600                 return AO_SCHEME_NIL;
601         delay = ao_scheme_arg(cons, 0);
602         ao_scheme_os_delay(ao_scheme_poly_int(delay));
603         return delay;
604 }
605
606 ao_poly
607 ao_scheme_do_eval(struct ao_scheme_cons *cons)
608 {
609         if (!ao_scheme_check_argc(_ao_scheme_atom_eval, cons, 1, 1))
610                 return AO_SCHEME_NIL;
611         ao_scheme_stack->state = eval_sexpr;
612         return cons->car;
613 }
614
615 ao_poly
616 ao_scheme_do_apply(struct ao_scheme_cons *cons)
617 {
618         if (!ao_scheme_check_argc(_ao_scheme_atom_apply, cons, 2, INT_MAX))
619                 return AO_SCHEME_NIL;
620         ao_scheme_stack->state = eval_apply;
621         return ao_scheme_cons_poly(cons);
622 }
623
624 ao_poly
625 ao_scheme_do_read(struct ao_scheme_cons *cons)
626 {
627         if (!ao_scheme_check_argc(_ao_scheme_atom_read, cons, 0, 0))
628                 return AO_SCHEME_NIL;
629         return ao_scheme_read();
630 }
631
632 ao_poly
633 ao_scheme_do_collect(struct ao_scheme_cons *cons)
634 {
635         int     free;
636         (void) cons;
637         free = ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
638         return ao_scheme_integer_poly(free);
639 }
640
641 ao_poly
642 ao_scheme_do_nullp(struct ao_scheme_cons *cons)
643 {
644         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
645                 return AO_SCHEME_NIL;
646         if (ao_scheme_arg(cons, 0) == AO_SCHEME_NIL)
647                 return _ao_scheme_bool_true;
648         else
649                 return _ao_scheme_bool_false;
650 }
651
652 ao_poly
653 ao_scheme_do_not(struct ao_scheme_cons *cons)
654 {
655         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
656                 return AO_SCHEME_NIL;
657         if (ao_scheme_arg(cons, 0) == _ao_scheme_bool_false)
658                 return _ao_scheme_bool_true;
659         else
660                 return _ao_scheme_bool_false;
661 }
662
663 static ao_poly
664 ao_scheme_do_typep(int type, struct ao_scheme_cons *cons)
665 {
666         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
667                 return AO_SCHEME_NIL;
668         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == type)
669                 return _ao_scheme_bool_true;
670         return _ao_scheme_bool_false;
671 }
672
673 ao_poly
674 ao_scheme_do_pairp(struct ao_scheme_cons *cons)
675 {
676         ao_poly v;
677         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
678                 return AO_SCHEME_NIL;
679         v = ao_scheme_arg(cons, 0);
680         if (v != AO_SCHEME_NIL && ao_scheme_poly_type(v) == AO_SCHEME_CONS)
681                 return _ao_scheme_bool_true;
682         return _ao_scheme_bool_false;
683 }
684
685 ao_poly
686 ao_scheme_do_integerp(struct ao_scheme_cons *cons)
687 {
688         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
689                 return AO_SCHEME_NIL;
690         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
691         case AO_SCHEME_INT:
692         case AO_SCHEME_BIGINT:
693                 return _ao_scheme_bool_true;
694         default:
695                 return _ao_scheme_bool_false;
696         }
697 }
698
699 ao_poly
700 ao_scheme_do_numberp(struct ao_scheme_cons *cons)
701 {
702         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
703                 return AO_SCHEME_NIL;
704         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
705         case AO_SCHEME_INT:
706         case AO_SCHEME_BIGINT:
707         case AO_SCHEME_FLOAT:
708                 return _ao_scheme_bool_true;
709         default:
710                 return _ao_scheme_bool_false;
711         }
712 }
713
714 ao_poly
715 ao_scheme_do_stringp(struct ao_scheme_cons *cons)
716 {
717         return ao_scheme_do_typep(AO_SCHEME_STRING, cons);
718 }
719
720 ao_poly
721 ao_scheme_do_symbolp(struct ao_scheme_cons *cons)
722 {
723         return ao_scheme_do_typep(AO_SCHEME_ATOM, cons);
724 }
725
726 ao_poly
727 ao_scheme_do_booleanp(struct ao_scheme_cons *cons)
728 {
729         return ao_scheme_do_typep(AO_SCHEME_BOOL, cons);
730 }
731
732 ao_poly
733 ao_scheme_do_procedurep(struct ao_scheme_cons *cons)
734 {
735         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
736                 return AO_SCHEME_NIL;
737         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
738         case AO_SCHEME_BUILTIN:
739         case AO_SCHEME_LAMBDA:
740                 return _ao_scheme_bool_true;
741         default:
742         return _ao_scheme_bool_false;
743         }
744 }
745
746 /* This one is special -- a list is either nil or
747  * a 'proper' list with only cons cells
748  */
749 ao_poly
750 ao_scheme_do_listp(struct ao_scheme_cons *cons)
751 {
752         ao_poly v;
753         if (!ao_scheme_check_argc(_ao_scheme_atom_list3f, cons, 1, 1))
754                 return AO_SCHEME_NIL;
755         v = ao_scheme_arg(cons, 0);
756         for (;;) {
757                 if (v == AO_SCHEME_NIL)
758                         return _ao_scheme_bool_true;
759                 if (ao_scheme_poly_type(v) != AO_SCHEME_CONS)
760                         return _ao_scheme_bool_false;
761                 v = ao_scheme_poly_cons(v)->cdr;
762         }
763 }
764
765 ao_poly
766 ao_scheme_do_set_car(struct ao_scheme_cons *cons)
767 {
768         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
769                 return AO_SCHEME_NIL;
770         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
771                 return AO_SCHEME_NIL;
772         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->car = ao_scheme_arg(cons, 1);
773 }
774
775 ao_poly
776 ao_scheme_do_set_cdr(struct ao_scheme_cons *cons)
777 {
778         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
779                 return AO_SCHEME_NIL;
780         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
781                 return AO_SCHEME_NIL;
782         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->cdr = ao_scheme_arg(cons, 1);
783 }
784
785 ao_poly
786 ao_scheme_do_symbol_to_string(struct ao_scheme_cons *cons)
787 {
788         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
789                 return AO_SCHEME_NIL;
790         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_ATOM, 0))
791                 return AO_SCHEME_NIL;
792         return ao_scheme_string_poly(ao_scheme_string_copy(ao_scheme_poly_atom(ao_scheme_arg(cons, 0))->name));
793 }
794
795 ao_poly
796 ao_scheme_do_string_to_symbol(struct ao_scheme_cons *cons)
797 {
798         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
799                 return AO_SCHEME_NIL;
800         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_STRING, 0))
801                 return AO_SCHEME_NIL;
802
803         return ao_scheme_atom_poly(ao_scheme_atom_intern(ao_scheme_poly_string(ao_scheme_arg(cons, 0))));
804 }
805
806 ao_poly
807 ao_scheme_do_read_char(struct ao_scheme_cons *cons)
808 {
809         int     c;
810         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
811                 return AO_SCHEME_NIL;
812         c = getchar();
813         return ao_scheme_int_poly(c);
814 }
815
816 ao_poly
817 ao_scheme_do_write_char(struct ao_scheme_cons *cons)
818 {
819         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
820                 return AO_SCHEME_NIL;
821         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
822                 return AO_SCHEME_NIL;
823         putchar(ao_scheme_poly_integer(ao_scheme_arg(cons, 0)));
824         return _ao_scheme_bool_true;
825 }
826
827 ao_poly
828 ao_scheme_do_exit(struct ao_scheme_cons *cons)
829 {
830         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
831                 return AO_SCHEME_NIL;
832         ao_scheme_exception |= AO_SCHEME_EXIT;
833         return _ao_scheme_bool_true;
834 }
835
836 ao_poly
837 ao_scheme_do_current_jiffy(struct ao_scheme_cons *cons)
838 {
839         int     jiffy;
840
841         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
842                 return AO_SCHEME_NIL;
843         jiffy = ao_scheme_os_jiffy();
844         return (ao_scheme_int_poly(jiffy));
845 }
846
847 ao_poly
848 ao_scheme_do_current_second(struct ao_scheme_cons *cons)
849 {
850         int     second;
851
852         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
853                 return AO_SCHEME_NIL;
854         second = ao_scheme_os_jiffy() / AO_SCHEME_JIFFIES_PER_SECOND;
855         return (ao_scheme_int_poly(second));
856 }
857
858 ao_poly
859 ao_scheme_do_jiffies_per_second(struct ao_scheme_cons *cons)
860 {
861         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
862                 return AO_SCHEME_NIL;
863         return (ao_scheme_int_poly(AO_SCHEME_JIFFIES_PER_SECOND));
864 }
865
866 ao_poly
867 ao_scheme_do_vector(struct ao_scheme_cons *cons)
868 {
869         return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
870 }
871
872 ao_poly
873 ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
874 {
875         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dref, cons, 2, 2))
876                 return AO_SCHEME_NIL;
877         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dref, cons, 0, AO_SCHEME_VECTOR, 0))
878                 return AO_SCHEME_NIL;
879         return ao_scheme_vector_get(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
880 }
881
882 ao_poly
883 ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
884 {
885         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dset21, cons, 3, 3))
886                 return AO_SCHEME_NIL;
887         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dset21, cons, 0, AO_SCHEME_VECTOR, 0))
888                 return AO_SCHEME_NIL;
889         return ao_scheme_vector_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1), ao_scheme_arg(cons, 2));
890 }
891
892 ao_poly
893 ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
894 {
895         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3evector, cons, 1, 1))
896                 return AO_SCHEME_NIL;
897         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3evector, cons, 0, AO_SCHEME_CONS, 0))
898                 return AO_SCHEME_NIL;
899         return ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
900 }
901
902 ao_poly
903 ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
904 {
905         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
906                 return AO_SCHEME_NIL;
907         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
908                 return AO_SCHEME_NIL;
909         return ao_scheme_cons_poly(ao_scheme_vector_to_list(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))));
910 }
911
912 ao_poly
913 ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
914 {
915         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
916                 return AO_SCHEME_NIL;
917         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
918                 return AO_SCHEME_NIL;
919         return ao_scheme_integer_poly(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))->length);
920 }
921
922 ao_poly
923 ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
924 {
925         return ao_scheme_do_typep(AO_SCHEME_VECTOR, cons);
926 }
927
928 #define AO_SCHEME_BUILTIN_FUNCS
929 #include "ao_scheme_builtin.h"