#ifndef INCLUDED_STACK_H #define INCLUDED_STACK_H #include "base.h" #include "list.h" #define DEFAULT_MAX_LISP_EVAL_DEPTH 1000 #define LOCAL_REFERENCES_BLOCK_LENGTH 64 struct LocalReferencesBlock { LispVal *refs[LOCAL_REFERENCES_BLOCK_LENGTH]; }; struct LocalReferences { size_t num_blocks; size_t num_refs; struct LocalReferencesBlock **blocks; }; struct StackFrame { LispVal *name; // name of function call LispVal *fobj; // the function object bool evaled_args; // whether args have been evaluated yet LispVal *args; // arguments of the function call LispVal *lexenv; // lexical environment (plist) struct LocalReferences local_refs; }; struct LispStack { size_t max_depth; size_t depth; size_t first_clear_local_refs; // index of the first frame that has local // refs that has not been grown struct StackFrame *frames; LispVal *nogc_retval; }; extern struct LispStack the_stack; static ALWAYS_INLINE struct StackFrame *LISP_STACK_TOP(void) { return the_stack.depth ? &the_stack.frames[the_stack.depth - 1] : NULL; } static ALWAYS_INLINE LispVal *TOP_LEXENV(void) { return the_stack.depth ? LISP_STACK_TOP()->lexenv : Qnil; } static ALWAYS_INLINE LispVal *PARENT_LEXENV(void) { return the_stack.depth > 1 ? the_stack.frames[the_stack.depth - 2].lexenv : Qnil; } void lisp_init_stack(void); void lisp_teardown_stack(void); void push_stack_frame(LispVal *name, LispVal *fobj, LispVal *args); void pop_stack_frame(void); void add_local_reference_no_recurse(LispVal *obj); void add_local_reference(LispVal *obj); // replace the args in the top stack frame with ARGS and mark them as evaluted // (this is for backtraces) void set_stack_evaluated_args(LispVal *args); // Return true if successful, false if not found and not created bool set_lexical_variable(LispVal *name, LispVal *value, bool create_if_absent); // Just add a new lexical variable without any checking static inline void new_lexical_variable(LispVal *name, LispVal *value) { assert(the_stack.depth != 0); LISP_STACK_TOP()->lexenv = CONS(name, CONS(value, LISP_STACK_TOP()->lexenv)); } // Copy the previous frame's lexenv to the top of the stack. void copy_parent_lexenv(void); // used by the GC void compact_stack_frame(struct StackFrame *restrict frame); #endif