altos/lisp: Make ao_lisp_ref and ao_lisp_poly non-inline
[fw/altos] / src / lisp / ao_lisp_eval.c
index f41962195ee7bd4227d1ce91e5cbc87138d807ae..ae2436b8cd86d7026bde5b1bc7347abaced9ba00 100644 (file)
@@ -12,7 +12,7 @@
  * General Public License for more details.
  */
 
-#define DBG_EVAL 1
+#define DBG_EVAL 0
 #include "ao_lisp.h"
 #include <assert.h>
 
@@ -32,7 +32,6 @@ stack_mark(void *addr)
                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->macro_frame, 0);
                stack = ao_lisp_poly_stack(stack->prev);
                if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack)))
                        break;
@@ -47,20 +46,20 @@ stack_move(void *addr)
        struct ao_lisp_stack    *stack = addr;
 
        while (stack) {
-               void    *prev;
+               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->macro_frame, 0);
                prev = ao_lisp_poly_stack(stack->prev);
-               ret = ao_lisp_move(&ao_lisp_stack_type, &prev);
+               ret = ao_lisp_move_memory((void **) &prev,
+                                         sizeof (struct ao_lisp_stack));
                if (prev != ao_lisp_poly_stack(stack->prev))
                        stack->prev = ao_lisp_stack_poly(prev);
                if (ret)
                        break;
-               stack = ao_lisp_poly_stack(stack->prev);
+               stack = prev;
        }
 }
 
@@ -85,28 +84,15 @@ static void
 ao_lisp_stack_reset(struct ao_lisp_stack *stack)
 {
        stack->state = eval_sexpr;
-       stack->macro = 0;
        stack->sexprs = AO_LISP_NIL;
        stack->values = AO_LISP_NIL;
        stack->values_tail = AO_LISP_NIL;
 }
 
-static void
-ao_lisp_frames_dump(void)
-{
-       struct ao_lisp_stack *s;
-       DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-       for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) {
-               DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n");
-               DBGI(".. macro frame: "); DBG_POLY(s->frame); DBG("\n");
-       }
-}
 
 static int
 ao_lisp_stack_push(void)
 {
-       DBGI("stack push\n");
-       DBG_IN();
        struct ao_lisp_stack    *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
        if (!stack)
                return 0;
@@ -115,7 +101,9 @@ ao_lisp_stack_push(void)
        stack->list = AO_LISP_NIL;
        ao_lisp_stack = stack;
        ao_lisp_stack_reset(stack);
-       ao_lisp_frames_dump();
+       DBGI("stack push\n");
+       DBG_FRAMES();
+       DBG_IN();
        return 1;
 }
 
@@ -124,11 +112,14 @@ ao_lisp_stack_pop(void)
 {
        if (!ao_lisp_stack)
                return;
-       ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
        ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev);
+       if (ao_lisp_stack)
+               ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
+       else
+               ao_lisp_frame_current = NULL;
        DBG_OUT();
        DBGI("stack pop\n");
-       ao_lisp_frames_dump();
+       DBG_FRAMES();
 }
 
 static void
@@ -246,33 +237,11 @@ static int
 ao_lisp_eval_val(void)
 {
        DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n");
-       if (ao_lisp_stack->macro) {
-               DBGI("..macro %d\n", ao_lisp_stack->macro);
-               DBGI("..current frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               DBGI("..saved frame   "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
-               DBGI("..macro frame   "); DBG_POLY(ao_lisp_stack->macro_frame); DBG("\n");
-               DBGI("..sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-               DBGI("..values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
-               /*
-                * Re-use the current stack to evaluate
-                * the value from the macro
-                */
-               ao_lisp_stack->state = eval_sexpr;
-//             assert(ao_lisp_stack->frame == ao_lisp_stack->macro_frame);
-               ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->macro_frame);
-               ao_lisp_stack->frame = ao_lisp_stack->macro_frame;
-               ao_lisp_stack->macro = 0;
-               ao_lisp_stack->macro_frame = AO_LISP_NIL;
-               ao_lisp_stack->sexprs = AO_LISP_NIL;
-               ao_lisp_stack->values = AO_LISP_NIL;
-               ao_lisp_stack->values_tail = AO_LISP_NIL;
-       } else {
-               /*
-                * Value computed, pop the stack
-                * to figure out what to do with the value
-                */
-               ao_lisp_stack_pop();
-       }
+       /*
+        * Value computed, pop the stack
+        * to figure out what to do with the value
+        */
+       ao_lisp_stack_pop();
        DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1);
        return 1;
 }
@@ -280,22 +249,25 @@ ao_lisp_eval_val(void)
 /*
  * A formal has been computed.
  *
- * If this is the first formal, then
- * check to see if we've got a lamda/lexpr or
- * macro/nlambda.
+ * If this is the first formal, then check to see if we've got a
+ * lamda/lexpr or macro/nlambda.
  *
- * For lambda/lexpr, go compute another formal.
- * This will terminate when the sexpr state
- * sees nil.
+ * For lambda/lexpr, go compute another formal.  This will terminate
+ * when the sexpr state sees nil.
  *
- * For macro/nlambda, we're done, so move the
- * sexprs into the values and go execute it.
+ * For macro/nlambda, we're done, so move the sexprs into the values
+ * and go execute it.
+ *
+ * Macros have an additional step of saving a stack frame holding the
+ * macro value execution context, which then gets the result of the
+ * macro to run
  */
 
 static int
 ao_lisp_eval_formal(void)
 {
-       ao_poly formal;
+       ao_poly                 formal;
+       struct ao_lisp_stack    *prev;
 
        DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n");
 
@@ -307,17 +279,34 @@ ao_lisp_eval_formal(void)
                        DBGI(".. lambda or lexpr\n");
                        break;
                case AO_LISP_FUNC_MACRO:
-                       ao_lisp_stack->macro = 1;
-                       DBGI(".. macro %d\n", ao_lisp_stack->macro);
-                       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->macro_frame = ao_lisp_stack->frame;
+                       /* Evaluate the result once more */
+                       ao_lisp_stack->state = eval_sexpr;
+                       if (!ao_lisp_stack_push())
+                               return 0;
+
+                       /* After the function returns, take that
+                        * value and re-evaluate it
+                        */
+                       prev = ao_lisp_poly_stack(ao_lisp_stack->prev);
+                       ao_lisp_stack->state = eval_sexpr;
+                       ao_lisp_stack->sexprs = prev->sexprs;
+                       prev->sexprs = AO_LISP_NIL;
+
+                       DBGI(".. start macro\n");
+                       DBGI(".. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
+                       DBGI(".. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
+                       DBG_FRAMES();
+
                        /* fall through ... */
                case AO_LISP_FUNC_NLAMBDA:
                        DBGI(".. nlambda or macro\n");
+
+                       /* use the raw sexprs as values */
                        ao_lisp_stack->values = ao_lisp_stack->sexprs;
                        ao_lisp_stack->values_tail = AO_LISP_NIL;
                        ao_lisp_stack->state = eval_exec;
+
+                       /* ready to execute now */
                        return 1;
                case -1:
                        return 0;
@@ -386,8 +375,7 @@ ao_lisp_eval_exec(void)
        case AO_LISP_LAMBDA:
                ao_lisp_stack->state = eval_sexpr;
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               ao_lisp_v = ao_lisp_lambda_eval(ao_lisp_poly_lambda(ao_lisp_v),
-                                               ao_lisp_poly_cons(ao_lisp_stack->values));
+               ao_lisp_v = ao_lisp_lambda_eval();
                DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n");
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
                break;
@@ -397,14 +385,6 @@ ao_lisp_eval_exec(void)
        return 1;
 }
 
-static int
-ao_lisp_eval_lambda_done(void)
-{
-       DBGI("lambda_done: "); DBG_POLY(ao_lisp_v); DBG("\n");
-       DBG_STACK();
-       return 1;
-}
-
 /*
  * Start evaluating the next cond clause
  *
@@ -458,12 +438,11 @@ ao_lisp_eval_cond_test(void)
                struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
                struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr);
 
-               ao_lisp_stack->state = eval_val;
                if (c) {
+                       ao_lisp_stack->state = eval_sexpr;
                        ao_lisp_v = c->car;
-                       if (!ao_lisp_stack_push())
-                               return 0;
-               }
+               } else
+                       ao_lisp_stack->state = eval_val;
        } else {
                ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
                DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
@@ -472,6 +451,85 @@ ao_lisp_eval_cond_test(void)
        return 1;
 }
 
+/*
+ * Evaluate a list of sexprs, returning the value from the last one.
+ *
+ * ao_lisp_progn records the list in stack->sexprs, so we just need to
+ * walk that list. Set ao_lisp_v to the car of the list and jump to
+ * eval_sexpr. When that's done, it will land in eval_val. For all but
+ * the last, leave a stack frame with eval_progn set so that we come
+ * back here. For the last, don't add a stack frame so that we can
+ * just continue on.
+ */
+static int
+ao_lisp_eval_progn(void)
+{
+       DBGI("progn: "); 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_stack->sexprs) {
+               ao_lisp_v = AO_LISP_NIL;
+               ao_lisp_stack->state = eval_val;
+       } else {
+               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
+               ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
+               if (ao_lisp_stack->sexprs) {
+                       ao_lisp_stack->state = eval_progn;
+                       if (!ao_lisp_stack_push())
+                               return 0;
+               }
+               ao_lisp_stack->state = eval_sexpr;
+       }
+       return 1;
+}
+
+/*
+ * Conditionally execute a list of sexprs while the first is true
+ */
+static int
+ao_lisp_eval_while(void)
+{
+       DBGI("while: "); 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_stack->sexprs) {
+               ao_lisp_v = AO_LISP_NIL;
+               ao_lisp_stack->state = eval_val;
+       } else {
+               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
+               ao_lisp_stack->state = eval_while_test;
+               if (!ao_lisp_stack_push())
+                       return 0;
+               ao_lisp_stack->state = eval_sexpr;
+       }
+       return 1;
+}
+
+/*
+ * Check the while condition, terminate the loop if nil. Otherwise keep going
+ */
+static int
+ao_lisp_eval_while_test(void)
+{
+       DBGI("while_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) {
+               ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
+               if (ao_lisp_v)
+                       ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
+               ao_lisp_stack->state = eval_while;
+               if (!ao_lisp_stack_push())
+                       return 0;
+       }
+       else
+               ao_lisp_stack->state = eval_val;
+       return 1;
+}
+
 static int (*const evals[])(void) = {
        [eval_sexpr] = ao_lisp_eval_sexpr,
        [eval_val] = ao_lisp_eval_val,
@@ -479,6 +537,9 @@ static int (*const evals[])(void) = {
        [eval_exec] = ao_lisp_eval_exec,
        [eval_cond] = ao_lisp_eval_cond,
        [eval_cond_test] = ao_lisp_eval_cond_test,
+       [eval_progn] = ao_lisp_eval_progn,
+       [eval_while] = ao_lisp_eval_while,
+       [eval_while_test] = ao_lisp_eval_while_test,
 };
 
 ao_poly
@@ -497,7 +558,6 @@ ao_lisp_eval(ao_poly _v)
                return AO_LISP_NIL;
 
        while (ao_lisp_stack) {
-//             DBG_STACK();
                if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
                        ao_lisp_stack_clear();
                        return AO_LISP_NIL;