altos/lisp: Split out read debug, add memory validation
[fw/altos] / src / lisp / ao_lisp_eval.c
index 3be7c9c4fa68c2fb29b60ec6f8b10ec6216ae705..ced182f6aeddfeb9a2b617f0f4b05293c4fc2d04 100644 (file)
@@ -17,6 +17,7 @@
 
 struct ao_lisp_stack           *ao_lisp_stack;
 ao_poly                                ao_lisp_v;
+uint8_t                                ao_lisp_skip_cons_free;
 
 ao_poly
 ao_lisp_set_cond(struct ao_lisp_cons *c)
@@ -67,7 +68,7 @@ func_type(ao_poly func)
 static int
 ao_lisp_eval_sexpr(void)
 {
-       DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n");
+       DBGI("sexpr: %v\n", ao_lisp_v);
        switch (ao_lisp_poly_type(ao_lisp_v)) {
        case AO_LISP_CONS:
                if (ao_lisp_v == AO_LISP_NIL) {
@@ -107,7 +108,10 @@ 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_BIGINT:
+       case AO_LISP_FLOAT:
        case AO_LISP_STRING:
        case AO_LISP_BUILTIN:
        case AO_LISP_LAMBDA:
@@ -189,8 +193,8 @@ ao_lisp_eval_formal(void)
                        ao_lisp_stack->sexprs = prev->sexprs;
 
                        DBGI(".. start macro\n");
-                       DBGI(".. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
-                       DBGI(".. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
+                       DBGI("\t.. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
+                       DBGI("\t.. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
                        DBG_FRAMES();
 
                        /* fall through ... */
@@ -210,7 +214,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;
 
@@ -268,7 +272,7 @@ 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 && !ao_lisp_stack_marked(ao_lisp_stack))
+               if (builtin && builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack) && !ao_lisp_skip_cons_free)
                        ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values));
 
                ao_lisp_v = v;
@@ -279,7 +283,7 @@ ao_lisp_eval_exec(void)
                break;
        case AO_LISP_LAMBDA:
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
-               ao_lisp_stack->state = eval_progn;
+               ao_lisp_stack->state = eval_begin;
                v = ao_lisp_lambda_eval();
                ao_lisp_stack->sexprs = v;
                ao_lisp_stack->values = AO_LISP_NIL;
@@ -294,6 +298,38 @@ ao_lisp_eval_exec(void)
                DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
                break;
        }
+       ao_lisp_skip_cons_free = 0;
+       return 1;
+}
+
+/*
+ * Finish setting up the apply evaluation
+ *
+ * The value is the list to execute
+ */
+static int
+ao_lisp_eval_apply(void)
+{
+       struct ao_lisp_cons     *cons = ao_lisp_poly_cons(ao_lisp_v);
+       struct ao_lisp_cons     *cdr, *prev;
+
+       /* Glue the arguments into the right shape. That's all but the last
+        * concatenated onto the last
+        */
+       cdr = cons;
+       for (;;) {
+               prev = cdr;
+               cdr = ao_lisp_poly_cons(prev->cdr);
+               if (cdr->cdr == AO_LISP_NIL)
+                       break;
+       }
+       DBGI("before mangling: "); DBG_POLY(ao_lisp_v); DBG("\n");
+       prev->cdr = cdr->car;
+       ao_lisp_stack->values = ao_lisp_v;
+       ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car;
+       DBGI("apply: "); DBG_POLY(ao_lisp_stack->values); DBG ("\n");
+       ao_lisp_stack->state = eval_exec;
+       ao_lisp_skip_cons_free = 1;
        return 1;
 }
 
@@ -314,7 +350,7 @@ ao_lisp_eval_cond(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_stack->sexprs) {
-               ao_lisp_v = AO_LISP_NIL;
+               ao_lisp_v = _ao_lisp_bool_false;
                ao_lisp_stack->state = eval_val;
        } else {
                ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
@@ -323,6 +359,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;
@@ -345,12 +383,12 @@ 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;
 
                if (c) {
-                       ao_lisp_stack->state = eval_progn;
+                       ao_lisp_stack->state = eval_begin;
                        ao_lisp_stack->sexprs = c;
                } else
                        ao_lisp_stack->state = eval_val;
@@ -365,17 +403,17 @@ ao_lisp_eval_cond_test(void)
 /*
  * 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
+ * ao_lisp_begin 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
+ * the last, leave a stack frame with eval_begin 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)
+ao_lisp_eval_begin(void)
 {
-       DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
+       DBGI("begin: "); 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");
 
@@ -390,7 +428,7 @@ ao_lisp_eval_progn(void)
                 * return the value of the last one by just landing in eval_sexpr
                 */
                if (ao_lisp_stack->sexprs) {
-                       ao_lisp_stack->state = eval_progn;
+                       ao_lisp_stack->state = eval_begin;
                        if (!ao_lisp_stack_push())
                                return 0;
                }
@@ -432,13 +470,13 @@ 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())
                        return 0;
-               ao_lisp_stack->state = eval_progn;
+               ao_lisp_stack->state = eval_begin;
                ao_lisp_stack->sexprs = ao_lisp_v;
        }
        else
@@ -475,22 +513,27 @@ static int (*const evals[])(void) = {
        [eval_val] = ao_lisp_eval_val,
        [eval_formal] = ao_lisp_eval_formal,
        [eval_exec] = ao_lisp_eval_exec,
+       [eval_apply] = ao_lisp_eval_apply,
        [eval_cond] = ao_lisp_eval_cond,
        [eval_cond_test] = ao_lisp_eval_cond_test,
-       [eval_progn] = ao_lisp_eval_progn,
+       [eval_begin] = ao_lisp_eval_begin,
        [eval_while] = ao_lisp_eval_while,
        [eval_while_test] = ao_lisp_eval_while_test,
        [eval_macro] = ao_lisp_eval_macro,
 };
 
 const char *ao_lisp_state_names[] = {
-       "sexpr",
-       "val",
-       "formal",
-       "exec",
-       "cond",
-       "cond_test",
-       "progn",
+       [eval_sexpr] = "sexpr",
+       [eval_val] = "val",
+       [eval_formal] = "formal",
+       [eval_exec] = "exec",
+       [eval_apply] = "apply",
+       [eval_cond] = "cond",
+       [eval_cond_test] = "cond_test",
+       [eval_begin] = "begin",
+       [eval_while] = "while",
+       [eval_while_test] = "while_test",
+       [eval_macro] = "macro",
 };
 
 /*
@@ -516,6 +559,8 @@ ao_lisp_eval(ao_poly _v)
 {
        ao_lisp_v = _v;
 
+       ao_lisp_frame_init();
+
        if (!ao_lisp_stack_push())
                return AO_LISP_NIL;