altos/lisp: Add 'else' sematics to cond
[fw/altos] / src / lisp / ao_lisp_eval.c
index 5fa9e0ad47a25ebbde49557b315ae41fd4e6ff1b..57227e9338d3c9a095da4ad430e9bc1ae10a61cc 100644 (file)
  * General Public License for more details.
  */
 
-#define DBG_EVAL 0
 #include "ao_lisp.h"
 #include <assert.h>
 
-const struct ao_lisp_type ao_lisp_stack_type;
-
-static int
-stack_size(void *addr)
-{
-       (void) addr;
-       return sizeof (struct ao_lisp_stack);
-}
-
-static void
-stack_mark(void *addr)
-{
-       struct ao_lisp_stack    *stack = addr;
-       for (;;) {
-               ao_lisp_poly_mark(stack->sexprs, 0);
-               ao_lisp_poly_mark(stack->values, 0);
-               /* no need to mark values_tail */
-               ao_lisp_poly_mark(stack->frame, 0);
-               ao_lisp_poly_mark(stack->list, 0);
-               stack = ao_lisp_poly_stack(stack->prev);
-               if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack))
-                       break;
-       }
-}
-
-static void
-stack_move(void *addr)
-{
-       struct ao_lisp_stack    *stack = addr;
-
-       while (stack) {
-               struct ao_lisp_stack    *prev;
-               int                     ret;
-               (void) ao_lisp_poly_move(&stack->sexprs, 0);
-               (void) ao_lisp_poly_move(&stack->values, 0);
-               (void) ao_lisp_poly_move(&stack->values_tail, 0);
-               (void) ao_lisp_poly_move(&stack->frame, 0);
-               (void) ao_lisp_poly_move(&stack->list, 0);
-               prev = ao_lisp_poly_stack(stack->prev);
-               if (!prev)
-                       break;
-               ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev);
-               if (prev != ao_lisp_poly_stack(stack->prev))
-                       stack->prev = ao_lisp_stack_poly(prev);
-               if (ret)
-                       break;
-               stack = prev;
-       }
-}
-
-const struct ao_lisp_type ao_lisp_stack_type = {
-       .size = stack_size,
-       .mark = stack_mark,
-       .move = stack_move,
-       .name = "stack"
-};
-
 struct ao_lisp_stack           *ao_lisp_stack;
 ao_poly                                ao_lisp_v;
 
-struct ao_lisp_stack           *ao_lisp_stack_free_list;
-
 ao_poly
 ao_lisp_set_cond(struct ao_lisp_cons *c)
 {
@@ -86,72 +26,6 @@ ao_lisp_set_cond(struct ao_lisp_cons *c)
        return AO_LISP_NIL;
 }
 
-static void
-ao_lisp_stack_reset(struct ao_lisp_stack *stack)
-{
-       stack->state = eval_sexpr;
-       stack->sexprs = AO_LISP_NIL;
-       stack->values = AO_LISP_NIL;
-       stack->values_tail = AO_LISP_NIL;
-}
-
-
-static int
-ao_lisp_stack_push(void)
-{
-       struct ao_lisp_stack    *stack;
-       if (ao_lisp_stack_free_list) {
-               stack = ao_lisp_stack_free_list;
-               ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev);
-       } else {
-               stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
-               if (!stack)
-                       return 0;
-       }
-       stack->prev = ao_lisp_stack_poly(ao_lisp_stack);
-       stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
-       stack->list = AO_LISP_NIL;
-       ao_lisp_stack = stack;
-       ao_lisp_stack_reset(stack);
-       DBGI("stack push\n");
-       DBG_FRAMES();
-       DBG_IN();
-       return 1;
-}
-
-static void
-ao_lisp_stack_pop(void)
-{
-       ao_poly                 prev;
-       struct ao_lisp_frame    *prev_frame;
-
-       if (!ao_lisp_stack)
-               return;
-       prev = ao_lisp_stack->prev;
-       ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list);
-       ao_lisp_stack_free_list = ao_lisp_stack;
-
-       ao_lisp_stack = ao_lisp_poly_stack(prev);
-       prev_frame = ao_lisp_frame_current;
-       if (ao_lisp_stack)
-               ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
-       else
-               ao_lisp_frame_current = NULL;
-       if (ao_lisp_frame_current != prev_frame)
-               ao_lisp_frame_free(prev_frame);
-       DBG_OUT();
-       DBGI("stack pop\n");
-       DBG_FRAMES();
-}
-
-static void
-ao_lisp_stack_clear(void)
-{
-       ao_lisp_stack = NULL;
-       ao_lisp_frame_current = NULL;
-       ao_lisp_v = AO_LISP_NIL;
-}
-
 static int
 func_type(ao_poly func)
 {
@@ -162,6 +36,8 @@ func_type(ao_poly func)
                return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK;
        case AO_LISP_LAMBDA:
                return ao_lisp_poly_lambda(func)->args;
+       case AO_LISP_STACK:
+               return AO_LISP_FUNC_LAMBDA;
        default:
                ao_lisp_error(AO_LISP_INVALID, "not a func");
                return -1;
@@ -231,6 +107,7 @@ ao_lisp_eval_sexpr(void)
                DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
                ao_lisp_v = ao_lisp_atom_get(ao_lisp_v);
                /* fall through */
+       case AO_LISP_BOOL:
        case AO_LISP_INT:
        case AO_LISP_STRING:
        case AO_LISP_BUILTIN:
@@ -334,7 +211,7 @@ ao_lisp_eval_formal(void)
        }
 
        /* Append formal to list of values */
-       formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL));
+       formal = ao_lisp__cons(ao_lisp_v, AO_LISP_NIL);
        if (!formal)
                return 0;
 
@@ -392,10 +269,12 @@ ao_lisp_eval_exec(void)
                                DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
                        });
                builtin = ao_lisp_poly_builtin(ao_lisp_v);
-               if (builtin->args & AO_LISP_FUNC_FREE_ARGS)
+               if (builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack))
                        ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values));
 
                ao_lisp_v = v;
+               ao_lisp_stack->values = AO_LISP_NIL;
+               ao_lisp_stack->values_tail = AO_LISP_NIL;
                DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n");
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
                break;
@@ -404,12 +283,18 @@ ao_lisp_eval_exec(void)
                ao_lisp_stack->state = eval_progn;
                v = ao_lisp_lambda_eval();
                ao_lisp_stack->sexprs = v;
+               ao_lisp_stack->values = AO_LISP_NIL;
+               ao_lisp_stack->values_tail = AO_LISP_NIL;
                DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
                break;
+       case AO_LISP_STACK:
+               DBGI(".. stack "); DBG_POLY(ao_lisp_v); DBG("\n");
+               ao_lisp_v = ao_lisp_stack_eval();
+               DBGI(".. value "); DBG_POLY(ao_lisp_v); DBG("\n");
+               DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
+               break;
        }
-       ao_lisp_stack->values = AO_LISP_NIL;
-       ao_lisp_stack->values_tail = AO_LISP_NIL;
        return 1;
 }
 
@@ -439,6 +324,8 @@ ao_lisp_eval_cond(void)
                        return 0;
                }
                ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
+               if (ao_lisp_v == _ao_lisp_atom_else)
+                       ao_lisp_v = _ao_lisp_bool_true;
                ao_lisp_stack->state = eval_cond_test;
                if (!ao_lisp_stack_push())
                        return 0;
@@ -461,7 +348,7 @@ ao_lisp_eval_cond_test(void)
        DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
        DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
        DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-       if (ao_lisp_v) {
+       if (ao_lisp_v != _ao_lisp_bool_false) {
                struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
                ao_poly c = car->cdr;
 
@@ -525,6 +412,7 @@ ao_lisp_eval_while(void)
        DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
        DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
 
+       ao_lisp_stack->values = ao_lisp_v;
        if (!ao_lisp_stack->sexprs) {
                ao_lisp_v = AO_LISP_NIL;
                ao_lisp_stack->state = eval_val;
@@ -547,7 +435,8 @@ ao_lisp_eval_while_test(void)
        DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
        DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
 
-       if (ao_lisp_v) {
+       if (ao_lisp_v != _ao_lisp_bool_false) {
+               ao_lisp_stack->values = ao_lisp_v;
                ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
                ao_lisp_stack->state = eval_while;
                if (!ao_lisp_stack_push())
@@ -556,7 +445,10 @@ ao_lisp_eval_while_test(void)
                ao_lisp_stack->sexprs = ao_lisp_v;
        }
        else
+       {
                ao_lisp_stack->state = eval_val;
+               ao_lisp_v = ao_lisp_stack->values;
+       }
        return 1;
 }
 
@@ -594,6 +486,19 @@ static int (*const evals[])(void) = {
        [eval_macro] = ao_lisp_eval_macro,
 };
 
+const char *ao_lisp_state_names[] = {
+       "sexpr",
+       "val",
+       "formal",
+       "exec",
+       "cond",
+       "cond_test",
+       "progn",
+       "while",
+       "while_test",
+       "macro",
+};
+
 /*
  * Called at restore time to reset all execution state
  */