altos/lisp: Add 'else' sematics to cond
[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 #include <assert.h>
17
18 struct ao_lisp_stack            *ao_lisp_stack;
19 ao_poly                         ao_lisp_v;
20
21 ao_poly
22 ao_lisp_set_cond(struct ao_lisp_cons *c)
23 {
24         ao_lisp_stack->state = eval_cond;
25         ao_lisp_stack->sexprs = ao_lisp_cons_poly(c);
26         return AO_LISP_NIL;
27 }
28
29 static int
30 func_type(ao_poly func)
31 {
32         if (func == AO_LISP_NIL)
33                 return ao_lisp_error(AO_LISP_INVALID, "func is nil");
34         switch (ao_lisp_poly_type(func)) {
35         case AO_LISP_BUILTIN:
36                 return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK;
37         case AO_LISP_LAMBDA:
38                 return ao_lisp_poly_lambda(func)->args;
39         case AO_LISP_STACK:
40                 return AO_LISP_FUNC_LAMBDA;
41         default:
42                 ao_lisp_error(AO_LISP_INVALID, "not a func");
43                 return -1;
44         }
45 }
46
47 /*
48  * Flattened eval to avoid stack issues
49  */
50
51 /*
52  * Evaluate an s-expression
53  *
54  * For a list, evaluate all of the elements and
55  * then execute the resulting function call.
56  *
57  * Each element of the list is evaluated in
58  * a clean stack context.
59  *
60  * The current stack state is set to 'formal' so that
61  * when the evaluation is complete, the value
62  * will get appended to the values list.
63  *
64  * For other types, compute the value directly.
65  */
66
67 static int
68 ao_lisp_eval_sexpr(void)
69 {
70         DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n");
71         switch (ao_lisp_poly_type(ao_lisp_v)) {
72         case AO_LISP_CONS:
73                 if (ao_lisp_v == AO_LISP_NIL) {
74                         if (!ao_lisp_stack->values) {
75                                 /*
76                                  * empty list evaluates to empty list
77                                  */
78                                 ao_lisp_v = AO_LISP_NIL;
79                                 ao_lisp_stack->state = eval_val;
80                         } else {
81                                 /*
82                                  * done with arguments, go execute it
83                                  */
84                                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car;
85                                 ao_lisp_stack->state = eval_exec;
86                         }
87                 } else {
88                         if (!ao_lisp_stack->values)
89                                 ao_lisp_stack->list = ao_lisp_v;
90                         /*
91                          * Evaluate another argument and then switch
92                          * to 'formal' to add the value to the values
93                          * list
94                          */
95                         ao_lisp_stack->sexprs = ao_lisp_v;
96                         ao_lisp_stack->state = eval_formal;
97                         if (!ao_lisp_stack_push())
98                                 return 0;
99                         /*
100                          * push will reset the state to 'sexpr', which
101                          * will evaluate the expression
102                          */
103                         ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
104                 }
105                 break;
106         case AO_LISP_ATOM:
107                 DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
108                 ao_lisp_v = ao_lisp_atom_get(ao_lisp_v);
109                 /* fall through */
110         case AO_LISP_BOOL:
111         case AO_LISP_INT:
112         case AO_LISP_STRING:
113         case AO_LISP_BUILTIN:
114         case AO_LISP_LAMBDA:
115                 ao_lisp_stack->state = eval_val;
116                 break;
117         }
118         DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n");
119         return 1;
120 }
121
122 /*
123  * A value has been computed.
124  *
125  * If the value was computed from a macro,
126  * then we want to reset the current context
127  * to evaluate the macro result again.
128  *
129  * If not a macro, then pop the stack.
130  * If the stack is empty, we're done.
131  * Otherwise, the stack will contain
132  * the next state.
133  */
134
135 static int
136 ao_lisp_eval_val(void)
137 {
138         DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n");
139         /*
140          * Value computed, pop the stack
141          * to figure out what to do with the value
142          */
143         ao_lisp_stack_pop();
144         DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1);
145         return 1;
146 }
147
148 /*
149  * A formal has been computed.
150  *
151  * If this is the first formal, then check to see if we've got a
152  * lamda/lexpr or macro/nlambda.
153  *
154  * For lambda/lexpr, go compute another formal.  This will terminate
155  * when the sexpr state sees nil.
156  *
157  * For macro/nlambda, we're done, so move the sexprs into the values
158  * and go execute it.
159  *
160  * Macros have an additional step of saving a stack frame holding the
161  * macro value execution context, which then gets the result of the
162  * macro to run
163  */
164
165 static int
166 ao_lisp_eval_formal(void)
167 {
168         ao_poly                 formal;
169         struct ao_lisp_stack    *prev;
170
171         DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n");
172
173         /* Check what kind of function we've got */
174         if (!ao_lisp_stack->values) {
175                 switch (func_type(ao_lisp_v)) {
176                 case AO_LISP_FUNC_LAMBDA:
177                 case AO_LISP_FUNC_LEXPR:
178                         DBGI(".. lambda or lexpr\n");
179                         break;
180                 case AO_LISP_FUNC_MACRO:
181                         /* Evaluate the result once more */
182                         ao_lisp_stack->state = eval_macro;
183                         if (!ao_lisp_stack_push())
184                                 return 0;
185
186                         /* After the function returns, take that
187                          * value and re-evaluate it
188                          */
189                         prev = ao_lisp_poly_stack(ao_lisp_stack->prev);
190                         ao_lisp_stack->sexprs = prev->sexprs;
191
192                         DBGI(".. start macro\n");
193                         DBGI(".. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
194                         DBGI(".. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
195                         DBG_FRAMES();
196
197                         /* fall through ... */
198                 case AO_LISP_FUNC_NLAMBDA:
199                         DBGI(".. nlambda or macro\n");
200
201                         /* use the raw sexprs as values */
202                         ao_lisp_stack->values = ao_lisp_stack->sexprs;
203                         ao_lisp_stack->values_tail = AO_LISP_NIL;
204                         ao_lisp_stack->state = eval_exec;
205
206                         /* ready to execute now */
207                         return 1;
208                 case -1:
209                         return 0;
210                 }
211         }
212
213         /* Append formal to list of values */
214         formal = ao_lisp__cons(ao_lisp_v, AO_LISP_NIL);
215         if (!formal)
216                 return 0;
217
218         if (ao_lisp_stack->values_tail)
219                 ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal;
220         else
221                 ao_lisp_stack->values = formal;
222         ao_lisp_stack->values_tail = formal;
223
224         DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
225
226         /*
227          * Step to the next argument, if this is last, then
228          * 'sexpr' will end up switching to 'exec'
229          */
230         ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
231
232         ao_lisp_stack->state = eval_sexpr;
233
234         DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n");
235         return 1;
236 }
237
238 /*
239  * Start executing a function call
240  *
241  * Most builtins are easy, just call the function.
242  * 'cond' is magic; it sticks the list of clauses
243  * in 'sexprs' and switches to 'cond' state. That
244  * bit of magic is done in ao_lisp_set_cond.
245  *
246  * Lambdas build a new frame to hold the locals and
247  * then re-use the current stack context to evaluate
248  * the s-expression from the lambda.
249  */
250
251 static int
252 ao_lisp_eval_exec(void)
253 {
254         ao_poly v;
255         struct ao_lisp_builtin  *builtin;
256
257         DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n");
258         ao_lisp_stack->sexprs = AO_LISP_NIL;
259         switch (ao_lisp_poly_type(ao_lisp_v)) {
260         case AO_LISP_BUILTIN:
261                 ao_lisp_stack->state = eval_val;
262                 builtin = ao_lisp_poly_builtin(ao_lisp_v);
263                 v = ao_lisp_func(builtin) (
264                         ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr));
265                 DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) {
266                                 struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
267                                 ao_poly atom = ao_lisp_arg(cons, 1);
268                                 ao_poly val = ao_lisp_arg(cons, 2);
269                                 DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
270                         });
271                 builtin = ao_lisp_poly_builtin(ao_lisp_v);
272                 if (builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack))
273                         ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values));
274
275                 ao_lisp_v = v;
276                 ao_lisp_stack->values = AO_LISP_NIL;
277                 ao_lisp_stack->values_tail = AO_LISP_NIL;
278                 DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n");
279                 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
280                 break;
281         case AO_LISP_LAMBDA:
282                 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
283                 ao_lisp_stack->state = eval_progn;
284                 v = ao_lisp_lambda_eval();
285                 ao_lisp_stack->sexprs = v;
286                 ao_lisp_stack->values = AO_LISP_NIL;
287                 ao_lisp_stack->values_tail = AO_LISP_NIL;
288                 DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
289                 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
290                 break;
291         case AO_LISP_STACK:
292                 DBGI(".. stack "); DBG_POLY(ao_lisp_v); DBG("\n");
293                 ao_lisp_v = ao_lisp_stack_eval();
294                 DBGI(".. value "); DBG_POLY(ao_lisp_v); DBG("\n");
295                 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
296                 break;
297         }
298         return 1;
299 }
300
301 /*
302  * Start evaluating the next cond clause
303  *
304  * If the list of clauses is empty, then
305  * the result of the cond is nil.
306  *
307  * Otherwise, set the current stack state to 'cond_test' and create a
308  * new stack context to evaluate the test s-expression. Once that's
309  * complete, we'll land in 'cond_test' to finish the clause.
310  */
311 static int
312 ao_lisp_eval_cond(void)
313 {
314         DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
315         DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
316         DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
317         if (!ao_lisp_stack->sexprs) {
318                 ao_lisp_v = AO_LISP_NIL;
319                 ao_lisp_stack->state = eval_val;
320         } else {
321                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
322                 if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) {
323                         ao_lisp_error(AO_LISP_INVALID, "invalid cond clause");
324                         return 0;
325                 }
326                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
327                 if (ao_lisp_v == _ao_lisp_atom_else)
328                         ao_lisp_v = _ao_lisp_bool_true;
329                 ao_lisp_stack->state = eval_cond_test;
330                 if (!ao_lisp_stack_push())
331                         return 0;
332         }
333         return 1;
334 }
335
336 /*
337  * Finish a cond clause.
338  *
339  * Check the value from the test expression, if
340  * non-nil, then set up to evaluate the value expression.
341  *
342  * Otherwise, step to the next clause and go back to the 'cond'
343  * state
344  */
345 static int
346 ao_lisp_eval_cond_test(void)
347 {
348         DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
349         DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
350         DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
351         if (ao_lisp_v != _ao_lisp_bool_false) {
352                 struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
353                 ao_poly c = car->cdr;
354
355                 if (c) {
356                         ao_lisp_stack->state = eval_progn;
357                         ao_lisp_stack->sexprs = c;
358                 } else
359                         ao_lisp_stack->state = eval_val;
360         } else {
361                 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
362                 DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
363                 ao_lisp_stack->state = eval_cond;
364         }
365         return 1;
366 }
367
368 /*
369  * Evaluate a list of sexprs, returning the value from the last one.
370  *
371  * ao_lisp_progn records the list in stack->sexprs, so we just need to
372  * walk that list. Set ao_lisp_v to the car of the list and jump to
373  * eval_sexpr. When that's done, it will land in eval_val. For all but
374  * the last, leave a stack frame with eval_progn set so that we come
375  * back here. For the last, don't add a stack frame so that we can
376  * just continue on.
377  */
378 static int
379 ao_lisp_eval_progn(void)
380 {
381         DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
382         DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
383         DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
384
385         if (!ao_lisp_stack->sexprs) {
386                 ao_lisp_v = AO_LISP_NIL;
387                 ao_lisp_stack->state = eval_val;
388         } else {
389                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
390                 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
391
392                 /* If there are more sexprs to do, then come back here, otherwise
393                  * return the value of the last one by just landing in eval_sexpr
394                  */
395                 if (ao_lisp_stack->sexprs) {
396                         ao_lisp_stack->state = eval_progn;
397                         if (!ao_lisp_stack_push())
398                                 return 0;
399                 }
400                 ao_lisp_stack->state = eval_sexpr;
401         }
402         return 1;
403 }
404
405 /*
406  * Conditionally execute a list of sexprs while the first is true
407  */
408 static int
409 ao_lisp_eval_while(void)
410 {
411         DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
412         DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
413         DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
414
415         ao_lisp_stack->values = ao_lisp_v;
416         if (!ao_lisp_stack->sexprs) {
417                 ao_lisp_v = AO_LISP_NIL;
418                 ao_lisp_stack->state = eval_val;
419         } else {
420                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
421                 ao_lisp_stack->state = eval_while_test;
422                 if (!ao_lisp_stack_push())
423                         return 0;
424         }
425         return 1;
426 }
427
428 /*
429  * Check the while condition, terminate the loop if nil. Otherwise keep going
430  */
431 static int
432 ao_lisp_eval_while_test(void)
433 {
434         DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
435         DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
436         DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
437
438         if (ao_lisp_v != _ao_lisp_bool_false) {
439                 ao_lisp_stack->values = ao_lisp_v;
440                 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
441                 ao_lisp_stack->state = eval_while;
442                 if (!ao_lisp_stack_push())
443                         return 0;
444                 ao_lisp_stack->state = eval_progn;
445                 ao_lisp_stack->sexprs = ao_lisp_v;
446         }
447         else
448         {
449                 ao_lisp_stack->state = eval_val;
450                 ao_lisp_v = ao_lisp_stack->values;
451         }
452         return 1;
453 }
454
455 /*
456  * Replace the original sexpr with the macro expansion, then
457  * execute that
458  */
459 static int
460 ao_lisp_eval_macro(void)
461 {
462         DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
463
464         if (ao_lisp_v == AO_LISP_NIL)
465                 ao_lisp_abort();
466         if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) {
467                 *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v);
468                 ao_lisp_v = ao_lisp_stack->sexprs;
469                 DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n");
470         }
471         ao_lisp_stack->sexprs = AO_LISP_NIL;
472         ao_lisp_stack->state = eval_sexpr;
473         return 1;
474 }
475
476 static int (*const evals[])(void) = {
477         [eval_sexpr] = ao_lisp_eval_sexpr,
478         [eval_val] = ao_lisp_eval_val,
479         [eval_formal] = ao_lisp_eval_formal,
480         [eval_exec] = ao_lisp_eval_exec,
481         [eval_cond] = ao_lisp_eval_cond,
482         [eval_cond_test] = ao_lisp_eval_cond_test,
483         [eval_progn] = ao_lisp_eval_progn,
484         [eval_while] = ao_lisp_eval_while,
485         [eval_while_test] = ao_lisp_eval_while_test,
486         [eval_macro] = ao_lisp_eval_macro,
487 };
488
489 const char *ao_lisp_state_names[] = {
490         "sexpr",
491         "val",
492         "formal",
493         "exec",
494         "cond",
495         "cond_test",
496         "progn",
497         "while",
498         "while_test",
499         "macro",
500 };
501
502 /*
503  * Called at restore time to reset all execution state
504  */
505
506 void
507 ao_lisp_eval_clear_globals(void)
508 {
509         ao_lisp_stack = NULL;
510         ao_lisp_frame_current = NULL;
511         ao_lisp_v = AO_LISP_NIL;
512 }
513
514 int
515 ao_lisp_eval_restart(void)
516 {
517         return ao_lisp_stack_push();
518 }
519
520 ao_poly
521 ao_lisp_eval(ao_poly _v)
522 {
523         ao_lisp_v = _v;
524
525         if (!ao_lisp_stack_push())
526                 return AO_LISP_NIL;
527
528         while (ao_lisp_stack) {
529                 if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
530                         ao_lisp_stack_clear();
531                         return AO_LISP_NIL;
532                 }
533         }
534         DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");});
535         ao_lisp_frame_current = NULL;
536         return ao_lisp_v;
537 }