1754e6777790ecd6176c0eb3d9fd067e2ef7be11
[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, "%v: arg %d invalid type %v", name, argc, car);
127         return _ao_scheme_bool_true;
128 }
129
130 int32_t
131 ao_scheme_arg_int(ao_poly name, struct ao_scheme_cons *cons, int argc)
132 {
133         ao_poly p = ao_scheme_arg(cons, argc);
134         int32_t i = ao_scheme_poly_integer(p);
135
136         if (i == AO_SCHEME_NOT_INTEGER)
137                 (void) ao_scheme_error(AO_SCHEME_INVALID, "%v: arg %d invalid type %v", name, argc, p);
138         return i;
139 }
140
141 ao_poly
142 ao_scheme_do_car(struct ao_scheme_cons *cons)
143 {
144         if (!ao_scheme_check_argc(_ao_scheme_atom_car, cons, 1, 1))
145                 return AO_SCHEME_NIL;
146         if (!ao_scheme_check_argt(_ao_scheme_atom_car, cons, 0, AO_SCHEME_CONS, 0))
147                 return AO_SCHEME_NIL;
148         return ao_scheme_poly_cons(cons->car)->car;
149 }
150
151 ao_poly
152 ao_scheme_do_cdr(struct ao_scheme_cons *cons)
153 {
154         if (!ao_scheme_check_argc(_ao_scheme_atom_cdr, cons, 1, 1))
155                 return AO_SCHEME_NIL;
156         if (!ao_scheme_check_argt(_ao_scheme_atom_cdr, cons, 0, AO_SCHEME_CONS, 0))
157                 return AO_SCHEME_NIL;
158         return ao_scheme_poly_cons(cons->car)->cdr;
159 }
160
161 ao_poly
162 ao_scheme_do_cons(struct ao_scheme_cons *cons)
163 {
164         ao_poly car, cdr;
165         if(!ao_scheme_check_argc(_ao_scheme_atom_cons, cons, 2, 2))
166                 return AO_SCHEME_NIL;
167         car = ao_scheme_arg(cons, 0);
168         cdr = ao_scheme_arg(cons, 1);
169         return ao_scheme__cons(car, cdr);
170 }
171
172 ao_poly
173 ao_scheme_do_last(struct ao_scheme_cons *cons)
174 {
175         struct ao_scheme_cons   *list;
176         if (!ao_scheme_check_argc(_ao_scheme_atom_last, cons, 1, 1))
177                 return AO_SCHEME_NIL;
178         if (!ao_scheme_check_argt(_ao_scheme_atom_last, cons, 0, AO_SCHEME_CONS, 1))
179                 return AO_SCHEME_NIL;
180         for (list = ao_scheme_poly_cons(ao_scheme_arg(cons, 0));
181              list;
182              list = ao_scheme_cons_cdr(list))
183         {
184                 if (!list->cdr)
185                         return list->car;
186         }
187         return AO_SCHEME_NIL;
188 }
189
190 ao_poly
191 ao_scheme_do_length(struct ao_scheme_cons *cons)
192 {
193         if (!ao_scheme_check_argc(_ao_scheme_atom_length, cons, 1, 1))
194                 return AO_SCHEME_NIL;
195         if (!ao_scheme_check_argt(_ao_scheme_atom_length, cons, 0, AO_SCHEME_CONS, 1))
196                 return AO_SCHEME_NIL;
197         return ao_scheme_int_poly(ao_scheme_cons_length(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
198 }
199
200 ao_poly
201 ao_scheme_do_list_copy(struct ao_scheme_cons *cons)
202 {
203         struct ao_scheme_cons *new;
204
205         if (!ao_scheme_check_argc(_ao_scheme_atom_length, cons, 1, 1))
206                 return AO_SCHEME_NIL;
207         if (!ao_scheme_check_argt(_ao_scheme_atom_length, cons, 0, AO_SCHEME_CONS, 1))
208                 return AO_SCHEME_NIL;
209         new = ao_scheme_cons_copy(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
210         return ao_scheme_cons_poly(new);
211 }
212
213 ao_poly
214 ao_scheme_do_quote(struct ao_scheme_cons *cons)
215 {
216         if (!ao_scheme_check_argc(_ao_scheme_atom_quote, cons, 1, 1))
217                 return AO_SCHEME_NIL;
218         return ao_scheme_arg(cons, 0);
219 }
220
221 ao_poly
222 ao_scheme_do_set(struct ao_scheme_cons *cons)
223 {
224         if (!ao_scheme_check_argc(_ao_scheme_atom_set, cons, 2, 2))
225                 return AO_SCHEME_NIL;
226         if (!ao_scheme_check_argt(_ao_scheme_atom_set, cons, 0, AO_SCHEME_ATOM, 0))
227                 return AO_SCHEME_NIL;
228
229         return ao_scheme_atom_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
230 }
231
232 ao_poly
233 ao_scheme_do_def(struct ao_scheme_cons *cons)
234 {
235         if (!ao_scheme_check_argc(_ao_scheme_atom_def, cons, 2, 2))
236                 return AO_SCHEME_NIL;
237         if (!ao_scheme_check_argt(_ao_scheme_atom_def, cons, 0, AO_SCHEME_ATOM, 0))
238                 return AO_SCHEME_NIL;
239
240         return ao_scheme_atom_def(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
241 }
242
243 ao_poly
244 ao_scheme_do_setq(struct ao_scheme_cons *cons)
245 {
246         ao_poly name;
247         if (!ao_scheme_check_argc(_ao_scheme_atom_set21, cons, 2, 2))
248                 return AO_SCHEME_NIL;
249         name = cons->car;
250         if (ao_scheme_poly_type(name) != AO_SCHEME_ATOM)
251                 return ao_scheme_error(AO_SCHEME_INVALID, "set! of non-atom %v", name);
252         if (!ao_scheme_atom_ref(name, NULL))
253                 return ao_scheme_error(AO_SCHEME_INVALID, "atom %v not defined", name);
254         return ao_scheme__cons(_ao_scheme_atom_set,
255                              ao_scheme__cons(ao_scheme__cons(_ao_scheme_atom_quote,
256                                                          ao_scheme__cons(name, AO_SCHEME_NIL)),
257                                            cons->cdr));
258 }
259
260 ao_poly
261 ao_scheme_do_cond(struct ao_scheme_cons *cons)
262 {
263         ao_scheme_set_cond(cons);
264         return AO_SCHEME_NIL;
265 }
266
267 ao_poly
268 ao_scheme_do_begin(struct ao_scheme_cons *cons)
269 {
270         ao_scheme_stack->state = eval_begin;
271         ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
272         return AO_SCHEME_NIL;
273 }
274
275 ao_poly
276 ao_scheme_do_while(struct ao_scheme_cons *cons)
277 {
278         ao_scheme_stack->state = eval_while;
279         ao_scheme_stack->sexprs = ao_scheme_cons_poly(cons);
280         return AO_SCHEME_NIL;
281 }
282
283 ao_poly
284 ao_scheme_do_write(struct ao_scheme_cons *cons)
285 {
286         ao_poly val = AO_SCHEME_NIL;
287         while (cons) {
288                 val = cons->car;
289                 ao_scheme_poly_write(val);
290                 cons = ao_scheme_cons_cdr(cons);
291                 if (cons)
292                         printf(" ");
293         }
294         return _ao_scheme_bool_true;
295 }
296
297 ao_poly
298 ao_scheme_do_display(struct ao_scheme_cons *cons)
299 {
300         ao_poly val = AO_SCHEME_NIL;
301         while (cons) {
302                 val = cons->car;
303                 ao_scheme_poly_display(val);
304                 cons = ao_scheme_cons_cdr(cons);
305         }
306         return _ao_scheme_bool_true;
307 }
308
309 ao_poly
310 ao_scheme_math(struct ao_scheme_cons *orig_cons, enum ao_scheme_builtin_id op)
311 {
312         struct ao_scheme_cons *cons = cons;
313         ao_poly ret = AO_SCHEME_NIL;
314
315         for (cons = orig_cons; cons; cons = ao_scheme_cons_cdr(cons)) {
316                 ao_poly         car = cons->car;
317                 uint8_t         rt = ao_scheme_poly_type(ret);
318                 uint8_t         ct = ao_scheme_poly_type(car);
319
320                 if (cons == orig_cons) {
321                         ret = car;
322                         ao_scheme_cons_stash(0, cons);
323                         if (cons->cdr == AO_SCHEME_NIL) {
324                                 switch (op) {
325                                 case builtin_minus:
326                                         if (ao_scheme_integer_typep(ct))
327                                                 ret = ao_scheme_integer_poly(-ao_scheme_poly_integer(ret));
328                                         else if (ct == AO_SCHEME_FLOAT)
329                                                 ret = ao_scheme_float_get(-ao_scheme_poly_number(ret));
330                                         break;
331                                 case builtin_divide:
332                                         if (ao_scheme_integer_typep(ct) && ao_scheme_poly_integer(ret) == 1)
333                                                 ;
334                                         else if (ao_scheme_number_typep(ct)) {
335                                                 float   v = ao_scheme_poly_number(ret);
336                                                 ret = ao_scheme_float_get(1/v);
337                                         }
338                                         break;
339                                 default:
340                                         break;
341                                 }
342                         }
343                         cons = ao_scheme_cons_fetch(0);
344                 } else if (ao_scheme_integer_typep(rt) && ao_scheme_integer_typep(ct)) {
345                         int32_t r = ao_scheme_poly_integer(ret);
346                         int32_t c = ao_scheme_poly_integer(car);
347                         int64_t t;
348
349                         switch(op) {
350                         case builtin_plus:
351                                 r += c;
352                         check_overflow:
353                                 if (r < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < r)
354                                         goto inexact;
355                                 break;
356                         case builtin_minus:
357                                 r -= c;
358                                 goto check_overflow;
359                                 break;
360                         case builtin_times:
361                                 t = (int64_t) r * (int64_t) c;
362                                 if (t < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < t)
363                                         goto inexact;
364                                 r = (int32_t) t;
365                                 break;
366                         case builtin_divide:
367                                 if (c != 0 && (r % c) == 0)
368                                         r /= c;
369                                 else
370                                         goto inexact;
371                                 break;
372                         case builtin_quotient:
373                                 if (c == 0)
374                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "quotient by zero");
375                                 if (r % c != 0 && (c < 0) != (r < 0))
376                                         r = r / c - 1;
377                                 else
378                                         r = r / c;
379                                 break;
380                         case builtin_remainder:
381                                 if (c == 0)
382                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "remainder by zero");
383                                 r %= c;
384                                 break;
385                         case builtin_modulo:
386                                 if (c == 0)
387                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "modulo by zero");
388                                 r %= c;
389                                 if ((r < 0) != (c < 0))
390                                         r += c;
391                                 break;
392                         default:
393                                 break;
394                         }
395                         ao_scheme_cons_stash(0, cons);
396                         ret = ao_scheme_integer_poly(r);
397                         cons = ao_scheme_cons_fetch(0);
398                 } else if (ao_scheme_number_typep(rt) && ao_scheme_number_typep(ct)) {
399                         float r, c;
400                 inexact:
401                         r = ao_scheme_poly_number(ret);
402                         c = ao_scheme_poly_number(car);
403                         switch(op) {
404                         case builtin_plus:
405                                 r += c;
406                                 break;
407                         case builtin_minus:
408                                 r -= c;
409                                 break;
410                         case builtin_times:
411                                 r *= c;
412                                 break;
413                         case builtin_divide:
414                                 r /= c;
415                                 break;
416                         case builtin_quotient:
417                         case builtin_remainder:
418                         case builtin_modulo:
419                                 return ao_scheme_error(AO_SCHEME_INVALID, "non-integer value in integer divide");
420                         default:
421                                 break;
422                         }
423                         ao_scheme_cons_stash(0, cons);
424                         ret = ao_scheme_float_get(r);
425                         cons = ao_scheme_cons_fetch(0);
426                 }
427                 else if (rt == AO_SCHEME_STRING && ct == AO_SCHEME_STRING && op == builtin_plus) {
428                         ao_scheme_cons_stash(0, cons);
429                         ret = ao_scheme_string_poly(ao_scheme_string_cat(ao_scheme_poly_string(ret),
430                                                                          ao_scheme_poly_string(car)));
431                         cons = ao_scheme_cons_fetch(0);
432                         if (!ret)
433                                 return ret;
434                 }
435                 else
436                         return ao_scheme_error(AO_SCHEME_INVALID, "invalid args");
437         }
438         return ret;
439 }
440
441 ao_poly
442 ao_scheme_do_plus(struct ao_scheme_cons *cons)
443 {
444         return ao_scheme_math(cons, builtin_plus);
445 }
446
447 ao_poly
448 ao_scheme_do_minus(struct ao_scheme_cons *cons)
449 {
450         return ao_scheme_math(cons, builtin_minus);
451 }
452
453 ao_poly
454 ao_scheme_do_times(struct ao_scheme_cons *cons)
455 {
456         return ao_scheme_math(cons, builtin_times);
457 }
458
459 ao_poly
460 ao_scheme_do_divide(struct ao_scheme_cons *cons)
461 {
462         return ao_scheme_math(cons, builtin_divide);
463 }
464
465 ao_poly
466 ao_scheme_do_quotient(struct ao_scheme_cons *cons)
467 {
468         return ao_scheme_math(cons, builtin_quotient);
469 }
470
471 ao_poly
472 ao_scheme_do_modulo(struct ao_scheme_cons *cons)
473 {
474         return ao_scheme_math(cons, builtin_modulo);
475 }
476
477 ao_poly
478 ao_scheme_do_remainder(struct ao_scheme_cons *cons)
479 {
480         return ao_scheme_math(cons, builtin_remainder);
481 }
482
483 ao_poly
484 ao_scheme_compare(struct ao_scheme_cons *cons, enum ao_scheme_builtin_id op)
485 {
486         ao_poly left;
487
488         if (!cons)
489                 return _ao_scheme_bool_true;
490
491         left = cons->car;
492         for (cons = ao_scheme_cons_cdr(cons); cons; cons = ao_scheme_cons_cdr(cons)) {
493                 ao_poly right = cons->car;
494
495                 if (op == builtin_equal && left == right) {
496                         ;
497                 } else {
498                         uint8_t lt = ao_scheme_poly_type(left);
499                         uint8_t rt = ao_scheme_poly_type(right);
500                         if (ao_scheme_integer_typep(lt) && ao_scheme_integer_typep(rt)) {
501                                 int32_t l = ao_scheme_poly_integer(left);
502                                 int32_t r = ao_scheme_poly_integer(right);
503
504                                 switch (op) {
505                                 case builtin_less:
506                                         if (!(l < r))
507                                                 return _ao_scheme_bool_false;
508                                         break;
509                                 case builtin_greater:
510                                         if (!(l > r))
511                                                 return _ao_scheme_bool_false;
512                                         break;
513                                 case builtin_less_equal:
514                                         if (!(l <= r))
515                                                 return _ao_scheme_bool_false;
516                                         break;
517                                 case builtin_greater_equal:
518                                         if (!(l >= r))
519                                                 return _ao_scheme_bool_false;
520                                         break;
521                                 case builtin_equal:
522                                         if (!(l == r))
523                                                 return _ao_scheme_bool_false;
524                                 default:
525                                         break;
526                                 }
527                         } else if (ao_scheme_number_typep(lt) && ao_scheme_number_typep(rt)) {
528                                 float l, r;
529
530                                 l = ao_scheme_poly_number(left);
531                                 r = ao_scheme_poly_number(right);
532
533                                 switch (op) {
534                                 case builtin_less:
535                                         if (!(l < r))
536                                                 return _ao_scheme_bool_false;
537                                         break;
538                                 case builtin_greater:
539                                         if (!(l > r))
540                                                 return _ao_scheme_bool_false;
541                                         break;
542                                 case builtin_less_equal:
543                                         if (!(l <= r))
544                                                 return _ao_scheme_bool_false;
545                                         break;
546                                 case builtin_greater_equal:
547                                         if (!(l >= r))
548                                                 return _ao_scheme_bool_false;
549                                         break;
550                                 case builtin_equal:
551                                         if (!(l == r))
552                                                 return _ao_scheme_bool_false;
553                                 default:
554                                         break;
555                                 }
556                         } else if (lt == AO_SCHEME_STRING && rt == AO_SCHEME_STRING) {
557                                 int c = strcmp(ao_scheme_poly_string(left),
558                                                ao_scheme_poly_string(right));
559                                 switch (op) {
560                                 case builtin_less:
561                                         if (!(c < 0))
562                                                 return _ao_scheme_bool_false;
563                                         break;
564                                 case builtin_greater:
565                                         if (!(c > 0))
566                                                 return _ao_scheme_bool_false;
567                                         break;
568                                 case builtin_less_equal:
569                                         if (!(c <= 0))
570                                                 return _ao_scheme_bool_false;
571                                         break;
572                                 case builtin_greater_equal:
573                                         if (!(c >= 0))
574                                                 return _ao_scheme_bool_false;
575                                         break;
576                                 case builtin_equal:
577                                         if (!(c == 0))
578                                                 return _ao_scheme_bool_false;
579                                         break;
580                                 default:
581                                         break;
582                                 }
583                         } else
584                                 return _ao_scheme_bool_false;
585                 }
586                 left = right;
587         }
588         return _ao_scheme_bool_true;
589 }
590
591 ao_poly
592 ao_scheme_do_equal(struct ao_scheme_cons *cons)
593 {
594         return ao_scheme_compare(cons, builtin_equal);
595 }
596
597 ao_poly
598 ao_scheme_do_less(struct ao_scheme_cons *cons)
599 {
600         return ao_scheme_compare(cons, builtin_less);
601 }
602
603 ao_poly
604 ao_scheme_do_greater(struct ao_scheme_cons *cons)
605 {
606         return ao_scheme_compare(cons, builtin_greater);
607 }
608
609 ao_poly
610 ao_scheme_do_less_equal(struct ao_scheme_cons *cons)
611 {
612         return ao_scheme_compare(cons, builtin_less_equal);
613 }
614
615 ao_poly
616 ao_scheme_do_greater_equal(struct ao_scheme_cons *cons)
617 {
618         return ao_scheme_compare(cons, builtin_greater_equal);
619 }
620
621 ao_poly
622 ao_scheme_do_list_to_string(struct ao_scheme_cons *cons)
623 {
624         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3estring, cons, 1, 1))
625                 return AO_SCHEME_NIL;
626         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3estring, cons, 0, AO_SCHEME_CONS, 1))
627                 return AO_SCHEME_NIL;
628         return ao_scheme_string_pack(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
629 }
630
631 ao_poly
632 ao_scheme_do_string_to_list(struct ao_scheme_cons *cons)
633 {
634         if (!ao_scheme_check_argc(_ao_scheme_atom_string2d3elist, cons, 1, 1))
635                 return AO_SCHEME_NIL;
636         if (!ao_scheme_check_argt(_ao_scheme_atom_string2d3elist, cons, 0, AO_SCHEME_STRING, 0))
637                 return AO_SCHEME_NIL;
638         return ao_scheme_string_unpack(ao_scheme_poly_string(ao_scheme_arg(cons, 0)));
639 }
640
641 ao_poly
642 ao_scheme_do_string_ref(struct ao_scheme_cons *cons)
643 {
644         char *string;
645         int32_t ref;
646         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dref, cons, 2, 2))
647                 return AO_SCHEME_NIL;
648         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dref, cons, 0, AO_SCHEME_STRING, 0))
649                 return AO_SCHEME_NIL;
650         ref = ao_scheme_arg_int(_ao_scheme_atom_string2dref, cons, 1);
651         if (ref == AO_SCHEME_NOT_INTEGER)
652                 return AO_SCHEME_NIL;
653         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
654         while (*string && ref) {
655                 ++string;
656                 --ref;
657         }
658         if (!*string)
659                 return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
660                                        _ao_scheme_atom_string2dref,
661                                        ao_scheme_arg(cons, 0),
662                                        ao_scheme_arg(cons, 1));
663         return ao_scheme_int_poly(*string);
664 }
665
666 ao_poly
667 ao_scheme_do_string_length(struct ao_scheme_cons *cons)
668 {
669         char *string;
670
671         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dlength, cons, 1, 1))
672                 return AO_SCHEME_NIL;
673         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dlength, cons, 0, AO_SCHEME_STRING, 0))
674                 return AO_SCHEME_NIL;
675         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
676         return ao_scheme_integer_poly(strlen(string));
677 }
678
679 ao_poly
680 ao_scheme_do_string_copy(struct ao_scheme_cons *cons)
681 {
682         char *string;
683
684         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dcopy, cons, 1, 1))
685                 return AO_SCHEME_NIL;
686         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dcopy, cons, 0, AO_SCHEME_STRING, 0))
687                 return AO_SCHEME_NIL;
688         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
689         return ao_scheme_string_poly(ao_scheme_string_copy(string));
690 }
691
692 ao_poly
693 ao_scheme_do_string_set(struct ao_scheme_cons *cons)
694 {
695         char *string;
696         int32_t ref;
697         int32_t val;
698
699         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dset21, cons, 3, 3))
700                 return AO_SCHEME_NIL;
701         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dset21, cons, 0, AO_SCHEME_STRING, 0))
702                 return AO_SCHEME_NIL;
703         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
704         ref = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 1);
705         if (ref == AO_SCHEME_NOT_INTEGER)
706                 return AO_SCHEME_NIL;
707         val = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 2);
708         if (val == AO_SCHEME_NOT_INTEGER)
709                 return AO_SCHEME_NIL;
710         while (*string && ref) {
711                 ++string;
712                 --ref;
713         }
714         if (!*string)
715                 return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
716                                        _ao_scheme_atom_string2dset21,
717                                        ao_scheme_arg(cons, 0),
718                                        ao_scheme_arg(cons, 1));
719         *string = val;
720         return ao_scheme_int_poly(*string);
721 }
722
723 ao_poly
724 ao_scheme_do_flush_output(struct ao_scheme_cons *cons)
725 {
726         if (!ao_scheme_check_argc(_ao_scheme_atom_flush2doutput, cons, 0, 0))
727                 return AO_SCHEME_NIL;
728         ao_scheme_os_flush();
729         return _ao_scheme_bool_true;
730 }
731
732 ao_poly
733 ao_scheme_do_led(struct ao_scheme_cons *cons)
734 {
735         int32_t led;
736         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
737                 return AO_SCHEME_NIL;
738         led = ao_scheme_arg_int(_ao_scheme_atom_led, cons, 0);
739         if (led == AO_SCHEME_NOT_INTEGER)
740                 return AO_SCHEME_NIL;
741         led = ao_scheme_arg(cons, 0);
742         ao_scheme_os_led(ao_scheme_poly_int(led));
743         return led;
744 }
745
746 ao_poly
747 ao_scheme_do_delay(struct ao_scheme_cons *cons)
748 {
749         int32_t delay;
750
751         if (!ao_scheme_check_argc(_ao_scheme_atom_delay, cons, 1, 1))
752                 return AO_SCHEME_NIL;
753         delay = ao_scheme_arg_int(_ao_scheme_atom_delay, cons, 0);
754         if (delay == AO_SCHEME_NOT_INTEGER)
755                 return AO_SCHEME_NIL;
756         ao_scheme_os_delay(delay);
757         return delay;
758 }
759
760 ao_poly
761 ao_scheme_do_eval(struct ao_scheme_cons *cons)
762 {
763         if (!ao_scheme_check_argc(_ao_scheme_atom_eval, cons, 1, 1))
764                 return AO_SCHEME_NIL;
765         ao_scheme_stack->state = eval_sexpr;
766         return cons->car;
767 }
768
769 ao_poly
770 ao_scheme_do_apply(struct ao_scheme_cons *cons)
771 {
772         if (!ao_scheme_check_argc(_ao_scheme_atom_apply, cons, 2, INT_MAX))
773                 return AO_SCHEME_NIL;
774         ao_scheme_stack->state = eval_apply;
775         return ao_scheme_cons_poly(cons);
776 }
777
778 ao_poly
779 ao_scheme_do_read(struct ao_scheme_cons *cons)
780 {
781         if (!ao_scheme_check_argc(_ao_scheme_atom_read, cons, 0, 0))
782                 return AO_SCHEME_NIL;
783         return ao_scheme_read();
784 }
785
786 ao_poly
787 ao_scheme_do_collect(struct ao_scheme_cons *cons)
788 {
789         int     free;
790         (void) cons;
791         free = ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
792         return ao_scheme_integer_poly(free);
793 }
794
795 ao_poly
796 ao_scheme_do_nullp(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_arg(cons, 0) == AO_SCHEME_NIL)
801                 return _ao_scheme_bool_true;
802         else
803                 return _ao_scheme_bool_false;
804 }
805
806 ao_poly
807 ao_scheme_do_not(struct ao_scheme_cons *cons)
808 {
809         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
810                 return AO_SCHEME_NIL;
811         if (ao_scheme_arg(cons, 0) == _ao_scheme_bool_false)
812                 return _ao_scheme_bool_true;
813         else
814                 return _ao_scheme_bool_false;
815 }
816
817 static ao_poly
818 ao_scheme_do_typep(int type, struct ao_scheme_cons *cons)
819 {
820         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
821                 return AO_SCHEME_NIL;
822         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == type)
823                 return _ao_scheme_bool_true;
824         return _ao_scheme_bool_false;
825 }
826
827 ao_poly
828 ao_scheme_do_pairp(struct ao_scheme_cons *cons)
829 {
830         ao_poly v;
831         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
832                 return AO_SCHEME_NIL;
833         v = ao_scheme_arg(cons, 0);
834         if (v != AO_SCHEME_NIL && ao_scheme_poly_type(v) == AO_SCHEME_CONS)
835                 return _ao_scheme_bool_true;
836         return _ao_scheme_bool_false;
837 }
838
839 ao_poly
840 ao_scheme_do_integerp(struct ao_scheme_cons *cons)
841 {
842         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
843                 return AO_SCHEME_NIL;
844         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
845         case AO_SCHEME_INT:
846         case AO_SCHEME_BIGINT:
847                 return _ao_scheme_bool_true;
848         default:
849                 return _ao_scheme_bool_false;
850         }
851 }
852
853 ao_poly
854 ao_scheme_do_numberp(struct ao_scheme_cons *cons)
855 {
856         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
857                 return AO_SCHEME_NIL;
858         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
859         case AO_SCHEME_INT:
860         case AO_SCHEME_BIGINT:
861         case AO_SCHEME_FLOAT:
862                 return _ao_scheme_bool_true;
863         default:
864                 return _ao_scheme_bool_false;
865         }
866 }
867
868 ao_poly
869 ao_scheme_do_stringp(struct ao_scheme_cons *cons)
870 {
871         return ao_scheme_do_typep(AO_SCHEME_STRING, cons);
872 }
873
874 ao_poly
875 ao_scheme_do_symbolp(struct ao_scheme_cons *cons)
876 {
877         return ao_scheme_do_typep(AO_SCHEME_ATOM, cons);
878 }
879
880 ao_poly
881 ao_scheme_do_booleanp(struct ao_scheme_cons *cons)
882 {
883         return ao_scheme_do_typep(AO_SCHEME_BOOL, cons);
884 }
885
886 ao_poly
887 ao_scheme_do_procedurep(struct ao_scheme_cons *cons)
888 {
889         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
890                 return AO_SCHEME_NIL;
891         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
892         case AO_SCHEME_BUILTIN:
893         case AO_SCHEME_LAMBDA:
894                 return _ao_scheme_bool_true;
895         default:
896         return _ao_scheme_bool_false;
897         }
898 }
899
900 /* This one is special -- a list is either nil or
901  * a 'proper' list with only cons cells
902  */
903 ao_poly
904 ao_scheme_do_listp(struct ao_scheme_cons *cons)
905 {
906         ao_poly v;
907         if (!ao_scheme_check_argc(_ao_scheme_atom_list3f, cons, 1, 1))
908                 return AO_SCHEME_NIL;
909         v = ao_scheme_arg(cons, 0);
910         for (;;) {
911                 if (v == AO_SCHEME_NIL)
912                         return _ao_scheme_bool_true;
913                 if (ao_scheme_poly_type(v) != AO_SCHEME_CONS)
914                         return _ao_scheme_bool_false;
915                 v = ao_scheme_poly_cons(v)->cdr;
916         }
917 }
918
919 ao_poly
920 ao_scheme_do_set_car(struct ao_scheme_cons *cons)
921 {
922         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
923                 return AO_SCHEME_NIL;
924         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
925                 return AO_SCHEME_NIL;
926         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->car = ao_scheme_arg(cons, 1);
927 }
928
929 ao_poly
930 ao_scheme_do_set_cdr(struct ao_scheme_cons *cons)
931 {
932         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
933                 return AO_SCHEME_NIL;
934         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
935                 return AO_SCHEME_NIL;
936         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->cdr = ao_scheme_arg(cons, 1);
937 }
938
939 ao_poly
940 ao_scheme_do_symbol_to_string(struct ao_scheme_cons *cons)
941 {
942         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
943                 return AO_SCHEME_NIL;
944         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_ATOM, 0))
945                 return AO_SCHEME_NIL;
946         return ao_scheme_string_poly(ao_scheme_string_copy(ao_scheme_poly_atom(ao_scheme_arg(cons, 0))->name));
947 }
948
949 ao_poly
950 ao_scheme_do_string_to_symbol(struct ao_scheme_cons *cons)
951 {
952         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
953                 return AO_SCHEME_NIL;
954         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_STRING, 0))
955                 return AO_SCHEME_NIL;
956
957         return ao_scheme_atom_poly(ao_scheme_atom_intern(ao_scheme_poly_string(ao_scheme_arg(cons, 0))));
958 }
959
960 ao_poly
961 ao_scheme_do_read_char(struct ao_scheme_cons *cons)
962 {
963         int     c;
964         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
965                 return AO_SCHEME_NIL;
966         c = getchar();
967         return ao_scheme_int_poly(c);
968 }
969
970 ao_poly
971 ao_scheme_do_write_char(struct ao_scheme_cons *cons)
972 {
973         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
974                 return AO_SCHEME_NIL;
975         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
976                 return AO_SCHEME_NIL;
977         putchar(ao_scheme_poly_integer(ao_scheme_arg(cons, 0)));
978         return _ao_scheme_bool_true;
979 }
980
981 ao_poly
982 ao_scheme_do_exit(struct ao_scheme_cons *cons)
983 {
984         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
985                 return AO_SCHEME_NIL;
986         ao_scheme_exception |= AO_SCHEME_EXIT;
987         return _ao_scheme_bool_true;
988 }
989
990 ao_poly
991 ao_scheme_do_current_jiffy(struct ao_scheme_cons *cons)
992 {
993         int     jiffy;
994
995         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
996                 return AO_SCHEME_NIL;
997         jiffy = ao_scheme_os_jiffy();
998         return (ao_scheme_int_poly(jiffy));
999 }
1000
1001 ao_poly
1002 ao_scheme_do_current_second(struct ao_scheme_cons *cons)
1003 {
1004         int     second;
1005
1006         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1007                 return AO_SCHEME_NIL;
1008         second = ao_scheme_os_jiffy() / AO_SCHEME_JIFFIES_PER_SECOND;
1009         return (ao_scheme_int_poly(second));
1010 }
1011
1012 ao_poly
1013 ao_scheme_do_jiffies_per_second(struct ao_scheme_cons *cons)
1014 {
1015         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1016                 return AO_SCHEME_NIL;
1017         return (ao_scheme_int_poly(AO_SCHEME_JIFFIES_PER_SECOND));
1018 }
1019
1020 ao_poly
1021 ao_scheme_do_vector(struct ao_scheme_cons *cons)
1022 {
1023         return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
1024 }
1025
1026 ao_poly
1027 ao_scheme_do_make_vector(struct ao_scheme_cons *cons)
1028 {
1029         int32_t k;
1030
1031         if (!ao_scheme_check_argc(_ao_scheme_atom_make2dvector, cons, 2, 2))
1032                 return AO_SCHEME_NIL;
1033         k = ao_scheme_arg_int(_ao_scheme_atom_make2dvector, cons, 0);
1034         if (k == AO_SCHEME_NOT_INTEGER)
1035                 return AO_SCHEME_NIL;
1036         return ao_scheme_vector_poly(ao_scheme_vector_alloc(k, ao_scheme_arg(cons, 1)));
1037 }
1038
1039 ao_poly
1040 ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
1041 {
1042         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dref, cons, 2, 2))
1043                 return AO_SCHEME_NIL;
1044         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dref, cons, 0, AO_SCHEME_VECTOR, 0))
1045                 return AO_SCHEME_NIL;
1046         return ao_scheme_vector_get(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
1047 }
1048
1049 ao_poly
1050 ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
1051 {
1052         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dset21, cons, 3, 3))
1053                 return AO_SCHEME_NIL;
1054         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dset21, cons, 0, AO_SCHEME_VECTOR, 0))
1055                 return AO_SCHEME_NIL;
1056         return ao_scheme_vector_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1), ao_scheme_arg(cons, 2));
1057 }
1058
1059 ao_poly
1060 ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
1061 {
1062         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3evector, cons, 1, 1))
1063                 return AO_SCHEME_NIL;
1064         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3evector, cons, 0, AO_SCHEME_CONS, 0))
1065                 return AO_SCHEME_NIL;
1066         return ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
1067 }
1068
1069 ao_poly
1070 ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
1071 {
1072         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
1073                 return AO_SCHEME_NIL;
1074         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
1075                 return AO_SCHEME_NIL;
1076         return ao_scheme_cons_poly(ao_scheme_vector_to_list(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))));
1077 }
1078
1079 ao_poly
1080 ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
1081 {
1082         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
1083                 return AO_SCHEME_NIL;
1084         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
1085                 return AO_SCHEME_NIL;
1086         return ao_scheme_integer_poly(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))->length);
1087 }
1088
1089 ao_poly
1090 ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
1091 {
1092         return ao_scheme_do_typep(AO_SCHEME_VECTOR, cons);
1093 }
1094
1095 #define AO_SCHEME_BUILTIN_FUNCS
1096 #include "ao_scheme_builtin.h"