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

Procedure (applicative closure) type for x-lang. More...

#include "x-type.h"
#include "x-type/prim.h"

Go to the source code of this file.

Macros

#define X_TYPE_PROCEDURE_NAME   "PROCEDURE"
 
#define X_OBJ_FLAG_WRAP   X_OBJ_FLAG_1
 
Type predicates
#define x_obj_type_isprocedure(B, X)   x_obj_is_type((B), (X), X_TYPE_PROCEDURE_NAME)
 
State accessors

Procedure state list: (params . (body . env)). Stored in x_callable_state (slot 1) of [fn-ptr][state] layout. GC traverses via the p_units=2 fallback in x_type_heap_mark.

The environment is the one the closure was made in, and a call makes a child of it. It reaches the root through its parents, so a closure carries no separate copy of the global tree the way it once did; the root is an environment like any other.

#define x_procstate(X)   x_callable_state((X))
 
#define x_procparams(X)   x_firstobj(x_procstate((X)))
 
#define x_procbody(X)   x_firstobj(x_restobj(x_procstate((X))))
 
#define x_procenv(X)   x_restobj(x_restobj(x_procstate((X))))
 
Convenience constructors
#define x_mkproc(B, P, BD, E)   x_make_procedure((B), X_OBJ_FLAG_NONE, (P), (BD), (E))
 
#define x_mkfproc(B, F, P, BD, E)   x_make_procedure((B), (F), (P), (BD), (E))
 
#define x_mkwrap(B, C)   x_make_procedure((B), X_OBJ_FLAG_WRAP, NULL, NULL, (C))
 

Functions

x_obj_tx_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_tx_type_procedure_register (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_procedure_struct (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_procedure_make (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_procedure_call (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_procedure_apply (x_obj_t *p_base, x_obj_t *p_args)
 

Variables

Static primitive atoms for the type struct.
x_satom_t x_type_procedure_name
 
x_satom_t x_type_procedure_make_prim
 
x_satom_t x_type_procedure_call_prim
 
x_satom_t x_type_procedure_struct_prim
 

Detailed Description

Procedure (applicative closure) type for x-lang.

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

A procedure is a two-unit heap object with callable layout:

slot 0 slot 1 (state_list)
+-----------------+ +------------------------------------------+
| fn_ptr | | (params . (body . env)) |
| (x_type_ | | |
| procedure_call)| | params ---- formal parameter tree |
+-----------------+ | body ------ list of body expressions |
| env ------- the captured environment |
+------------------------------------------+
Note
Slot 0 holds a raw C function pointer, NOT a heap object. The GC mark callback (x_type_procedure_mark) must skip slot 0 and only traverse slot 1 (the state list). Marking slot 0 as a heap pointer would corrupt the GC free-list.

When X_OBJ_FLAG_WRAP is set, the procedure is a wrapped applicative: env holds the underlying combiner instead of a closure environment, and call dispatches to that combiner after evaluating args.

See also
x_type_procedure_mark in procedure.c
x_type_procedure_call for the TCO call path
x_type_procedure_apply for the non-TCO apply path

Macro Definition Documentation

◆ x_mkfproc

#define x_mkfproc (   B,
  F,
  P,
  BD,
 
)    x_make_procedure((B), (F), (P), (BD), (E))

Make procedure with flags.

◆ x_mkproc

#define x_mkproc (   B,
  P,
  BD,
 
)    x_make_procedure((B), X_OBJ_FLAG_NONE, (P), (BD), (E))

Make unwrapped procedure.

◆ x_mkwrap

#define x_mkwrap (   B,
 
)    x_make_procedure((B), X_OBJ_FLAG_WRAP, NULL, NULL, (C))

Wrap a combiner as applicative.

◆ X_OBJ_FLAG_WRAP

#define X_OBJ_FLAG_WRAP   X_OBJ_FLAG_1

Flag marking a wrapped applicative combiner.

◆ x_obj_type_isprocedure

#define x_obj_type_isprocedure (   B,
 
)    x_obj_is_type((B), (X), X_TYPE_PROCEDURE_NAME)

Test if object is a procedure.

◆ x_procbody

#define x_procbody (   X)    x_firstobj(x_restobj(x_procstate((X))))

Body expression list.

◆ x_procenv

#define x_procenv (   X)    x_restobj(x_restobj(x_procstate((X))))

Captured environment.

◆ x_procparams

#define x_procparams (   X)    x_firstobj(x_procstate((X)))

Parameter tree.

◆ x_procstate

#define x_procstate (   X)    x_callable_state((X))

Full state list.

◆ X_TYPE_PROCEDURE_NAME

#define X_TYPE_PROCEDURE_NAME   "PROCEDURE"

Type name string.

Function Documentation

◆ x_make_procedure()

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 object on the heap.

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.

Parameters
p_basex_obj_t* – Base (execution context)
flagsx_obj_flag_t – Object flags (e.g. X_OBJ_FLAG_WRAP)
p_paramsx_obj_t* – Formal parameter tree
p_bodyx_obj_t* – Body expression list
p_envx_obj_t* – Captured lexical environment
Returns
Heap-allocated procedure object
Note
Constructor direction is DELIBERATELY the reverse of the simple atom/int/ptr types (#248) – see x_make_operative. A procedure carries four fields and this is the hot path (x_mkproc, called on every fn form via closure.c), so it builds the state tree directly; x_type_procedure_make – the rare generic handler – adapts an arg list to it.

◆ x_type_procedure_apply()

x_obj_t * x_type_procedure_apply ( x_obj_t p_base,
x_obj_t p_args 
)

Non-TCO apply path for (apply f args).

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.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (procedure . evaluated-args)
Returns
Result of the procedure body
See also
x_type_procedure_call for the TCO path

◆ x_type_procedure_call()

x_obj_t * x_type_procedure_call ( x_obj_t p_base,
x_obj_t p_args 
)

Type-dispatch call callback – evaluate a procedure application.

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.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (procedure . unevaluated-args)
Returns
Result of the procedure body
See also
x_type_procedure_apply for the non-TCO path

◆ x_type_procedure_make()

x_obj_t * x_type_procedure_make ( x_obj_t p_base,
x_obj_t p_args 
)

Type-dispatch make callback for PROCEDURE.

Type-dispatch make callback: construct a procedure from x-lang args.

Expects args: (params body env [flags]).

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – Construction arguments
Returns
New procedure object

◆ x_type_procedure_register()

x_obj_t * x_type_procedure_register ( x_obj_t p_base,
x_obj_t p_args 
)

Register (or retrieve) the PROCEDURE type struct on p_base.

Register (or retrieve) the PROCEDURE type struct on p_base.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – Unused
Returns
The registered type struct object

◆ x_type_procedure_struct()

x_obj_t * x_type_procedure_struct ( x_obj_t p_base,
x_obj_t p_args 
)

Build the PROCEDURE type struct descriptor.

Variable Documentation

◆ x_type_procedure_call_prim

x_satom_t x_type_procedure_call_prim

◆ x_type_procedure_make_prim

x_satom_t x_type_procedure_make_prim

◆ x_type_procedure_name

x_satom_t x_type_procedure_name
extern

◆ x_type_procedure_struct_prim

x_satom_t x_type_procedure_struct_prim