2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
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.
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.
18 #define DBG(...) printf(__VA_ARGS__)
19 #define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a))
20 #define DBG_POLY(a) ao_lisp_poly_print(a)
21 #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1)
28 struct ao_lisp_stack {
36 static struct ao_lisp_stack *
37 ao_lisp_poly_stack(ao_poly p)
39 return ao_lisp_ref(p);
43 ao_lisp_stack_poly(struct ao_lisp_stack *stack)
45 return ao_lisp_poly(stack, AO_LISP_OTHER);
49 stack_size(void *addr)
52 return sizeof (struct ao_lisp_stack);
56 stack_mark(void *addr)
58 struct ao_lisp_stack *stack = addr;
60 ao_lisp_poly_mark(stack->actuals);
61 ao_lisp_poly_mark(stack->formals);
62 ao_lisp_poly_mark(stack->frame);
63 ao_lisp_poly_mark(stack->cond);
64 stack = ao_lisp_poly_stack(stack->next);
65 if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack)))
71 stack_move(void *addr)
73 struct ao_lisp_stack *stack = addr;
76 struct ao_lisp_stack *next;
77 stack->actuals = ao_lisp_poly_move(stack->actuals);
78 stack->formals = ao_lisp_poly_move(stack->formals);
79 stack->frame = ao_lisp_poly_move(stack->frame);
80 stack->cond = ao_lisp_poly_move(stack->cond);
81 next = ao_lisp_ref(stack->next);
82 next = ao_lisp_move_memory(next, sizeof (struct ao_lisp_stack));
83 stack->next = ao_lisp_stack_poly(next);
88 static const struct ao_lisp_type ao_lisp_stack_type = {
95 static struct ao_lisp_stack *stack;
96 static struct ao_lisp_cons *actuals;
97 static struct ao_lisp_cons *formals;
98 static struct ao_lisp_cons *formals_tail;
99 static struct ao_lisp_cons *cond;
100 struct ao_lisp_frame *next_frame;
101 static uint8_t been_here;
104 ao_lisp_set_cond(struct ao_lisp_cons *c)
111 ao_lisp_stack_push(void)
113 struct ao_lisp_stack *n = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
116 n->next = ao_lisp_stack_poly(stack);
117 n->actuals = ao_lisp_cons_poly(actuals);
118 n->formals = ao_lisp_cons_poly(formals);
119 n->cond = ao_lisp_cons_poly(cond);
120 n->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
121 DBG("push frame %d\n", OFFSET(ao_lisp_frame_current));
127 ao_lisp_stack_pop(void)
129 actuals = ao_lisp_poly_cons(stack->actuals);
130 formals = ao_lisp_poly_cons(stack->formals);
131 cond = ao_lisp_poly_cons(stack->cond);
132 ao_lisp_frame_current = ao_lisp_poly_frame(stack->frame);
133 DBG("pop frame %d\n", OFFSET(ao_lisp_frame_current));
136 /* Recompute the tail of the formals list */
138 struct ao_lisp_cons *formal;
139 for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr));
140 formals_tail = formal;
142 stack = ao_lisp_poly_stack(stack->next);
146 ao_lisp_stack_clear(void)
149 actuals = formals = formals_tail = 0;
151 ao_lisp_frame_current = 0;
156 func_type(ao_poly func)
158 struct ao_lisp_cons *cons;
159 struct ao_lisp_cons *args;
162 DBG("func type "); DBG_POLY(func); DBG("\n");
163 if (func == AO_LISP_NIL)
164 return ao_lisp_error(AO_LISP_INVALID, "func is nil");
165 if (ao_lisp_poly_type(func) != AO_LISP_CONS)
166 return ao_lisp_error(AO_LISP_INVALID, "func is not list");
167 cons = ao_lisp_poly_cons(func);
168 if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3))
170 if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0))
172 if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1))
174 args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1));
177 if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) {
178 return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f);
180 args = ao_lisp_poly_cons(args->cdr);
183 return ao_lisp_arg(cons, 0);
187 ao_lisp_cons_length(struct ao_lisp_cons *cons)
192 cons = ao_lisp_poly_cons(cons->cdr);
198 ao_lisp_lambda(struct ao_lisp_cons *cons)
201 struct ao_lisp_cons *lambda;
202 struct ao_lisp_cons *args;
206 lambda = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
207 DBG("lambda "); DBG_CONS(lambda); DBG("\n");
208 type = ao_lisp_arg(lambda, 0);
209 args = ao_lisp_poly_cons(ao_lisp_arg(lambda, 1));
211 args_wanted = ao_lisp_cons_length(args);
213 /* Create a frame to hold the variables
215 if (type == _ao_lisp_atom_lambda)
216 args_provided = ao_lisp_cons_length(cons) - 1;
219 if (args_wanted != args_provided)
220 return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided);
221 next_frame = ao_lisp_frame_new(args_wanted, 0);
222 DBG("new frame %d\n", OFFSET(next_frame));
224 case _ao_lisp_atom_lambda: {
226 struct ao_lisp_cons *vals = ao_lisp_poly_cons(cons->cdr);
228 for (f = 0; f < args_wanted; f++) {
229 next_frame->vals[f].atom = args->car;
230 next_frame->vals[f].val = vals->car;
231 args = ao_lisp_poly_cons(args->cdr);
232 vals = ao_lisp_poly_cons(vals->cdr);
236 case _ao_lisp_atom_lexpr:
237 case _ao_lisp_atom_nlambda:
238 next_frame->vals[0].atom = args->car;
239 next_frame->vals[0].val = cons->cdr;
241 case _ao_lisp_atom_macro:
242 next_frame->vals[0].atom = args->car;
243 next_frame->vals[0].val = ao_lisp_cons_poly(cons);
246 return ao_lisp_arg(lambda, 2);
250 ao_lisp_eval(ao_poly v)
252 struct ao_lisp_cons *formal;
257 ao_lisp_root_add(&ao_lisp_stack_type, &stack);
258 ao_lisp_root_add(&ao_lisp_cons_type, &actuals);
259 ao_lisp_root_add(&ao_lisp_cons_type, &formals);
260 ao_lisp_root_add(&ao_lisp_cons_type, &formals_tail);
271 if (cond->car == AO_LISP_NIL) {
275 if (ao_lisp_poly_type(cond->car) != AO_LISP_CONS) {
276 ao_lisp_error(AO_LISP_INVALID, "malformed cond");
279 v = ao_lisp_poly_cons(cond->car)->car;
283 /* Build stack frames for each list */
284 while (ao_lisp_poly_type(v) == AO_LISP_CONS) {
285 if (v == AO_LISP_NIL)
288 /* Push existing bits on the stack */
290 if (!ao_lisp_stack_push())
293 actuals = ao_lisp_poly_cons(v);
300 // DBG("start: stack"); DBG_CONS(stack); DBG("\n");
301 // DBG("start: actuals"); DBG_CONS(actuals); DBG("\n");
302 // DBG("start: formals"); DBG_CONS(formals); DBG("\n");
305 /* Evaluate primitive types */
307 DBG ("actual: "); DBG_POLY(v); DBG("\n");
309 switch (ao_lisp_poly_type(v)) {
314 v = ao_lisp_atom_get(v);
319 DBG("add formal: "); DBG_POLY(v); DBG("\n");
321 /* We've processed the first element of the list, go check
322 * what kind of function we've got
324 if (formals == NULL) {
325 if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
326 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
328 case AO_LISP_NLAMBDA:
333 v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr));
334 DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals));
335 DBG(" -> "); DBG_POLY(v);
337 if (ao_lisp_poly_type(v) != AO_LISP_CONS) {
338 ao_lisp_error(AO_LISP_INVALID, "macro didn't return list");
341 /* Reset frame to the new list */
342 actuals = ao_lisp_poly_cons(v);
347 switch (func_type(v)) {
348 case _ao_lisp_atom_lambda:
349 case _ao_lisp_atom_lexpr:
351 case _ao_lisp_atom_nlambda:
354 case _ao_lisp_atom_macro:
357 ao_lisp_error(AO_LISP_INVALID, "operator is not a function");
363 formal = ao_lisp_cons_cons(v, NULL);
365 formals_tail->cdr = ao_lisp_cons_poly(formal);
368 formals_tail = formal;
369 actuals = ao_lisp_poly_cons(actuals->cdr);
378 /* Process all of the arguments */
388 /* Evaluate the resulting list */
389 if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) {
390 struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v);
392 v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr));
399 if (ao_lisp_exception)
405 v = ao_lisp_lambda(formals);
406 if (ao_lisp_exception)
413 // DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n");
414 // DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n");
415 // DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n");
420 ao_lisp_frame_current = 0;
423 ao_lisp_frame_current = next_frame;
424 DBG("next frame %d\n", OFFSET(next_frame));
430 v = ao_lisp_poly_cons(cond->car)->cdr;
431 if (v != AO_LISP_NIL) {
432 v = ao_lisp_poly_cons(v)->car;
436 cond = ao_lisp_poly_cons(cond->cdr);
444 DBG("leaving frame at %d\n", OFFSET(ao_lisp_frame_current));
447 ao_lisp_stack_clear();