+ ao_lisp_stack->values = ao_lisp_v;
+ 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;
+ }
+ 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_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_begin;
+ ao_lisp_stack->sexprs = ao_lisp_v;
+ }
+ else
+ {
+ ao_lisp_stack->state = eval_val;
+ ao_lisp_v = ao_lisp_stack->values;
+ }
+ return 1;
+}
+
+/*
+ * Replace the original sexpr with the macro expansion, then
+ * execute that
+ */
+static int
+ao_lisp_eval_macro(void)
+{
+ DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
+
+ if (ao_lisp_v == AO_LISP_NIL)
+ ao_lisp_abort();
+ if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) {
+ *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v);
+ ao_lisp_v = ao_lisp_stack->sexprs;
+ DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n");
+ }
+ ao_lisp_stack->sexprs = AO_LISP_NIL;
+ ao_lisp_stack->state = eval_sexpr;
+ return 1;
+}
+
+static int (*const evals[])(void) = {
+ [eval_sexpr] = ao_lisp_eval_sexpr,
+ [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_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[] = {
+ [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",
+};
+
+/*
+ * Called at restore time to reset all execution state
+ */
+
+void
+ao_lisp_eval_clear_globals(void)
+{
+ ao_lisp_stack = NULL;
+ ao_lisp_frame_current = NULL;
+ ao_lisp_v = AO_LISP_NIL;
+}
+
+int
+ao_lisp_eval_restart(void)
+{
+ return ao_lisp_stack_push();
+}
+
+ao_poly
+ao_lisp_eval(ao_poly _v)
+{
+ ao_lisp_v = _v;
+
+ ao_lisp_frame_init();
+
+ if (!ao_lisp_stack_push())
+ return AO_LISP_NIL;
+
+ while (ao_lisp_stack) {
+ if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
+ ao_lisp_stack_clear();
+ return AO_LISP_NIL;