b67889930a33fbc47833435fd032c962a04c4edb
[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 (char *) "???";
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 (char *) "???";
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 (char *) "(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 static 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 static 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;
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 #ifdef AO_SCHEME_FEATURE_FLOAT
329                                         else if (ct == AO_SCHEME_FLOAT)
330                                                 ret = ao_scheme_float_get(-ao_scheme_poly_number(ret));
331 #endif
332                                         break;
333                                 case builtin_divide:
334                                         if (ao_scheme_integer_typep(ct) && ao_scheme_poly_integer(ret) == 1) {
335                                         } else {
336 #ifdef AO_SCHEME_FEATURE_FLOAT
337                                                 if (ao_scheme_number_typep(ct)) {
338                                                         float   v = ao_scheme_poly_number(ret);
339                                                         ret = ao_scheme_float_get(1/v);
340                                                 }
341 #else
342                                                 ret = ao_scheme_integer_poly(0);
343 #endif
344                                         }
345                                         break;
346                                 default:
347                                         break;
348                                 }
349                         }
350                         cons = ao_scheme_cons_fetch(0);
351                 } else if (ao_scheme_integer_typep(rt) && ao_scheme_integer_typep(ct)) {
352                         int32_t r = ao_scheme_poly_integer(ret);
353                         int32_t c = ao_scheme_poly_integer(car);
354 #ifdef AO_SCHEME_FEATURE_FLOAT
355                         int64_t t;
356 #endif
357
358                         switch(op) {
359                         case builtin_plus:
360                                 r += c;
361                         check_overflow:
362 #ifdef AO_SCHEME_FEATURE_FLOAT
363                                 if (r < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < r)
364                                         goto inexact;
365 #endif
366                                 break;
367                         case builtin_minus:
368                                 r -= c;
369                                 goto check_overflow;
370                                 break;
371                         case builtin_times:
372 #ifdef AO_SCHEME_FEATURE_FLOAT
373                                 t = (int64_t) r * (int64_t) c;
374                                 if (t < AO_SCHEME_MIN_BIGINT || AO_SCHEME_MAX_BIGINT < t)
375                                         goto inexact;
376                                 r = (int32_t) t;
377 #else
378                                 r = r * c;
379 #endif
380                                 break;
381                         case builtin_divide:
382 #ifdef AO_SCHEME_FEATURE_FLOAT
383                                 if (c != 0 && (r % c) == 0)
384                                         r /= c;
385                                 else
386                                         goto inexact;
387 #else
388                                 r /= c;
389 #endif
390                                 break;
391                         case builtin_quotient:
392                                 if (c == 0)
393                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "quotient by zero");
394                                 if (r % c != 0 && (c < 0) != (r < 0))
395                                         r = r / c - 1;
396                                 else
397                                         r = r / c;
398                                 break;
399                         case builtin_remainder:
400                                 if (c == 0)
401                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "remainder by zero");
402                                 r %= c;
403                                 break;
404                         case builtin_modulo:
405                                 if (c == 0)
406                                         return ao_scheme_error(AO_SCHEME_DIVIDE_BY_ZERO, "modulo by zero");
407                                 r %= c;
408                                 if ((r < 0) != (c < 0))
409                                         r += c;
410                                 break;
411                         default:
412                                 break;
413                         }
414                         ao_scheme_cons_stash(0, cons);
415                         ret = ao_scheme_integer_poly(r);
416                         cons = ao_scheme_cons_fetch(0);
417 #ifdef AO_SCHEME_FEATURE_FLOAT
418                 } else if (ao_scheme_number_typep(rt) && ao_scheme_number_typep(ct)) {
419                         float r, c;
420                 inexact:
421                         r = ao_scheme_poly_number(ret);
422                         c = ao_scheme_poly_number(car);
423                         switch(op) {
424                         case builtin_plus:
425                                 r += c;
426                                 break;
427                         case builtin_minus:
428                                 r -= c;
429                                 break;
430                         case builtin_times:
431                                 r *= c;
432                                 break;
433                         case builtin_divide:
434                                 r /= c;
435                                 break;
436                         case builtin_quotient:
437                         case builtin_remainder:
438                         case builtin_modulo:
439                                 return ao_scheme_error(AO_SCHEME_INVALID, "non-integer value in integer divide");
440                         default:
441                                 break;
442                         }
443                         ao_scheme_cons_stash(0, cons);
444                         ret = ao_scheme_float_get(r);
445                         cons = ao_scheme_cons_fetch(0);
446 #endif
447                 }
448                 else if (rt == AO_SCHEME_STRING && ct == AO_SCHEME_STRING && op == builtin_plus) {
449                         ao_scheme_cons_stash(0, cons);
450                         ret = ao_scheme_string_poly(ao_scheme_string_cat(ao_scheme_poly_string(ret),
451                                                                          ao_scheme_poly_string(car)));
452                         cons = ao_scheme_cons_fetch(0);
453                         if (!ret)
454                                 return ret;
455                 }
456                 else
457                         return ao_scheme_error(AO_SCHEME_INVALID, "invalid args");
458         }
459         return ret;
460 }
461
462 ao_poly
463 ao_scheme_do_plus(struct ao_scheme_cons *cons)
464 {
465         return ao_scheme_math(cons, builtin_plus);
466 }
467
468 ao_poly
469 ao_scheme_do_minus(struct ao_scheme_cons *cons)
470 {
471         return ao_scheme_math(cons, builtin_minus);
472 }
473
474 ao_poly
475 ao_scheme_do_times(struct ao_scheme_cons *cons)
476 {
477         return ao_scheme_math(cons, builtin_times);
478 }
479
480 ao_poly
481 ao_scheme_do_divide(struct ao_scheme_cons *cons)
482 {
483         return ao_scheme_math(cons, builtin_divide);
484 }
485
486 ao_poly
487 ao_scheme_do_quotient(struct ao_scheme_cons *cons)
488 {
489         return ao_scheme_math(cons, builtin_quotient);
490 }
491
492 ao_poly
493 ao_scheme_do_modulo(struct ao_scheme_cons *cons)
494 {
495         return ao_scheme_math(cons, builtin_modulo);
496 }
497
498 ao_poly
499 ao_scheme_do_remainder(struct ao_scheme_cons *cons)
500 {
501         return ao_scheme_math(cons, builtin_remainder);
502 }
503
504 static ao_poly
505 ao_scheme_compare(struct ao_scheme_cons *cons, enum ao_scheme_builtin_id op)
506 {
507         ao_poly left;
508
509         if (!cons)
510                 return _ao_scheme_bool_true;
511
512         left = cons->car;
513         for (cons = ao_scheme_cons_cdr(cons); cons; cons = ao_scheme_cons_cdr(cons)) {
514                 ao_poly right = cons->car;
515
516                 if (op == builtin_equal && left == right) {
517                         ;
518                 } else {
519                         uint8_t lt = ao_scheme_poly_type(left);
520                         uint8_t rt = ao_scheme_poly_type(right);
521                         if (ao_scheme_integer_typep(lt) && ao_scheme_integer_typep(rt)) {
522                                 int32_t l = ao_scheme_poly_integer(left);
523                                 int32_t r = ao_scheme_poly_integer(right);
524
525                                 switch (op) {
526                                 case builtin_less:
527                                         if (!(l < r))
528                                                 return _ao_scheme_bool_false;
529                                         break;
530                                 case builtin_greater:
531                                         if (!(l > r))
532                                                 return _ao_scheme_bool_false;
533                                         break;
534                                 case builtin_less_equal:
535                                         if (!(l <= r))
536                                                 return _ao_scheme_bool_false;
537                                         break;
538                                 case builtin_greater_equal:
539                                         if (!(l >= r))
540                                                 return _ao_scheme_bool_false;
541                                         break;
542                                 case builtin_equal:
543                                         if (!(l == r))
544                                                 return _ao_scheme_bool_false;
545                                 default:
546                                         break;
547                                 }
548 #ifdef AO_SCHEME_FEATURE_FLOAT
549                         } else if (ao_scheme_number_typep(lt) && ao_scheme_number_typep(rt)) {
550                                 float l, r;
551
552                                 l = ao_scheme_poly_number(left);
553                                 r = ao_scheme_poly_number(right);
554
555                                 switch (op) {
556                                 case builtin_less:
557                                         if (!(l < r))
558                                                 return _ao_scheme_bool_false;
559                                         break;
560                                 case builtin_greater:
561                                         if (!(l > r))
562                                                 return _ao_scheme_bool_false;
563                                         break;
564                                 case builtin_less_equal:
565                                         if (!(l <= r))
566                                                 return _ao_scheme_bool_false;
567                                         break;
568                                 case builtin_greater_equal:
569                                         if (!(l >= r))
570                                                 return _ao_scheme_bool_false;
571                                         break;
572                                 case builtin_equal:
573                                         if (!(l == r))
574                                                 return _ao_scheme_bool_false;
575                                 default:
576                                         break;
577                                 }
578 #endif /* AO_SCHEME_FEATURE_FLOAT */
579                         } else if (lt == AO_SCHEME_STRING && rt == AO_SCHEME_STRING) {
580                                 int c = strcmp(ao_scheme_poly_string(left),
581                                                ao_scheme_poly_string(right));
582                                 switch (op) {
583                                 case builtin_less:
584                                         if (!(c < 0))
585                                                 return _ao_scheme_bool_false;
586                                         break;
587                                 case builtin_greater:
588                                         if (!(c > 0))
589                                                 return _ao_scheme_bool_false;
590                                         break;
591                                 case builtin_less_equal:
592                                         if (!(c <= 0))
593                                                 return _ao_scheme_bool_false;
594                                         break;
595                                 case builtin_greater_equal:
596                                         if (!(c >= 0))
597                                                 return _ao_scheme_bool_false;
598                                         break;
599                                 case builtin_equal:
600                                         if (!(c == 0))
601                                                 return _ao_scheme_bool_false;
602                                         break;
603                                 default:
604                                         break;
605                                 }
606                         } else
607                                 return _ao_scheme_bool_false;
608                 }
609                 left = right;
610         }
611         return _ao_scheme_bool_true;
612 }
613
614 ao_poly
615 ao_scheme_do_equal(struct ao_scheme_cons *cons)
616 {
617         return ao_scheme_compare(cons, builtin_equal);
618 }
619
620 ao_poly
621 ao_scheme_do_less(struct ao_scheme_cons *cons)
622 {
623         return ao_scheme_compare(cons, builtin_less);
624 }
625
626 ao_poly
627 ao_scheme_do_greater(struct ao_scheme_cons *cons)
628 {
629         return ao_scheme_compare(cons, builtin_greater);
630 }
631
632 ao_poly
633 ao_scheme_do_less_equal(struct ao_scheme_cons *cons)
634 {
635         return ao_scheme_compare(cons, builtin_less_equal);
636 }
637
638 ao_poly
639 ao_scheme_do_greater_equal(struct ao_scheme_cons *cons)
640 {
641         return ao_scheme_compare(cons, builtin_greater_equal);
642 }
643
644 ao_poly
645 ao_scheme_do_list_to_string(struct ao_scheme_cons *cons)
646 {
647         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3estring, cons, 1, 1))
648                 return AO_SCHEME_NIL;
649         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3estring, cons, 0, AO_SCHEME_CONS, 1))
650                 return AO_SCHEME_NIL;
651         return ao_scheme_string_pack(ao_scheme_poly_cons(ao_scheme_arg(cons, 0)));
652 }
653
654 ao_poly
655 ao_scheme_do_string_to_list(struct ao_scheme_cons *cons)
656 {
657         if (!ao_scheme_check_argc(_ao_scheme_atom_string2d3elist, cons, 1, 1))
658                 return AO_SCHEME_NIL;
659         if (!ao_scheme_check_argt(_ao_scheme_atom_string2d3elist, cons, 0, AO_SCHEME_STRING, 0))
660                 return AO_SCHEME_NIL;
661         return ao_scheme_string_unpack(ao_scheme_poly_string(ao_scheme_arg(cons, 0)));
662 }
663
664 ao_poly
665 ao_scheme_do_string_ref(struct ao_scheme_cons *cons)
666 {
667         char *string;
668         int32_t ref;
669         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dref, cons, 2, 2))
670                 return AO_SCHEME_NIL;
671         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dref, cons, 0, AO_SCHEME_STRING, 0))
672                 return AO_SCHEME_NIL;
673         ref = ao_scheme_arg_int(_ao_scheme_atom_string2dref, cons, 1);
674         if (ref == AO_SCHEME_NOT_INTEGER)
675                 return AO_SCHEME_NIL;
676         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
677         while (*string && ref) {
678                 ++string;
679                 --ref;
680         }
681         if (!*string)
682                 return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
683                                        _ao_scheme_atom_string2dref,
684                                        ao_scheme_arg(cons, 0),
685                                        ao_scheme_arg(cons, 1));
686         return ao_scheme_int_poly(*string);
687 }
688
689 ao_poly
690 ao_scheme_do_string_length(struct ao_scheme_cons *cons)
691 {
692         char *string;
693
694         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dlength, cons, 1, 1))
695                 return AO_SCHEME_NIL;
696         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dlength, cons, 0, AO_SCHEME_STRING, 0))
697                 return AO_SCHEME_NIL;
698         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
699         return ao_scheme_integer_poly(strlen(string));
700 }
701
702 ao_poly
703 ao_scheme_do_string_copy(struct ao_scheme_cons *cons)
704 {
705         char *string;
706
707         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dcopy, cons, 1, 1))
708                 return AO_SCHEME_NIL;
709         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dcopy, cons, 0, AO_SCHEME_STRING, 0))
710                 return AO_SCHEME_NIL;
711         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
712         return ao_scheme_string_poly(ao_scheme_string_copy(string));
713 }
714
715 ao_poly
716 ao_scheme_do_string_set(struct ao_scheme_cons *cons)
717 {
718         char *string;
719         int32_t ref;
720         int32_t val;
721
722         if (!ao_scheme_check_argc(_ao_scheme_atom_string2dset21, cons, 3, 3))
723                 return AO_SCHEME_NIL;
724         if (!ao_scheme_check_argt(_ao_scheme_atom_string2dset21, cons, 0, AO_SCHEME_STRING, 0))
725                 return AO_SCHEME_NIL;
726         string = ao_scheme_poly_string(ao_scheme_arg(cons, 0));
727         ref = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 1);
728         if (ref == AO_SCHEME_NOT_INTEGER)
729                 return AO_SCHEME_NIL;
730         val = ao_scheme_arg_int(_ao_scheme_atom_string2dset21, cons, 2);
731         if (val == AO_SCHEME_NOT_INTEGER)
732                 return AO_SCHEME_NIL;
733         while (*string && ref) {
734                 ++string;
735                 --ref;
736         }
737         if (!*string)
738                 return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid",
739                                        _ao_scheme_atom_string2dset21,
740                                        ao_scheme_arg(cons, 0),
741                                        ao_scheme_arg(cons, 1));
742         *string = val;
743         return ao_scheme_int_poly(*string);
744 }
745
746 ao_poly
747 ao_scheme_do_flush_output(struct ao_scheme_cons *cons)
748 {
749         if (!ao_scheme_check_argc(_ao_scheme_atom_flush2doutput, cons, 0, 0))
750                 return AO_SCHEME_NIL;
751         ao_scheme_os_flush();
752         return _ao_scheme_bool_true;
753 }
754
755 ao_poly
756 ao_scheme_do_led(struct ao_scheme_cons *cons)
757 {
758         int32_t led;
759         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
760                 return AO_SCHEME_NIL;
761         led = ao_scheme_arg_int(_ao_scheme_atom_led, cons, 0);
762         if (led == AO_SCHEME_NOT_INTEGER)
763                 return AO_SCHEME_NIL;
764         led = ao_scheme_arg(cons, 0);
765         ao_scheme_os_led(ao_scheme_poly_int(led));
766         return led;
767 }
768
769 ao_poly
770 ao_scheme_do_delay(struct ao_scheme_cons *cons)
771 {
772         int32_t delay;
773
774         if (!ao_scheme_check_argc(_ao_scheme_atom_delay, cons, 1, 1))
775                 return AO_SCHEME_NIL;
776         delay = ao_scheme_arg_int(_ao_scheme_atom_delay, cons, 0);
777         if (delay == AO_SCHEME_NOT_INTEGER)
778                 return AO_SCHEME_NIL;
779         ao_scheme_os_delay(delay);
780         return delay;
781 }
782
783 ao_poly
784 ao_scheme_do_eval(struct ao_scheme_cons *cons)
785 {
786         if (!ao_scheme_check_argc(_ao_scheme_atom_eval, cons, 1, 1))
787                 return AO_SCHEME_NIL;
788         ao_scheme_stack->state = eval_sexpr;
789         return cons->car;
790 }
791
792 ao_poly
793 ao_scheme_do_apply(struct ao_scheme_cons *cons)
794 {
795         if (!ao_scheme_check_argc(_ao_scheme_atom_apply, cons, 2, INT_MAX))
796                 return AO_SCHEME_NIL;
797         ao_scheme_stack->state = eval_apply;
798         return ao_scheme_cons_poly(cons);
799 }
800
801 ao_poly
802 ao_scheme_do_read(struct ao_scheme_cons *cons)
803 {
804         if (!ao_scheme_check_argc(_ao_scheme_atom_read, cons, 0, 0))
805                 return AO_SCHEME_NIL;
806         return ao_scheme_read();
807 }
808
809 ao_poly
810 ao_scheme_do_collect(struct ao_scheme_cons *cons)
811 {
812         int     free;
813         (void) cons;
814         free = ao_scheme_collect(AO_SCHEME_COLLECT_FULL);
815         return ao_scheme_integer_poly(free);
816 }
817
818 ao_poly
819 ao_scheme_do_nullp(struct ao_scheme_cons *cons)
820 {
821         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
822                 return AO_SCHEME_NIL;
823         if (ao_scheme_arg(cons, 0) == AO_SCHEME_NIL)
824                 return _ao_scheme_bool_true;
825         else
826                 return _ao_scheme_bool_false;
827 }
828
829 ao_poly
830 ao_scheme_do_not(struct ao_scheme_cons *cons)
831 {
832         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
833                 return AO_SCHEME_NIL;
834         if (ao_scheme_arg(cons, 0) == _ao_scheme_bool_false)
835                 return _ao_scheme_bool_true;
836         else
837                 return _ao_scheme_bool_false;
838 }
839
840 static ao_poly
841 ao_scheme_do_typep(int type, struct ao_scheme_cons *cons)
842 {
843         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
844                 return AO_SCHEME_NIL;
845         if (ao_scheme_poly_type(ao_scheme_arg(cons, 0)) == type)
846                 return _ao_scheme_bool_true;
847         return _ao_scheme_bool_false;
848 }
849
850 ao_poly
851 ao_scheme_do_pairp(struct ao_scheme_cons *cons)
852 {
853         ao_poly v;
854         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
855                 return AO_SCHEME_NIL;
856         v = ao_scheme_arg(cons, 0);
857         if (v != AO_SCHEME_NIL && ao_scheme_poly_type(v) == AO_SCHEME_CONS)
858                 return _ao_scheme_bool_true;
859         return _ao_scheme_bool_false;
860 }
861
862 ao_poly
863 ao_scheme_do_integerp(struct ao_scheme_cons *cons)
864 {
865 #ifdef AO_SCHEME_FEATURE_BIGINT
866         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
867                 return AO_SCHEME_NIL;
868         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
869         case AO_SCHEME_INT:
870         case AO_SCHEME_BIGINT:
871                 return _ao_scheme_bool_true;
872         default:
873                 return _ao_scheme_bool_false;
874         }
875 #else
876         return ao_scheme_do_typep(AO_SCHEME_INT, cons);
877 #endif
878 }
879
880 ao_poly
881 ao_scheme_do_numberp(struct ao_scheme_cons *cons)
882 {
883 #if defined(AO_SCHEME_FEATURE_BIGINT) || defined(AO_SCHEME_FEATURE_FLOAT)
884         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
885                 return AO_SCHEME_NIL;
886         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
887         case AO_SCHEME_INT:
888 #ifdef AO_SCHEME_FEATURE_BIGINT
889         case AO_SCHEME_BIGINT:
890 #endif
891 #ifdef AO_SCHEME_FEATURE_FLOAT
892         case AO_SCHEME_FLOAT:
893 #endif
894                 return _ao_scheme_bool_true;
895         default:
896                 return _ao_scheme_bool_false;
897         }
898 #else
899         return ao_scheme_do_integerp(cons);
900 #endif
901 }
902
903 ao_poly
904 ao_scheme_do_stringp(struct ao_scheme_cons *cons)
905 {
906         return ao_scheme_do_typep(AO_SCHEME_STRING, cons);
907 }
908
909 ao_poly
910 ao_scheme_do_symbolp(struct ao_scheme_cons *cons)
911 {
912         return ao_scheme_do_typep(AO_SCHEME_ATOM, cons);
913 }
914
915 ao_poly
916 ao_scheme_do_booleanp(struct ao_scheme_cons *cons)
917 {
918         return ao_scheme_do_typep(AO_SCHEME_BOOL, cons);
919 }
920
921 ao_poly
922 ao_scheme_do_procedurep(struct ao_scheme_cons *cons)
923 {
924         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
925                 return AO_SCHEME_NIL;
926         switch (ao_scheme_poly_type(ao_scheme_arg(cons, 0))) {
927         case AO_SCHEME_BUILTIN:
928         case AO_SCHEME_LAMBDA:
929                 return _ao_scheme_bool_true;
930         default:
931         return _ao_scheme_bool_false;
932         }
933 }
934
935 /* This one is special -- a list is either nil or
936  * a 'proper' list with only cons cells
937  */
938 ao_poly
939 ao_scheme_do_listp(struct ao_scheme_cons *cons)
940 {
941         ao_poly v;
942         if (!ao_scheme_check_argc(_ao_scheme_atom_list3f, cons, 1, 1))
943                 return AO_SCHEME_NIL;
944         v = ao_scheme_arg(cons, 0);
945         for (;;) {
946                 if (v == AO_SCHEME_NIL)
947                         return _ao_scheme_bool_true;
948                 if (ao_scheme_poly_type(v) != AO_SCHEME_CONS)
949                         return _ao_scheme_bool_false;
950                 v = ao_scheme_poly_cons(v)->cdr;
951         }
952 }
953
954 ao_poly
955 ao_scheme_do_set_car(struct ao_scheme_cons *cons)
956 {
957         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
958                 return AO_SCHEME_NIL;
959         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
960                 return AO_SCHEME_NIL;
961         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->car = ao_scheme_arg(cons, 1);
962 }
963
964 ao_poly
965 ao_scheme_do_set_cdr(struct ao_scheme_cons *cons)
966 {
967         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 2, 2))
968                 return AO_SCHEME_NIL;
969         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_CONS, 0))
970                 return AO_SCHEME_NIL;
971         return ao_scheme_poly_cons(ao_scheme_arg(cons, 0))->cdr = ao_scheme_arg(cons, 1);
972 }
973
974 ao_poly
975 ao_scheme_do_symbol_to_string(struct ao_scheme_cons *cons)
976 {
977         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
978                 return AO_SCHEME_NIL;
979         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_ATOM, 0))
980                 return AO_SCHEME_NIL;
981         return ao_scheme_string_poly(ao_scheme_string_copy(ao_scheme_poly_atom(ao_scheme_arg(cons, 0))->name));
982 }
983
984 ao_poly
985 ao_scheme_do_string_to_symbol(struct ao_scheme_cons *cons)
986 {
987         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
988                 return AO_SCHEME_NIL;
989         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_STRING, 0))
990                 return AO_SCHEME_NIL;
991
992         return ao_scheme_atom_poly(ao_scheme_atom_intern(ao_scheme_poly_string(ao_scheme_arg(cons, 0))));
993 }
994
995 ao_poly
996 ao_scheme_do_read_char(struct ao_scheme_cons *cons)
997 {
998         int     c;
999         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1000                 return AO_SCHEME_NIL;
1001         c = getchar();
1002         return ao_scheme_int_poly(c);
1003 }
1004
1005 ao_poly
1006 ao_scheme_do_write_char(struct ao_scheme_cons *cons)
1007 {
1008         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 1, 1))
1009                 return AO_SCHEME_NIL;
1010         if (!ao_scheme_check_argt(_ao_scheme_atom_led, cons, 0, AO_SCHEME_INT, 0))
1011                 return AO_SCHEME_NIL;
1012         putchar(ao_scheme_poly_integer(ao_scheme_arg(cons, 0)));
1013         return _ao_scheme_bool_true;
1014 }
1015
1016 ao_poly
1017 ao_scheme_do_exit(struct ao_scheme_cons *cons)
1018 {
1019         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1020                 return AO_SCHEME_NIL;
1021         ao_scheme_exception |= AO_SCHEME_EXIT;
1022         return _ao_scheme_bool_true;
1023 }
1024
1025 ao_poly
1026 ao_scheme_do_current_jiffy(struct ao_scheme_cons *cons)
1027 {
1028         int     jiffy;
1029
1030         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1031                 return AO_SCHEME_NIL;
1032         jiffy = ao_scheme_os_jiffy();
1033         return (ao_scheme_int_poly(jiffy));
1034 }
1035
1036 ao_poly
1037 ao_scheme_do_current_second(struct ao_scheme_cons *cons)
1038 {
1039         int     second;
1040
1041         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1042                 return AO_SCHEME_NIL;
1043         second = ao_scheme_os_jiffy() / AO_SCHEME_JIFFIES_PER_SECOND;
1044         return (ao_scheme_int_poly(second));
1045 }
1046
1047 ao_poly
1048 ao_scheme_do_jiffies_per_second(struct ao_scheme_cons *cons)
1049 {
1050         if (!ao_scheme_check_argc(_ao_scheme_atom_led, cons, 0, 0))
1051                 return AO_SCHEME_NIL;
1052         return (ao_scheme_int_poly(AO_SCHEME_JIFFIES_PER_SECOND));
1053 }
1054
1055 #ifdef AO_SCHEME_FEATURE_VECTOR
1056
1057 ao_poly
1058 ao_scheme_do_vector(struct ao_scheme_cons *cons)
1059 {
1060         return ao_scheme_vector_poly(ao_scheme_list_to_vector(cons));
1061 }
1062
1063 ao_poly
1064 ao_scheme_do_make_vector(struct ao_scheme_cons *cons)
1065 {
1066         int32_t k;
1067
1068         if (!ao_scheme_check_argc(_ao_scheme_atom_make2dvector, cons, 2, 2))
1069                 return AO_SCHEME_NIL;
1070         k = ao_scheme_arg_int(_ao_scheme_atom_make2dvector, cons, 0);
1071         if (k == AO_SCHEME_NOT_INTEGER)
1072                 return AO_SCHEME_NIL;
1073         return ao_scheme_vector_poly(ao_scheme_vector_alloc(k, ao_scheme_arg(cons, 1)));
1074 }
1075
1076 ao_poly
1077 ao_scheme_do_vector_ref(struct ao_scheme_cons *cons)
1078 {
1079         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dref, cons, 2, 2))
1080                 return AO_SCHEME_NIL;
1081         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dref, cons, 0, AO_SCHEME_VECTOR, 0))
1082                 return AO_SCHEME_NIL;
1083         return ao_scheme_vector_get(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1));
1084 }
1085
1086 ao_poly
1087 ao_scheme_do_vector_set(struct ao_scheme_cons *cons)
1088 {
1089         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2dset21, cons, 3, 3))
1090                 return AO_SCHEME_NIL;
1091         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2dset21, cons, 0, AO_SCHEME_VECTOR, 0))
1092                 return AO_SCHEME_NIL;
1093         return ao_scheme_vector_set(ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1), ao_scheme_arg(cons, 2));
1094 }
1095
1096 ao_poly
1097 ao_scheme_do_list_to_vector(struct ao_scheme_cons *cons)
1098 {
1099         if (!ao_scheme_check_argc(_ao_scheme_atom_list2d3evector, cons, 1, 1))
1100                 return AO_SCHEME_NIL;
1101         if (!ao_scheme_check_argt(_ao_scheme_atom_list2d3evector, cons, 0, AO_SCHEME_CONS, 0))
1102                 return AO_SCHEME_NIL;
1103         return ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(ao_scheme_arg(cons, 0))));
1104 }
1105
1106 ao_poly
1107 ao_scheme_do_vector_to_list(struct ao_scheme_cons *cons)
1108 {
1109         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
1110                 return AO_SCHEME_NIL;
1111         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
1112                 return AO_SCHEME_NIL;
1113         return ao_scheme_cons_poly(ao_scheme_vector_to_list(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))));
1114 }
1115
1116 ao_poly
1117 ao_scheme_do_vector_length(struct ao_scheme_cons *cons)
1118 {
1119         if (!ao_scheme_check_argc(_ao_scheme_atom_vector2d3elist, cons, 1, 1))
1120                 return AO_SCHEME_NIL;
1121         if (!ao_scheme_check_argt(_ao_scheme_atom_vector2d3elist, cons, 0, AO_SCHEME_VECTOR, 0))
1122                 return AO_SCHEME_NIL;
1123         return ao_scheme_integer_poly(ao_scheme_poly_vector(ao_scheme_arg(cons, 0))->length);
1124 }
1125
1126 ao_poly
1127 ao_scheme_do_vectorp(struct ao_scheme_cons *cons)
1128 {
1129         return ao_scheme_do_typep(AO_SCHEME_VECTOR, cons);
1130 }
1131
1132 #endif /* AO_SCHEME_FEATURE_VECTOR */
1133
1134 #define AO_SCHEME_BUILTIN_FUNCS
1135 #include "ao_scheme_builtin.h"