|
x-engine-c v0.2.13
The C engine for x-lang
|
Procedure (applicative closure) type implementation. More...
#include "x-type/procedure.h"#include "x-eval.h"#include "x-env.h"#include "x-tco.h"#include "x-heap.h"#include "x-obj/prim.h"#include "x-prim.h"Functions | |
| static x_obj_t * | x_type_procedure_mark (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_make_procedure (x_obj_t *p_base, x_obj_flag_t flags, x_obj_t *p_params, x_obj_t *p_body, x_obj_t *p_env) |
| x_obj_t * | x_type_procedure_save (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_type_procedure_struct (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_type_procedure_register (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_type_procedure_make (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_type_procedure_call (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_type_procedure_apply (x_obj_t *p_base, x_obj_t *p_args) |
Variables | |
| static x_satom_t | x_type_procedure_mark_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_mark }) |
| static x_satom_t | x_type_procedure_units_obj = x_obj_set(NULL, X_OBJ_FLAG_NONE, { .i = 2 }) |
| x_satom_t | x_type_procedure_name = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { .s = (x_char_t *)X_TYPE_PROCEDURE_NAME }) |
| x_satom_t | x_type_procedure_make_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_make }) |
| x_satom_t | x_type_procedure_call_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_call }) |
| x_satom_t | x_type_procedure_struct_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_struct }) |
| x_satom_t | x_type_procedure_save_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_save }) |
Procedure (applicative closure) type implementation.
| x_obj_t * x_make_procedure | ( | x_obj_t * | p_base, |
| x_obj_flag_t | flags, | ||
| x_obj_t * | p_params, | ||
| x_obj_t * | p_body, | ||
| x_obj_t * | p_env | ||
| ) |
Allocate a new procedure (closure) on the heap.
Builds the state list (params . (body . env)) and stores it in slot 1 of the two-unit callable layout.
| p_base | x_obj_t* – Base (execution context) |
| flags | x_obj_flag_t – Object flags (e.g. X_OBJ_FLAG_WRAP) |
| p_params | x_obj_t* – Formal parameter tree |
| p_body | x_obj_t* – Body expression list |
| p_env | x_obj_t* – Captured lexical environment |
Non-TCO apply path for (apply f args).
Arguments are already evaluated. Saves and restores the full environment state around body evaluation.
Unlike x_type_procedure_call, this path does NOT use the TCO trampoline. It calls x_eval_body (not x_eval_body_tco), which means the C call stack grows with each nested apply. This is necessary because apply is called from contexts where the caller needs the result immediately (e.g. map, fold, for-each).
The current environment is saved to a local before body evaluation and made current again afterward.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – (procedure . evaluated-args) |
Type-dispatch call callback: evaluate a procedure application (TCO).
For wrapped combiners (applicatives), dispatches to the underlying combiner with evaluated arguments. For plain closures, extends the environment, pushes a save-stack frame, and enters the body via TCO.
Two dispatch paths based on X_OBJ_FLAG_WRAP:
Wrapped applicative (WRAP flag set): The procedure is a thin wrapper around another combiner stored in the env slot. Args are evaluated, then the underlying combiner is called via x_obj_prim_call. This is how (wrap op) creates an applicative from an operative.
Plain closure (no WRAP flag): Pushes the caller's environment onto the save-stack, makes a child of the closure's environment with the parameters bound current, and enters the body via x_eval_body_tco for tail-call optimization – the trampoline loop in x_eval makes the saved environment current again when the TCO chain completes.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – (procedure . unevaluated-args) |
Type-dispatch make callback: construct a procedure from x-lang args.
Expects args: (params body env [flags]).
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Construction arguments |
GC mark callback for procedure objects.
Only marks slot 1 (state list), not slot 0 (fn ptr).
Procedure heap layout has two data slots:
Slot 0 is skipped because it holds a raw x_fn_t cast to x_obj_t*. Passing it to x_heap_tree_mark would chase an invalid heap pointer and corrupt the mark bitmap or segfault. Only slot 1 (the state pair list) contains GC-managed objects that need marking.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – (object . (flags)) |
Register (or retrieve) the PROCEDURE type struct on p_base.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Unused |
Build the PROCEDURE type struct descriptor.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Unused |
Build the PROCEDURE type struct descriptor.
| x_satom_t x_type_procedure_call_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_call }) |
| x_satom_t x_type_procedure_make_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_make }) |
|
static |
| x_satom_t x_type_procedure_name = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { .s = (x_char_t *)X_TYPE_PROCEDURE_NAME }) |
| x_satom_t x_type_procedure_save_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_save }) |
| x_satom_t x_type_procedure_struct_prim = x_obj_set(x_type_atom_obj, X_OBJ_FLAG_NONE, { (x_obj_t *)&x_type_procedure_struct }) |
|
static |