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.
19 const struct ao_lisp_type ao_lisp_stack_type;
22 stack_size(void *addr)
25 return sizeof (struct ao_lisp_stack);
29 stack_mark(void *addr)
31 struct ao_lisp_stack *stack = addr;
33 ao_lisp_poly_mark(stack->sexprs, 0);
34 ao_lisp_poly_mark(stack->values, 0);
35 /* no need to mark values_tail */
36 ao_lisp_poly_mark(stack->frame, 0);
37 ao_lisp_poly_mark(stack->list, 0);
38 stack = ao_lisp_poly_stack(stack->prev);
39 if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack))
45 stack_move(void *addr)
47 struct ao_lisp_stack *stack = addr;
50 struct ao_lisp_stack *prev;
52 (void) ao_lisp_poly_move(&stack->sexprs, 0);
53 (void) ao_lisp_poly_move(&stack->values, 0);
54 (void) ao_lisp_poly_move(&stack->values_tail, 0);
55 (void) ao_lisp_poly_move(&stack->frame, 0);
56 (void) ao_lisp_poly_move(&stack->list, 0);
57 prev = ao_lisp_poly_stack(stack->prev);
60 ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev);
61 if (prev != ao_lisp_poly_stack(stack->prev))
62 stack->prev = ao_lisp_stack_poly(prev);
69 const struct ao_lisp_type ao_lisp_stack_type = {
76 struct ao_lisp_stack *ao_lisp_stack;
79 struct ao_lisp_stack *ao_lisp_stack_free_list;
82 ao_lisp_set_cond(struct ao_lisp_cons *c)
84 ao_lisp_stack->state = eval_cond;
85 ao_lisp_stack->sexprs = ao_lisp_cons_poly(c);
90 ao_lisp_stack_reset(struct ao_lisp_stack *stack)
92 stack->state = eval_sexpr;
93 stack->sexprs = AO_LISP_NIL;
94 stack->values = AO_LISP_NIL;
95 stack->values_tail = AO_LISP_NIL;
100 ao_lisp_stack_push(void)
102 struct ao_lisp_stack *stack;
103 if (ao_lisp_stack_free_list) {
104 stack = ao_lisp_stack_free_list;
105 ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev);
107 stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack));
111 stack->prev = ao_lisp_stack_poly(ao_lisp_stack);
112 stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current);
113 stack->list = AO_LISP_NIL;
114 ao_lisp_stack = stack;
115 ao_lisp_stack_reset(stack);
116 DBGI("stack push\n");
123 ao_lisp_stack_pop(void)
126 struct ao_lisp_frame *prev_frame;
130 prev = ao_lisp_stack->prev;
131 ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list);
132 ao_lisp_stack_free_list = ao_lisp_stack;
134 ao_lisp_stack = ao_lisp_poly_stack(prev);
135 prev_frame = ao_lisp_frame_current;
137 ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame);
139 ao_lisp_frame_current = NULL;
140 if (ao_lisp_frame_current != prev_frame)
141 ao_lisp_frame_free(prev_frame);
148 ao_lisp_stack_clear(void)
150 ao_lisp_stack = NULL;
151 ao_lisp_frame_current = NULL;
152 ao_lisp_v = AO_LISP_NIL;
156 func_type(ao_poly func)
158 if (func == AO_LISP_NIL)
159 return ao_lisp_error(AO_LISP_INVALID, "func is nil");
160 switch (ao_lisp_poly_type(func)) {
161 case AO_LISP_BUILTIN:
162 return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK;
164 return ao_lisp_poly_lambda(func)->args;
166 ao_lisp_error(AO_LISP_INVALID, "not a func");
172 * Flattened eval to avoid stack issues
176 * Evaluate an s-expression
178 * For a list, evaluate all of the elements and
179 * then execute the resulting function call.
181 * Each element of the list is evaluated in
182 * a clean stack context.
184 * The current stack state is set to 'formal' so that
185 * when the evaluation is complete, the value
186 * will get appended to the values list.
188 * For other types, compute the value directly.
192 ao_lisp_eval_sexpr(void)
194 DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n");
195 switch (ao_lisp_poly_type(ao_lisp_v)) {
197 if (ao_lisp_v == AO_LISP_NIL) {
198 if (!ao_lisp_stack->values) {
200 * empty list evaluates to empty list
202 ao_lisp_v = AO_LISP_NIL;
203 ao_lisp_stack->state = eval_val;
206 * done with arguments, go execute it
208 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car;
209 ao_lisp_stack->state = eval_exec;
212 if (!ao_lisp_stack->values)
213 ao_lisp_stack->list = ao_lisp_v;
215 * Evaluate another argument and then switch
216 * to 'formal' to add the value to the values
219 ao_lisp_stack->sexprs = ao_lisp_v;
220 ao_lisp_stack->state = eval_formal;
221 if (!ao_lisp_stack_push())
224 * push will reset the state to 'sexpr', which
225 * will evaluate the expression
227 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
231 DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
232 ao_lisp_v = ao_lisp_atom_get(ao_lisp_v);
236 case AO_LISP_BUILTIN:
238 ao_lisp_stack->state = eval_val;
241 DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n");
246 * A value has been computed.
248 * If the value was computed from a macro,
249 * then we want to reset the current context
250 * to evaluate the macro result again.
252 * If not a macro, then pop the stack.
253 * If the stack is empty, we're done.
254 * Otherwise, the stack will contain
259 ao_lisp_eval_val(void)
261 DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n");
263 * Value computed, pop the stack
264 * to figure out what to do with the value
267 DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1);
272 * A formal has been computed.
274 * If this is the first formal, then check to see if we've got a
275 * lamda/lexpr or macro/nlambda.
277 * For lambda/lexpr, go compute another formal. This will terminate
278 * when the sexpr state sees nil.
280 * For macro/nlambda, we're done, so move the sexprs into the values
283 * Macros have an additional step of saving a stack frame holding the
284 * macro value execution context, which then gets the result of the
289 ao_lisp_eval_formal(void)
292 struct ao_lisp_stack *prev;
294 DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n");
296 /* Check what kind of function we've got */
297 if (!ao_lisp_stack->values) {
298 switch (func_type(ao_lisp_v)) {
299 case AO_LISP_FUNC_LAMBDA:
300 case AO_LISP_FUNC_LEXPR:
301 DBGI(".. lambda or lexpr\n");
303 case AO_LISP_FUNC_MACRO:
304 /* Evaluate the result once more */
305 ao_lisp_stack->state = eval_macro;
306 if (!ao_lisp_stack_push())
309 /* After the function returns, take that
310 * value and re-evaluate it
312 prev = ao_lisp_poly_stack(ao_lisp_stack->prev);
313 ao_lisp_stack->sexprs = prev->sexprs;
315 DBGI(".. start macro\n");
316 DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
317 DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
320 /* fall through ... */
321 case AO_LISP_FUNC_NLAMBDA:
322 DBGI(".. nlambda or macro\n");
324 /* use the raw sexprs as values */
325 ao_lisp_stack->values = ao_lisp_stack->sexprs;
326 ao_lisp_stack->values_tail = AO_LISP_NIL;
327 ao_lisp_stack->state = eval_exec;
329 /* ready to execute now */
336 /* Append formal to list of values */
337 formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL));
341 if (ao_lisp_stack->values_tail)
342 ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal;
344 ao_lisp_stack->values = formal;
345 ao_lisp_stack->values_tail = formal;
347 DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n");
350 * Step to the next argument, if this is last, then
351 * 'sexpr' will end up switching to 'exec'
353 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
355 ao_lisp_stack->state = eval_sexpr;
357 DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n");
362 * Start executing a function call
364 * Most builtins are easy, just call the function.
365 * 'cond' is magic; it sticks the list of clauses
366 * in 'sexprs' and switches to 'cond' state. That
367 * bit of magic is done in ao_lisp_set_cond.
369 * Lambdas build a new frame to hold the locals and
370 * then re-use the current stack context to evaluate
371 * the s-expression from the lambda.
375 ao_lisp_eval_exec(void)
378 struct ao_lisp_builtin *builtin;
380 DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n");
381 ao_lisp_stack->sexprs = AO_LISP_NIL;
382 switch (ao_lisp_poly_type(ao_lisp_v)) {
383 case AO_LISP_BUILTIN:
384 ao_lisp_stack->state = eval_val;
385 builtin = ao_lisp_poly_builtin(ao_lisp_v);
386 v = ao_lisp_func(builtin) (
387 ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr));
388 DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) {
389 struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values);
390 ao_poly atom = ao_lisp_arg(cons, 1);
391 ao_poly val = ao_lisp_arg(cons, 2);
392 DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n");
394 builtin = ao_lisp_poly_builtin(ao_lisp_v);
395 if (builtin->args & AO_LISP_FUNC_FREE_ARGS)
396 ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values));
399 DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n");
400 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
403 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
404 ao_lisp_stack->state = eval_progn;
405 v = ao_lisp_lambda_eval();
406 ao_lisp_stack->sexprs = v;
407 DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
408 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
411 ao_lisp_stack->values = AO_LISP_NIL;
412 ao_lisp_stack->values_tail = AO_LISP_NIL;
417 * Start evaluating the next cond clause
419 * If the list of clauses is empty, then
420 * the result of the cond is nil.
422 * Otherwise, set the current stack state to 'cond_test' and create a
423 * new stack context to evaluate the test s-expression. Once that's
424 * complete, we'll land in 'cond_test' to finish the clause.
427 ao_lisp_eval_cond(void)
429 DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
430 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
431 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
432 if (!ao_lisp_stack->sexprs) {
433 ao_lisp_v = AO_LISP_NIL;
434 ao_lisp_stack->state = eval_val;
436 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
437 if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) {
438 ao_lisp_error(AO_LISP_INVALID, "invalid cond clause");
441 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car;
442 ao_lisp_stack->state = eval_cond_test;
443 if (!ao_lisp_stack_push())
450 * Finish a cond clause.
452 * Check the value from the test expression, if
453 * non-nil, then set up to evaluate the value expression.
455 * Otherwise, step to the next clause and go back to the 'cond'
459 ao_lisp_eval_cond_test(void)
461 DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
462 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
463 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
465 struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car);
466 ao_poly c = car->cdr;
469 ao_lisp_stack->state = eval_progn;
470 ao_lisp_stack->sexprs = c;
472 ao_lisp_stack->state = eval_val;
474 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
475 DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
476 ao_lisp_stack->state = eval_cond;
482 * Evaluate a list of sexprs, returning the value from the last one.
484 * ao_lisp_progn records the list in stack->sexprs, so we just need to
485 * walk that list. Set ao_lisp_v to the car of the list and jump to
486 * eval_sexpr. When that's done, it will land in eval_val. For all but
487 * the last, leave a stack frame with eval_progn set so that we come
488 * back here. For the last, don't add a stack frame so that we can
492 ao_lisp_eval_progn(void)
494 DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
495 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
496 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
498 if (!ao_lisp_stack->sexprs) {
499 ao_lisp_v = AO_LISP_NIL;
500 ao_lisp_stack->state = eval_val;
502 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
503 ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
505 /* If there are more sexprs to do, then come back here, otherwise
506 * return the value of the last one by just landing in eval_sexpr
508 if (ao_lisp_stack->sexprs) {
509 ao_lisp_stack->state = eval_progn;
510 if (!ao_lisp_stack_push())
513 ao_lisp_stack->state = eval_sexpr;
519 * Conditionally execute a list of sexprs while the first is true
522 ao_lisp_eval_while(void)
524 DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
525 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
526 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
528 ao_lisp_stack->values = ao_lisp_v;
529 if (!ao_lisp_stack->sexprs) {
530 ao_lisp_v = AO_LISP_NIL;
531 ao_lisp_stack->state = eval_val;
533 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car;
534 ao_lisp_stack->state = eval_while_test;
535 if (!ao_lisp_stack_push())
542 * Check the while condition, terminate the loop if nil. Otherwise keep going
545 ao_lisp_eval_while_test(void)
547 DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
548 DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");
549 DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n");
552 ao_lisp_stack->values = ao_lisp_v;
553 ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr;
554 ao_lisp_stack->state = eval_while;
555 if (!ao_lisp_stack_push())
557 ao_lisp_stack->state = eval_progn;
558 ao_lisp_stack->sexprs = ao_lisp_v;
562 ao_lisp_stack->state = eval_val;
563 ao_lisp_v = ao_lisp_stack->values;
569 * Replace the original sexpr with the macro expansion, then
573 ao_lisp_eval_macro(void)
575 DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n");
577 if (ao_lisp_v == AO_LISP_NIL)
579 if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) {
580 *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v);
581 ao_lisp_v = ao_lisp_stack->sexprs;
582 DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n");
584 ao_lisp_stack->sexprs = AO_LISP_NIL;
585 ao_lisp_stack->state = eval_sexpr;
589 static int (*const evals[])(void) = {
590 [eval_sexpr] = ao_lisp_eval_sexpr,
591 [eval_val] = ao_lisp_eval_val,
592 [eval_formal] = ao_lisp_eval_formal,
593 [eval_exec] = ao_lisp_eval_exec,
594 [eval_cond] = ao_lisp_eval_cond,
595 [eval_cond_test] = ao_lisp_eval_cond_test,
596 [eval_progn] = ao_lisp_eval_progn,
597 [eval_while] = ao_lisp_eval_while,
598 [eval_while_test] = ao_lisp_eval_while_test,
599 [eval_macro] = ao_lisp_eval_macro,
603 * Called at restore time to reset all execution state
607 ao_lisp_eval_clear_globals(void)
609 ao_lisp_stack = NULL;
610 ao_lisp_frame_current = NULL;
611 ao_lisp_v = AO_LISP_NIL;
615 ao_lisp_eval_restart(void)
617 return ao_lisp_stack_push();
621 ao_lisp_eval(ao_poly _v)
625 if (!ao_lisp_stack_push())
628 while (ao_lisp_stack) {
629 if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) {
630 ao_lisp_stack_clear();
634 DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");});
635 ao_lisp_frame_current = NULL;