x-engine-c v0.2.31
The C engine for x-lang
Loading...
Searching...
No Matches
x-prim.h File Reference

Primitive function infrastructure and registration. More...

#include "x-obj.h"
#include "x-heap.h"
#include "x-eval.h"
#include <stdarg.h>

Go to the source code of this file.

Data Structures

struct  x_callable_entry_t
 
struct  x_prim_entry_t
 

Functions

static void __attribute__ ((unused)) x_args(x_obj_t *p_base
 
 va_start (ap, count)
 
 for (i=0;i< count;i++)
 
 va_end (ap)
 
 x_heap_root_push (p_cell, roots[0])
 
 x_heap_root_push (p_cell, roots[1])
 
 x_heap_root_pop (p_cell)
 
void x_value_bind (x_obj_t *p_base, x_char_t *name, x_obj_t *p_val)
 
void x_callable_bind (x_obj_t *p_base, x_char_t *name, x_fn_t fn)
 
void x_callable_bind_table (x_obj_t *p_base, const x_callable_entry_t *table, int count)
 
x_obj_t * x_prims (x_obj_t *p_base)
 
void x_prims_bind_table (x_obj_t *p_base, const x_prim_entry_t *table, int count)
 
x_obj_t * x_prim_register (x_obj_t *p_base, x_obj_t *p_args)
 
Module Registration Functions
x_obj_t * x_prim_core_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_arith_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_pred_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_string_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_io_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_heap_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_heap_mark_phase (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_heap_sweep_phase (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_heap_run_hooks (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_image_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_repl (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_type_register (x_obj_t *p_base, x_obj_t *p_args)
 Register all type-system and sandboxing primitives.
 
x_obj_t * x_prim_type_build_struct (x_obj_t *p_base, x_obj_t *p_name_atom, x_obj_t *p_handlers)
 Build a type struct from a handlers alist.
 
x_obj_t * x_prim_base_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_op1 (x_obj_t *p_base, x_obj_t *p_args, x_obj_t *(*op)(x_obj_t *, x_obj_t *))
 
x_obj_t * x_prim_buffer_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_iter_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_prim_ffi_register (x_obj_t *p_base, x_obj_t *p_args)
 Register all FFI primitives and platform constants.
 
x_obj_t * x_prim_callcc_register (x_obj_t *p_base, x_obj_t *p_args)
 
void x_callcc_init (void)
 

Variables

static void x_obj_t * p_args
 
static void x_obj_t int count
 
static void x_obj_t int int i
 
int held = 0
 
x_obj_t ** p_cell = x_heap_root_slot(p_base)
 
x_spair_t roots [2]
 

Detailed Description

Primitive function infrastructure and registration.

Declares the callable binding mechanism used to register C primitives into the x-lang environment, argument unpacking helpers, body/TCO evaluation entry points, and the per-module register functions.

Author
Jon Ruttan (jonru.nosp@m.ttan.nosp@m.@gmai.nosp@m.l.co.nosp@m.m)

Function Documentation

◆ x_callcc_init()

void x_callcc_init ( void  )

Initialize the call/cc subsystem.

Establish the stack base address for continuation capture.

Must be called once at interpreter startup, from a frame close to the bottom of the C call stack (typically main). The address of a local variable is recorded as the upper bound of all future stack captures.

Note
Uses a volatile local to prevent the compiler from eliminating the anchor variable.

◆ x_heap_mark_phase()

x_obj_t * x_heap_mark_phase ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

The collector's mark phase, a routine in the slot vector. Arguments: ().

Mark phase: trace live objects from every root (GC phase 1).

Four passes: (1) fire mark hooks, (2) tree-mark from the base data tree, (3) root-chain walk – the off-chain stack objects frames registered via x_heap_root_push, (4) tree-mark each registered GC root. The hook/root lists live in x-expr's heap-fields; x-expr stores but cannot dispatch (no callable mechanism at that layer), so the walk + invoke happens here.

Hooks MUST fire before the marking passes: everything a hook allocates is born unmarked, and the sweep that follows this phase frees every unmarked object. Firing hooks first means a hook allocation that escaped into reachable state – a (heap-mark-root!) spine cell, a set! into a global – is marked by the later passes and survives, while the hook's transient garbage is correctly swept. It also makes a root registered mid-collect count in the same cycle (pass 4 runs after the hooks push it). With hooks last, the sweep freed the escaped cells and left reachable dangling pointers – a use-after-free on the next collect (usually silent: the chunk is recycled and the mark walk traverses a reinterpreted object; ASan catches it only when the chunk stays unreused).

Note
A sweep must run with no allocation between it and this mark: a transient cell allocated after the mark is unmarked, so an intervening sweep frees it while the evaluator is still traversing it (see x_prim_heap_collect). A routine in the base's slot vector (X_SLOT_HEAP_MARK): a base may have a mark phase of its own.
Parameters
p_baseBase (execution context).
p_argsUnused: the run has no words.
Returns
NULL.
See also
x_heap_sweep_phase

◆ x_heap_run_hooks()

x_obj_t * x_heap_run_hooks ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Fire each hook on a hook list. Arguments: (hooks). Types: (object).

Fire each hook on a hook list, draining any deferred tail call. Arguments: (hooks). Types: (object). Shared by the mark and free hook walks (mark_phase / sweep_phase). A procedure hook that returns a non-nil tail leaves the env extended and tco_expr/tco_env set for an outer trampoline; there is none here, so drain it via x_eval_tco_trampoline – otherwise the env frame the hook left live is freed by the sweep and the next eval dereferences it.

◆ x_heap_sweep_phase()

x_obj_t * x_heap_sweep_phase ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

The collector's sweep phase, a routine in the slot vector. Arguments: ().

Sweep phase: fire free hooks, then reclaim unmarked objects (GC phase 2). x_heap_sweep also clears the mark flag on retained objects, readying them for the next cycle. A routine in the base's slot vector (X_SLOT_HEAP_SWEEP).

Parameters
p_baseBase (execution context).
p_argsUnused: the run has no words.
Returns
NULL.
See also
x_heap_mark_phase

◆ x_prim_arith_register()

x_obj_t * x_prim_arith_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register arithmetic primitives (+, -, *, /, %, ~, &, |, ^, <<, >>).

Register arithmetic primitives into the environment.

Binds: +, -, *, /, %, ~, &, |, ^, <<, >>

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – Unused
Returns
x_obj_t* – p_base

◆ x_prim_base_register()

x_obj_t * x_prim_base_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register the sandbox base primitives (make-base, base-eval, etc.).

Register the sandbox base primitives.

◆ x_prim_buffer_register()

x_obj_t * x_prim_buffer_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register the buffer/tokenizer primitives.

Register the buffer and tokenizer primitives.

◆ x_prim_callcc_register()

x_obj_t * x_prim_callcc_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register call/cc continuation primitives.

Register continuation primitives.

Binds: cc-invoke, call/cc.

Parameters
p_baseInterpreter base context.
p_argsUnused.
Returns
p_base.

◆ x_prim_core_register()

x_obj_t * x_prim_core_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register core primitives (pair, first, rest, apply, eval, eval!, tail-eval, wrap, unwrap, atomic, base).

Register core primitives into the environment.

Binds: pair, first, rest, apply, eval, eval!, tail-eval, wrap, unwrap, atomic, base.

Parameters
p_baseBase (execution context).
p_argsUnused.
Returns
The base object.

◆ x_prim_ffi_register()

x_obj_t * x_prim_ffi_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register all FFI primitives and platform constants.

Register FFI primitives (dlopen, dlsym, ffi-call, ptr-call, int->ptr/ptr->int, mem-*, ptr-*).

Binds: ptr-call, int->ptr, ptr->int, ptr->obj, ptr-set!, ptr-ref, ptr-ref-word, ptr-set-word!, obj->ptr, str->ptr, ptr->str, make-callable. (The obj-meta-* accessors are pure x-lang now: boot/reflect.x files reflective implementations into the catalogue over tools/contract/obj-layout.x and tools/contract/base-paths.x.)

Platform constants live in X, not here: word size is probed by boot/data.x, and the O_* open flags come from the per-OS tables in x/platform/syscall.x.

Parameters
p_baseBase (execution context) to bind primitives into.
p_argsUnused.
Returns
p_base.

◆ x_prim_heap_register()

x_obj_t * x_prim_heap_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register the GC primitives (heap-*, alloc-limit!, gc-pin!).

Register the GC primitives.

◆ x_prim_image_register()

x_obj_t * x_prim_image_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register the state-image primitives (image save!, image rebuild!).

Register the state-image primitives.

◆ x_prim_io_register()

x_obj_t * x_prim_io_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register I/O and heap primitives (write-str, read, read-char, clock, repl-read, heap-collect/-mark/-sweep/-count, alloc-limit!, heap-*-hook!, gc-pin!).

Register I/O primitives into the environment.

Binds: write-str, read, read-char, heap-mark, heap-sweep, heap-count, gc-pin!, repl-read. Conditionally binds clock (when X_SYS_CLOCK defined). (The printers – write, display, write-to-str, display-to-str – and error-line are pure x-lang now: boot/printer.x renders over the (io write-str) OUT door; boot/reflect.x walks the error handler.)

Parameters
p_baseBase (execution context).
p_argsUnused.
Returns
The base object.

◆ x_prim_iter_register()

x_obj_t * x_prim_iter_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register the iterator primitives.

◆ x_prim_op1()

x_obj_t * x_prim_op1 ( x_obj_t *  p_base,
x_obj_t *  p_args,
x_obj_t *(*)(x_obj_t *, x_obj_t *)  op 
)

Apply a single-arg type handler through the prim ABI (shared by the buffer and iter primitives).

Evaluate one argument and pass it as a 1-element list to a type operation.

The argument list is built on the stack (no heap allocation), so these wrappers stay safe inside reader/tokenizer callbacks. C primitives receive unevaluated args, hence the explicit x_eargs before delegating.

Parameters
p_baseBase (execution context).
p_argsUnevaluated: (self obj).
opThe type operation to drive with the evaluated object.
Returns
Whatever the operation returns.

◆ x_prim_pred_register()

x_obj_t * x_prim_pred_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register predicate primitives (same?, eq?, =, <, char->integer, integer->char).

Register predicate and type-conversion primitives.

Binds: same?, eq?, =, <, char->integer, integer->char.

Parameters
p_baseInterpreter base context.
p_argsUnused.
Returns
p_base.

◆ x_prim_register()

x_obj_t * x_prim_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register all primitive modules into the base environment.

Register all built-in primitives into the environment.

Binds the #t and #f boolean singletons, caches them in the base object, then delegates to each primitive module's register function (core, quote, binding, closure, control, arith, pred, string, io, type, ffi, callcc).

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – Unused
Returns
x_obj_t* – p_base

◆ x_prim_repl()

x_obj_t * x_prim_repl ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Minimal C read-eval loop (no output, no hooks).

Minimal read-eval loop: reads and evaluates expressions until EOF.

Parameters
p_baseBase (execution context).
p_argsUnused.
Returns
NULL on EOF.
Note
No output, no prompt, no hooks. Used for C-level bootstrapping; the x-lang REPL operative in x-core.x provides the full experience.

◆ x_prim_string_register()

x_obj_t * x_prim_string_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register string primitives (str-append, make-str, str->symbol, symbol->str, bytes->str, str-byte-len/-ref/-sub).

Register string manipulation primitives.

Binds: str-append, str->symbol, symbol->str, bytes->str, str-byte-len, str-byte-ref, str-byte-sub.

Note
bytes->str is the raw byte-packer (one low byte per char). The code-point-aware list->str is pure x-lang (x/type/str-utf8), UTF-8 encoding each char on top of bytes->str; boot-time callers that want bytes call bytes->str directly.
Parameters
p_baseInterpreter base context.
p_argsUnused.
Returns
p_base.

◆ x_prim_type_build_struct()

x_obj_t * x_prim_type_build_struct ( x_obj_t *  p_base,
x_obj_t *  p_name_atom,
x_obj_t *  p_handlers 
)

Build a type struct from a handlers alist.

Build a type pair-tree from a name atom and handler alist (shared by make-type and base-make-type).

Iterates a table of known handler field names (call, eval, write, display, length, analyse, delimit, read, error, from, to, units, free, mark, iter), looks each up in p_handlers via alist association, and populates the corresponding x_type_t slot.

Parameters
p_baseBase (execution context) used for symbol lookup and allocation.
p_name_atomAtom for the type name.
p_handlersAlist mapping handler name symbols to closures.
Returns
Heap-allocated type struct object.

◆ x_prim_type_register()

x_obj_t * x_prim_type_register ( x_obj_t *  p_base,
x_obj_t *  p_args 
)

Register all type-system and sandboxing primitives.

Register the type/base/buffer/token/iter primitives (make-type, make-instance, type?, type-of, make-base, base-eval, token-read, buffer-*, make-iter, iter-*).

Binds: make-type, base-make-type, make-instance, make-obj, type?, type-of, buffer-token, make-token-base, make-base, base-eval, base-bind, token-read, token-read-string. ((iter new) is pure x-lang now: boot/reflect.x dispatches the type tree's iter handler over the layout contracts.) (obj-ref / obj-set! / type-name are pure x-lang now: boot/data.x + boot/reflect.x implement them reflectively over the layout contracts.) ((obj relabel!) is pure x-lang too: boot/reflect.x writes the type header slot over the layout contract – retired from C by the #101 ruling.)

Parameters
p_baseBase (execution context) to bind primitives into.
p_argsUnused.
Returns
p_base.