81 lines
2.3 KiB
C
81 lines
2.3 KiB
C
#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
|