altos/lisp: get builtin macros working again
[fw/altos] / src / lisp / ao_lisp_eval.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_lisp.h"
16
17 #if 1
18 static int stack_depth;
19 #define DBG_INDENT()    do { int _s; for(_s = 0; _s < stack_depth; _s++) printf("  "); } while(0)
20 #define DBG_IN()        (++stack_depth)
21 #define DBG_OUT()       (--stack_depth)
22 #define DBG(...)        printf(__VA_ARGS__)
23 #define DBGI(...)       do { DBG_INDENT(); DBG(__VA_ARGS__); } while (0)
24 #define DBG_CONS(a)     ao_lisp_cons_print(ao_lisp_cons_poly(a))
25 #define DBG_POLY(a)     ao_lisp_poly_print(a)
26 #define OFFSET(a)       ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1)
27 #else
28 #define DBG_INDENT()
29 #define DBG_IN()
30 #define DBG_OUT()
31 #define DBG(...)
32 #define DBGI(...)
33 #define DBG_CONS(a)
34 #define DBG_POLY(a)
35 #endif
36
37 enum eval_state {
38         eval_sexpr,
39         eval_val,
40         eval_exec,
41         eval_exec_direct
42 };
43
44 struct ao_lisp_stack {
45         ao_poly                 prev;
46         uint8_t                 state;
47         uint8_t                 macro;
48         ao_poly                 actuals;
49         ao_poly                 formals;
50         ao_poly                 formals_tail;
51         ao_poly                 frame;
52 };
53
54 static struct ao_lisp_stack *
55 ao_lisp_poly_stack(ao_poly p)
56 {
57         return ao_lisp_ref(p);
58 }
59
60 static ao_poly
61 ao_lisp_stack_poly(struct ao_lisp_stack *stack)
62 {
63         return ao_lisp_poly(stack, AO_LISP_OTHER);
64 }
65
66 static int
67 stack_size(void *addr)
68 {
69         (void) addr;
70         return sizeof (struct ao_lisp_stack);
71 }
72
73 static void
74 stack_mark(void *addr)
75 {
76         struct ao_lisp_stack    *stack = addr;
77         for (;;) {
78                 ao_lisp_poly_mark(stack->actuals);
79                 ao_lisp_poly_mark(stack->formals);
80                 ao_lisp_poly_mark(stack->frame);
81                 stack = ao_lisp_poly_stack(stack->prev);
82                 if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack)))
83                         break;
84         }
85 }
86
87 static void
88 stack_move(void *addr)
89 {
90         struct ao_lisp_stack    *stack = addr;
91
92         for (;;) {
93                 struct ao_lisp_stack *prev;
94                 stack->actuals = ao_lisp_poly_move(stack->actuals);
95                 stack->formals = ao_lisp_poly_move(stack->formals);
96                 stack->frame = ao_lisp_poly_move(stack->frame);
97                 prev = ao_lisp_ref(stack->prev);
98                 prev = ao_lisp_move_memory(prev, sizeof (struct ao_lisp_stack));
99                 stack->prev = ao_lisp_stack_poly(prev);
100                 stack = prev;
101         }
102 }
103
104 static const struct ao_lisp_type ao_lisp_stack_type = {
105         .size = stack_size,
106         .mark = stack_mark,
107         .move = stack_move
108 };
109
110
111 static struct ao_lisp_stack     *ao_lisp_stack;
112 static uint8_t been_here;
113
114 ao_poly
115 ao_lisp_set_cond(struct ao_lisp_cons *c)
116 {
117         return AO_LISP_NIL;
118 }
119
120 static void
121 ao_lisp_stack_reset(struct ao_lisp_stack *stack)
122 {
123         stack->state = eval_sexpr;
124         stack->macro = 0;
125         stack->actuals = AO_LISP_NIL;
126         stack->formals = AO_LISP_NIL;
127         stack->formals_tail = AO_LISP_NIL;
128         stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
129 }
130
131 static struct ao_lisp_stack *
132 ao_lisp_stack_push(void)
133 {
134         struct ao_lisp_stack    *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
135         if (!stack)
136                 return NULL;
137         stack->prev = ao_lisp_stack_poly(ao_lisp_stack);
138         ao_lisp_stack_reset(stack);
139         ao_lisp_stack = stack;
140         DBGI("stack push\n");
141         DBG_IN();
142         return stack;
143 }
144
145 static struct ao_lisp_stack *
146 ao_lisp_stack_pop(void)
147 {
148         if (!ao_lisp_stack)
149                 return NULL;
150         DBG_OUT();
151         DBGI("stack pop\n");
152         ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev);
153         if (ao_lisp_stack)
154                 ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
155         else
156                 ao_lisp_frame_current = NULL;
157         return ao_lisp_stack;
158 }
159
160 static void
161 ao_lisp_stack_clear(void)
162 {
163         ao_lisp_stack = NULL;
164         ao_lisp_frame_current = NULL;
165 }
166
167
168 static ao_poly
169 func_type(ao_poly func)
170 {
171         struct ao_lisp_cons     *cons;
172         struct ao_lisp_cons     *args;
173         int                     f;
174
175         DBGI("func type "); DBG_POLY(func); DBG("\n");
176         if (func == AO_LISP_NIL)
177                 return ao_lisp_error(AO_LISP_INVALID, "func is nil");
178         if (ao_lisp_poly_type(func) == AO_LISP_BUILTIN) {
179                 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(func);
180                 return b->args;
181         } else if (ao_lisp_poly_type(func) == AO_LISP_CONS) {
182                 cons = ao_lisp_poly_cons(func);
183                 if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3))
184                         return AO_LISP_NIL;
185                 if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0))
186                         return AO_LISP_NIL;
187                 if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1))
188                         return AO_LISP_NIL;
189                 args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1));
190                 f = 0;
191                 while (args) {
192                         if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) {
193                                 return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f);
194                         }
195                         args = ao_lisp_poly_cons(args->cdr);
196                         f++;
197                 }
198                 return ao_lisp_arg(cons, 0);
199         } else
200                 return ao_lisp_error(AO_LISP_INVALID, "not a func");
201 }
202
203 static int
204 ao_lisp_cons_length(struct ao_lisp_cons *cons)
205 {
206         int     len = 0;
207         while (cons) {
208                 len++;
209                 cons = ao_lisp_poly_cons(cons->cdr);
210         }
211         return len;
212 }
213
214 static ao_poly
215 ao_lisp_lambda(struct ao_lisp_cons *cons)
216 {
217         ao_poly                 type;
218         struct ao_lisp_cons     *lambda;
219         struct ao_lisp_cons     *args;
220         struct ao_lisp_frame    *next_frame;
221         int                     args_wanted;
222         int                     args_provided;
223
224         lambda = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
225         DBGI("lambda "); DBG_CONS(lambda); DBG("\n");
226         type = ao_lisp_arg(lambda, 0);
227         args = ao_lisp_poly_cons(ao_lisp_arg(lambda, 1));
228
229         args_wanted = ao_lisp_cons_length(args);
230
231         /* Create a frame to hold the variables
232          */
233         if (type == _ao_lisp_atom_lambda)
234                 args_provided = ao_lisp_cons_length(cons) - 1;
235         else
236                 args_provided = 1;
237         if (args_wanted != args_provided)
238                 return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided);
239         next_frame = ao_lisp_frame_new(args_wanted, 0);
240         DBGI("new frame %d\n", OFFSET(next_frame));
241         switch (type) {
242         case _ao_lisp_atom_lambda: {
243                 int                     f;
244                 struct ao_lisp_cons     *vals = ao_lisp_poly_cons(cons->cdr);
245
246                 for (f = 0; f < args_wanted; f++) {
247                         next_frame->vals[f].atom = args->car;
248                         next_frame->vals[f].val = vals->car;
249                         args = ao_lisp_poly_cons(args->cdr);
250                         vals = ao_lisp_poly_cons(vals->cdr);
251                 }
252                 break;
253         }
254         case _ao_lisp_atom_lexpr:
255         case _ao_lisp_atom_nlambda:
256                 next_frame->vals[0].atom = args->car;
257                 next_frame->vals[0].val = cons->cdr;
258                 break;
259         case _ao_lisp_atom_macro:
260                 next_frame->vals[0].atom = args->car;
261                 next_frame->vals[0].val = ao_lisp_cons_poly(cons);
262                 break;
263         }
264         next_frame->next = ao_lisp_frame_poly(ao_lisp_frame_current);
265         ao_lisp_frame_current = next_frame;
266         ao_lisp_stack->frame = ao_lisp_frame_poly(next_frame);
267         return ao_lisp_arg(lambda, 2);
268 }
269
270 ao_poly
271 ao_lisp_eval(ao_poly v)
272 {
273         struct ao_lisp_stack    *stack;
274         ao_poly                 formal;
275
276         if (!been_here) {
277                 been_here = 1;
278                 ao_lisp_root_add(&ao_lisp_stack_type, &stack);
279         }
280
281         stack = ao_lisp_stack_push();
282
283         for (;;) {
284                 if (ao_lisp_exception)
285                         return AO_LISP_NIL;
286                 switch (stack->state) {
287                 case eval_sexpr:
288                         DBGI("sexpr: "); DBG_POLY(v); DBG("\n");
289                         switch (ao_lisp_poly_type(v)) {
290                         case AO_LISP_CONS:
291                                 if (v == AO_LISP_NIL) {
292                                         stack->state = eval_exec;
293                                         break;
294                                 }
295                                 stack->actuals = v;
296                                 stack = ao_lisp_stack_push();
297                                 v = ao_lisp_poly_cons(v)->car;
298                                 break;
299                         case AO_LISP_ATOM:
300                                 v = ao_lisp_atom_get(v);
301                                 /* fall through */
302                         case AO_LISP_INT:
303                         case AO_LISP_STRING:
304                                 stack->state = eval_val;
305                                 break;
306                         }
307                         break;
308                 case eval_val:
309                         DBGI("val: "); DBG_POLY(v); DBG("\n");
310                         stack = ao_lisp_stack_pop();
311                         if (!stack)
312                                 return v;
313
314                         stack->state = eval_sexpr;
315                         /* Check what kind of function we've got */
316                         if (!stack->formals) {
317                                 switch (func_type(v)) {
318                                 case AO_LISP_LAMBDA:
319                                 case _ao_lisp_atom_lambda:
320                                 case AO_LISP_LEXPR:
321                                 case _ao_lisp_atom_lexpr:
322                                         DBGI(".. lambda or lexpr\n");
323                                         break;
324                                 case AO_LISP_MACRO:
325                                 case _ao_lisp_atom_macro:
326                                         stack->macro = 1;
327                                 case AO_LISP_NLAMBDA:
328                                 case _ao_lisp_atom_nlambda:
329                                         DBGI(".. nlambda or macro\n");
330                                         stack->formals = stack->actuals;
331                                         stack->state = eval_exec_direct;
332                                         break;
333                                 }
334                                 if (stack->state == eval_exec_direct)
335                                         break;
336                         }
337
338                         formal = ao_lisp_cons_poly(ao_lisp_cons_cons(v, NULL));
339                         if (!formal) {
340                                 ao_lisp_stack_clear();
341                                 return AO_LISP_NIL;
342                         }
343
344                         if (stack->formals_tail)
345                                 ao_lisp_poly_cons(stack->formals_tail)->cdr = formal;
346                         else
347                                 stack->formals = formal;
348                         stack->formals_tail = formal;
349
350                         DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n");
351
352                         v = ao_lisp_poly_cons(stack->actuals)->cdr;
353
354                         break;
355                 case eval_exec:
356                         v = ao_lisp_poly_cons(stack->formals)->car;
357                 case eval_exec_direct:
358                         DBGI("exec: macro %d ", stack->macro); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n");
359                         if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
360                                 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
361                                 struct ao_lisp_cons     *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr);
362
363                                 DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n");
364                                 v = ao_lisp_func(b) (f);
365                                 DBGI("builtin result:"); DBG_POLY(v); DBG ("\n");
366                                 if (ao_lisp_exception) {
367                                         ao_lisp_stack_clear();
368                                         return AO_LISP_NIL;
369                                 }
370                                 if (stack->macro)
371                                         stack->state = eval_sexpr;
372                                 else
373                                         stack->state = eval_val;
374                                 stack->macro = 0;
375                                 break;
376                         } else {
377                                 v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals));
378                                 ao_lisp_stack_reset(stack);
379                         }
380                         break;
381                 }
382         }
383 }
384 #if 0
385
386
387         restart:
388                 if (cond) {
389                         DBGI("cond is now "); DBG_CONS(cond); DBG("\n");
390                         if (cond->car == AO_LISP_NIL) {
391                                 cond = AO_LISP_NIL;
392                                 v = AO_LISP_NIL;
393                         } else {
394                                 if (ao_lisp_poly_type(cond->car) != AO_LISP_CONS) {
395                                         ao_lisp_error(AO_LISP_INVALID, "malformed cond");
396                                         goto bail;
397                                 }
398                                 v = ao_lisp_poly_cons(cond->car)->car;
399                         }
400                 }
401
402                 /* Build stack frames for each list */
403                 while (ao_lisp_poly_type(v) == AO_LISP_CONS) {
404                         if (v == AO_LISP_NIL)
405                                 break;
406
407                         /* Push existing bits on the stack */
408                         if (cons++)
409                                 if (!ao_lisp_stack_push())
410                                         goto bail;
411
412                         actuals = ao_lisp_poly_cons(v);
413                         formals = NULL;
414                         formals_tail = NULL;
415                         save_cond = cond;
416                         cond = NULL;
417
418                         v = actuals->car;
419
420 //                      DBG("start: stack"); DBG_CONS(stack); DBG("\n");
421 //                      DBG("start: actuals"); DBG_CONS(actuals); DBG("\n");
422 //                      DBG("start: formals"); DBG_CONS(formals); DBG("\n");
423                 }
424
425                         if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
426                                 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
427                                 switch (b->args) {
428                                 case AO_LISP_NLAMBDA:
429                                         formals = actuals;
430                                         goto eval;
431
432                                 case AO_LISP_MACRO:
433                                         v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr));
434                                         DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals));
435                                         DBG(" -> "); DBG_POLY(v);
436                                         DBG("\n");
437                                         if (ao_lisp_poly_type(v) != AO_LISP_CONS) {
438                                                 ao_lisp_error(AO_LISP_INVALID, "macro didn't return list");
439                                                 goto bail;
440                                         }
441                                         /* Reset frame to the new list */
442                                         actuals = ao_lisp_poly_cons(v);
443                                         v = actuals->car;
444                                         goto restart;
445                                 }
446                 /* Evaluate primitive types */
447
448                 DBG ("actual: "); DBG_POLY(v); DBG("\n");
449
450                 switch (ao_lisp_poly_type(v)) {
451                 case AO_LISP_INT:
452                 case AO_LISP_STRING:
453                         break;
454                 case AO_LISP_ATOM:
455                         v = ao_lisp_atom_get(v);
456                         break;
457                 }
458
459                 while (cons) {
460                         DBG("add formal: "); DBG_POLY(v); DBG("\n");
461
462                         /* We've processed the first element of the list, go check
463                          * what kind of function we've got
464                          */
465                         if (formals == NULL) {
466                                 if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
467                                         struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
468                                         switch (b->args) {
469                                         case AO_LISP_NLAMBDA:
470                                                 formals = actuals;
471                                                 goto eval;
472
473                                         case AO_LISP_MACRO:
474                                                 v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr));
475                                                 DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals));
476                                                 DBG(" -> "); DBG_POLY(v);
477                                                 DBG("\n");
478                                                 if (ao_lisp_poly_type(v) != AO_LISP_CONS) {
479                                                         ao_lisp_error(AO_LISP_INVALID, "macro didn't return list");
480                                                         goto bail;
481                                                 }
482                                                 /* Reset frame to the new list */
483                                                 actuals = ao_lisp_poly_cons(v);
484                                                 v = actuals->car;
485                                                 goto restart;
486                                         }
487                                 } else {
488                                         switch (func_type(v)) {
489                                         case _ao_lisp_atom_lambda:
490                                         case _ao_lisp_atom_lexpr:
491                                                 break;
492                                         case _ao_lisp_atom_nlambda:
493                                                 formals = actuals;
494                                                 goto eval;
495                                         case _ao_lisp_atom_macro:
496                                                 break;
497                                         default:
498                                                 ao_lisp_error(AO_LISP_INVALID, "operator is not a function");
499                                                 goto bail;
500                                         }
501                                 }
502                         }
503
504                         formal = ao_lisp_cons_cons(v, NULL);
505                         if (formals_tail)
506                                 formals_tail->cdr = ao_lisp_cons_poly(formal);
507                         else
508                                 formals = formal;
509                         formals_tail = formal;
510                         actuals = ao_lisp_poly_cons(actuals->cdr);
511
512                         DBG("formals: ");
513                         DBG_CONS(formals);
514                         DBG("\n");
515                         DBG("actuals: ");
516                         DBG_CONS(actuals);
517                         DBG("\n");
518
519                         /* Process all of the arguments */
520                         if (actuals) {
521                                 v = actuals->car;
522                                 break;
523                         }
524
525                         v = formals->car;
526
527                 eval:
528
529                         /* Evaluate the resulting list */
530                         if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
531                                 struct ao_lisp_cons *old_cond = cond;
532                                 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
533
534                                 v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr));
535
536                                 DBG ("eval: ");
537                                 DBG_CONS(formals);
538                                 DBG(" -> ");
539                                 DBG_POLY(v);
540                                 DBG ("\n");
541                                 if (ao_lisp_exception)
542                                         goto bail;
543
544                                 if (cond != old_cond) {
545                                         DBG("cond changed from "); DBG_CONS(old_cond); DBG(" to "); DBG_CONS(cond); DBG("\n");
546                                         actuals = NULL;
547                                         formals = 0;
548                                         formals_tail = 0;
549                                         save_cons = cons;
550                                         cons = 0;
551                                         goto restart;
552                                 }
553                         } else {
554                                 v = ao_lisp_lambda(formals);
555                                 if (ao_lisp_exception)
556                                         goto bail;
557                         }
558
559                 cond_done:
560                         --cons;
561                         if (cons) {
562                                 ao_lisp_stack_pop();
563 //                              DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n");
564 //                              DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n");
565 //                              DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n");
566                         } else {
567                                 actuals = 0;
568                                 formals = 0;
569                                 formals_tail = 0;
570                                 ao_lisp_frame_current = 0;
571                         }
572                         if (next_frame) {
573                                 ao_lisp_frame_current = next_frame;
574                                 DBG("next frame %d\n", OFFSET(next_frame));
575                                 next_frame = 0;
576                                 goto restart;
577                         }
578                 }
579                 if (cond) {
580                         DBG("next cond cons is %d\n", cons);
581                         if (v) {
582                                 v = ao_lisp_poly_cons(cond->car)->cdr;
583                                 cond = 0;
584                                 cons = save_cons;
585                                 if (v != AO_LISP_NIL) {
586                                         v = ao_lisp_poly_cons(v)->car;
587                                         DBG("cond complete, sexpr is "); DBG_POLY(v); DBG("\n");
588                                 }
589                                 goto cond_done;
590                         } else {
591                                 cond = ao_lisp_poly_cons(cond->cdr);
592                                 DBG("next cond is "); DBG_CONS(cond); DBG("\n");
593                                 goto restart;
594                         }
595                 }
596                 if (!cons)
597                         break;
598         }
599         DBG("leaving frame at %d\n", OFFSET(ao_lisp_frame_current));
600         return v;
601 bail:
602         ao_lisp_stack_clear();
603         return AO_LISP_NIL;
604 #endif
605