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.
20 stack_size(void *addr)
23 return sizeof (struct ao_lisp_stack);
27 stack_mark(void *addr)
29 struct ao_lisp_stack *stack = addr;
31 ao_lisp_poly_mark(stack->sexprs, 0);
32 ao_lisp_poly_mark(stack->values, 0);
33 /* no need to mark values_tail */
34 ao_lisp_poly_mark(stack->frame, 0);
35 stack = ao_lisp_poly_stack(stack->prev);
36 if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack)))
41 static const struct ao_lisp_type ao_lisp_stack_type;
44 stack_move(void *addr)
46 struct ao_lisp_stack *stack = addr;
49 struct ao_lisp_stack *prev;
51 (void) ao_lisp_poly_move(&stack->sexprs, 0);
52 (void) ao_lisp_poly_move(&stack->values, 0);
53 (void) ao_lisp_poly_move(&stack->values_tail, 0);
54 (void) ao_lisp_poly_move(&stack->frame, 0);
55 prev = ao_lisp_poly_stack(stack->prev);
56 ret = ao_lisp_move_memory((void **) &prev,
57 sizeof (struct ao_lisp_stack));
58 if (prev != ao_lisp_poly_stack(stack->prev))
59 stack->prev = ao_lisp_stack_poly(prev);
66 static const struct ao_lisp_type ao_lisp_stack_type = {
72 struct ao_lisp_stack *ao_lisp_stack;
76 ao_lisp_set_cond(struct ao_lisp_cons *c)
78 ao_lisp_stack->state = eval_cond;
79 ao_lisp_stack->sexprs = ao_lisp_cons_poly(c);
84 ao_lisp_stack_reset(struct ao_lisp_stack *stack)
86 stack->state = eval_sexpr;
87 stack->sexprs = AO_LISP_NIL;
88 stack->values = AO_LISP_NIL;
89 stack->values_tail = AO_LISP_NIL;
94 ao_lisp_stack_push(void)
96 struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
99 stack->prev = ao_lisp_stack_poly(ao_lisp_stack);
100 stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
101 stack->list = AO_LISP_NIL;
102 ao_lisp_stack = stack;
103 ao_lisp_stack_reset(stack);
104 DBGI("stack push\n");
111 ao_lisp_stack_pop(void)
115 ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev);
117 ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
119 ao_lisp_frame_current = NULL;
126 ao_lisp_stack_clear(void)
128 ao_lisp_stack = NULL;
129 ao_lisp_frame_current = NULL;
130 ao_lisp_v = AO_LISP_NIL;
134 func_type(ao_poly func)
136 if (func == AO_LISP_NIL)
137 return ao_lisp_error(AO_LISP_INVALID, "func is nil");
138 switch (ao_lisp_poly_type(func)) {
139 case AO_LISP_BUILTIN:
140 return ao_lisp_poly_builtin(func)->args;
142 return ao_lisp_poly_lambda(func)->args;
144 ao_lisp_error(AO_LISP_INVALID, "not a func");
150 * Flattened eval to avoid stack issues
154 * Evaluate an s-expression
156 * For a list, evaluate all of the elements and
157 * then execute the resulting function call.
159 * Each element of the list is evaluated in
160 * a clean stack context.
162 * The current stack state is set to 'formal' so that
163 * when the evaluation is complete, the value
164 * will get appended to the values list.
166 * For other types, compute the value directly.
170 ao_lisp_eval_sexpr(void)
172 DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n");
173 switch (ao_lisp_poly_type(ao_lisp_v)) {
175 if (ao_lisp_v == AO_LISP_NIL) {
176 if (!ao_lisp_stack->values) {
178 * empty list evaluates to empty list
180 ao_lisp_v = AO_LISP_NIL;
181 ao_lisp_stack->state = eval_val;
184 * done with arguments, go execute it
186 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car;
187 ao_lisp_stack->state = eval_exec;
190 if (!ao_lisp_stack->values)
191 ao_lisp_stack->list = ao_lisp_v;
193 * Evaluate another argument and then switch
194 * to 'formal' to add the value to the values
197 ao_lisp_stack->sexprs = ao_lisp_v;
198 ao_lisp_stack->state = eval_formal;
199 if (!ao_lisp_stack_push())
202 * push will reset the state to 'sexpr', which
203 * will evaluate the expression
205 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
209 DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
210 ao_lisp_v = ao_lisp_atom_get(ao_lisp_v);
214 case AO_LISP_BUILTIN:
216 ao_lisp_stack->state = eval_val;
219 DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n");
224 * A value has been computed.
226 * If the value was computed from a macro,
227 * then we want to reset the current context
228 * to evaluate the macro result again.
230 * If not a macro, then pop the stack.
231 * If the stack is empty, we're done.
232 * Otherwise, the stack will contain
237 ao_lisp_eval_val(void)
239 DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n");
241 * Value computed, pop the stack
242 * to figure out what to do with the value
245 DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1);
250 * A formal has been computed.
252 * If this is the first formal, then check to see if we've got a
253 * lamda/lexpr or macro/nlambda.
255 * For lambda/lexpr, go compute another formal. This will terminate
256 * when the sexpr state sees nil.
258 * For macro/nlambda, we're done, so move the sexprs into the values
261 * Macros have an additional step of saving a stack frame holding the
262 * macro value execution context, which then gets the result of the
267 ao_lisp_eval_formal(void)
270 struct ao_lisp_stack *prev;
272 DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n");
274 /* Check what kind of function we've got */
275 if (!ao_lisp_stack->values) {
276 switch (func_type(ao_lisp_v)) {
277 case AO_LISP_FUNC_LAMBDA:
278 case AO_LISP_FUNC_LEXPR:
279 DBGI(".. lambda or lexpr\n");
281 case AO_LISP_FUNC_MACRO:
282 /* Evaluate the result once more */
283 ao_lisp_stack->state = eval_sexpr;
284 if (!ao_lisp_stack_push())
287 /* After the function returns, take that
288 * value and re-evaluate it
290 prev = ao_lisp_poly_stack(ao_lisp_stack->prev);
291 ao_lisp_stack->state = eval_sexpr;
292 ao_lisp_stack->sexprs = prev->sexprs;
293 prev->sexprs = AO_LISP_NIL;
295 DBGI(".. start macro\n");
296 DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
297 DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
300 /* fall through ... */
301 case AO_LISP_FUNC_NLAMBDA:
302 DBGI(".. nlambda or macro\n");
304 /* use the raw sexprs as values */
305 ao_lisp_stack->values = ao_lisp_stack->sexprs;
306 ao_lisp_stack->values_tail = AO_LISP_NIL;
307 ao_lisp_stack->state = eval_exec;
309 /* ready to execute now */
316 /* Append formal to list of values */
317 formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL));
321 if (ao_lisp_stack->values_tail)
322 ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal;
324 ao_lisp_stack->values = formal;
325 ao_lisp_stack->values_tail = formal;
327 DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
330 * Step to the next argument, if this is last, then
331 * 'sexpr' will end up switching to 'exec'
333 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
335 ao_lisp_stack->state = eval_sexpr;
337 DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n");
342 * Start executing a function call
344 * Most builtins are easy, just call the function.
345 * 'cond' is magic; it sticks the list of clauses
346 * in 'sexprs' and switches to 'cond' state. That
347 * bit of magic is done in ao_lisp_set_cond.
349 * Lambdas build a new frame to hold the locals and
350 * then re-use the current stack context to evaluate
351 * the s-expression from the lambda.
355 ao_lisp_eval_exec(void)
358 DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n");
359 ao_lisp_stack->sexprs = AO_LISP_NIL;
360 switch (ao_lisp_poly_type(ao_lisp_v)) {
361 case AO_LISP_BUILTIN:
362 ao_lisp_stack->state = eval_val;
363 v = ao_lisp_func(ao_lisp_poly_builtin(ao_lisp_v)) (
364 ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr));
365 DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) {
366 struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
367 ao_poly atom = ao_lisp_arg(cons, 1);
368 ao_poly val = ao_lisp_arg(cons, 2);
369 DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
372 DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n");
373 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
376 ao_lisp_stack->state = eval_sexpr;
377 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
378 ao_lisp_v = ao_lisp_lambda_eval();
379 DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n");
380 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
383 ao_lisp_stack->values = AO_LISP_NIL;
384 ao_lisp_stack->values_tail = AO_LISP_NIL;
389 * Start evaluating the next cond clause
391 * If the list of clauses is empty, then
392 * the result of the cond is nil.
394 * Otherwise, set the current stack state to 'cond_test' and create a
395 * new stack context to evaluate the test s-expression. Once that's
396 * complete, we'll land in 'cond_test' to finish the clause.
399 ao_lisp_eval_cond(void)
401 DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
402 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
403 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
404 if (!ao_lisp_stack->sexprs) {
405 ao_lisp_v = AO_LISP_NIL;
406 ao_lisp_stack->state = eval_val;
408 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
409 if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) {
410 ao_lisp_error(AO_LISP_INVALID, "invalid cond clause");
413 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
414 ao_lisp_stack->state = eval_cond_test;
415 if (!ao_lisp_stack_push())
417 ao_lisp_stack->state = eval_sexpr;
423 * Finish a cond clause.
425 * Check the value from the test expression, if
426 * non-nil, then set up to evaluate the value expression.
428 * Otherwise, step to the next clause and go back to the 'cond'
432 ao_lisp_eval_cond_test(void)
434 DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
435 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
436 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
438 struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
439 struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr);
442 ao_lisp_stack->state = eval_sexpr;
445 ao_lisp_stack->state = eval_val;
447 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
448 DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
449 ao_lisp_stack->state = eval_cond;
455 * Evaluate a list of sexprs, returning the value from the last one.
457 * ao_lisp_progn records the list in stack->sexprs, so we just need to
458 * walk that list. Set ao_lisp_v to the car of the list and jump to
459 * eval_sexpr. When that's done, it will land in eval_val. For all but
460 * the last, leave a stack frame with eval_progn set so that we come
461 * back here. For the last, don't add a stack frame so that we can
465 ao_lisp_eval_progn(void)
467 DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
468 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
469 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
471 if (!ao_lisp_stack->sexprs) {
472 ao_lisp_v = AO_LISP_NIL;
473 ao_lisp_stack->state = eval_val;
475 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
476 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
477 if (ao_lisp_stack->sexprs) {
478 ao_lisp_stack->state = eval_progn;
479 if (!ao_lisp_stack_push())
482 ao_lisp_stack->state = eval_sexpr;
488 * Conditionally execute a list of sexprs while the first is true
491 ao_lisp_eval_while(void)
493 DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
494 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
495 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
497 if (!ao_lisp_stack->sexprs) {
498 ao_lisp_v = AO_LISP_NIL;
499 ao_lisp_stack->state = eval_val;
501 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
502 ao_lisp_stack->state = eval_while_test;
503 if (!ao_lisp_stack_push())
505 ao_lisp_stack->state = eval_sexpr;
511 * Check the while condition, terminate the loop if nil. Otherwise keep going
514 ao_lisp_eval_while_test(void)
516 DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
517 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
518 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
521 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
523 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
524 ao_lisp_stack->state = eval_while;
525 if (!ao_lisp_stack_push())
529 ao_lisp_stack->state = eval_val;
533 static int (*const evals[])(void) = {
534 [eval_sexpr] = ao_lisp_eval_sexpr,
535 [eval_val] = ao_lisp_eval_val,
536 [eval_formal] = ao_lisp_eval_formal,
537 [eval_exec] = ao_lisp_eval_exec,
538 [eval_cond] = ao_lisp_eval_cond,
539 [eval_cond_test] = ao_lisp_eval_cond_test,
540 [eval_progn] = ao_lisp_eval_progn,
541 [eval_while] = ao_lisp_eval_while,
542 [eval_while_test] = ao_lisp_eval_while_test,
546 ao_lisp_eval(ao_poly _v)
548 static uint8_t been_here;
553 ao_lisp_root_add(&ao_lisp_stack_type, &ao_lisp_stack);
554 ao_lisp_root_poly_add(&ao_lisp_v);
557 if (!ao_lisp_stack_push())
560 while (ao_lisp_stack) {
561 if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
562 ao_lisp_stack_clear();
566 DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");});
567 ao_lisp_frame_current = NULL;