|
x-engine-c v0.2.13
The C engine for x-lang
|
The top-level bracket around a file's forms and around eval!. More...
Functions | |
| void | x_toplevel_enter (x_obj_t *p_base, x_toplevel_t *p_t) |
| void | x_toplevel_leave (x_obj_t *p_base, x_toplevel_t *p_t) |
The top-level bracket around a file's forms and around eval!.
| void x_toplevel_enter | ( | x_obj_t * | p_base, |
| x_toplevel_t * | p_t | ||
| ) |
Enter the top-level bracket: what a form evaluated at top level sees, whatever environment is current when it is asked for.
A top-level form's defs must bind in the root, and the closures it makes must capture the root – not the environment of whatever was being evaluated when the form was asked for. Two doors ask: x_eval_load, for every form of a file (include runs under whatever called it, and its x-level wrapper is a closure), and eval!, for the one form the REPL loop reads (lib/he.x reaches (repl) through (unless batch? (do (banner) (repl))), so every form typed at the prompt sits under those frames). The bracket is two moves: the save-stack is hidden (nil), so a form sees an empty stack exactly as at the true top level and each x_eval balances its own pushes; and the root is made current.
The displaced state is HEAP: the caller's environment and its save-stack, and for the length of the bracket nothing on the base tree reaches them. A C local is not a root (x-heap.h), so a form that collects (a library collecting between definitions is ordinary) would sweep them, and the caller would walk freed memory on its next lookup. So both are parked on the root chain in the caller's own struct, one registered node holding the two pointers; the pop is in x_toplevel_leave. The error path needs nothing more: a guard restores the root chain and the save-stack from its own snapshot, so a longjmp out of a bracketed form drops the node with the C frame that owns it.
| p_base | x_obj_t* – Base (execution context) |
| p_t | x_toplevel_t* – the caller's bracket state, filled here |
| void x_toplevel_leave | ( | x_obj_t * | p_base, |
| x_toplevel_t * | p_t | ||
| ) |
Leave the top-level bracket: unroot the parked state and put it back.
| p_base | x_obj_t* – Base (execution context) |
| p_t | x_toplevel_t* – the state x_toplevel_enter filled |