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