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

Type system field accessors and type struct definition. More...

#include "x-eval.h"

Go to the source code of this file.

Data Structures

struct  x_type_t
 C-side mirror of a type descriptor's fields. More...
 

Macros

#define X_TYPE_NO_CVT_TEXT   "no declared promotion; declare the cvt relation for"
 
#define x_type_arg_type(X)   x_firstobj((X))
 
Type Construction
#define x_mktype(B, T, X)   x_obj_make((B), (T), 0, 1, (X))
 
#define x_type_types(B)   (x_firstobj((B)))
 
#define x_type_settypes(B, X)   (x_type_types((B)) = (X))
 
Name and Data Fields
#define x_type_field_name_stack(X)   x_firstobj(X)
 
#define x_type_field_name(X)   x_firstobj(x_type_field_name_stack((X)))
 
#define x_type_field_data_stack(X)   x_firstobj(x_restobj(X))
 
#define x_type_field_data(X)   x_firstobj(x_type_field_data_stack((X)))
 
Heap Group – Memory Management Handlers

(mark make free clone units length)

#define x_type_field_heap(X)   x_firstobj(x_restobj(x_restobj(X)))
 
#define x_type_field_mark_stack(X)   x_firstobj(x_type_field_heap((X)))
 
#define x_type_field_mark(X)   x_firstobj(x_type_field_mark_stack((X)))
 
#define x_type_field_make_stack(X)   x_firstobj(x_restobj(x_type_field_heap((X))))
 
#define x_type_field_make(X)   x_firstobj(x_type_field_make_stack((X)))
 
#define x_type_field_free_stack(X)   x_firstobj(x_restobj(x_restobj(x_type_field_heap((X)))))
 
#define x_type_field_free(X)   x_firstobj(x_type_field_free_stack((X)))
 
#define x_type_field_clone_stack(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_type_field_heap((X))))))
 
#define x_type_field_clone(X)   x_firstobj(x_type_field_clone_stack((X)))
 
#define x_type_field_units_stack(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_type_field_heap((X)))))))
 
#define x_type_field_units(X)   x_firstobj(x_type_field_units_stack((X)))
 
#define x_type_field_length_stack(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_type_field_heap((X))))))))
 
#define x_type_field_length(X)   x_firstobj(x_type_field_length_stack((X)))
 
Proc Group – Call and Eval Handlers

(call eval)

#define x_type_field_proc(X)   x_firstobj(x_restobj(x_restobj(x_restobj(X))))
 
#define x_type_field_call_stack(X)   x_firstobj(x_type_field_proc((X)))
 
#define x_type_field_call(X)   x_firstobj(x_type_field_call_stack((X)))
 
#define x_type_field_eval_stack(X)   x_firstobj(x_restobj(x_type_field_proc((X))))
 
#define x_type_field_eval(X)   x_firstobj(x_type_field_eval_stack((X)))
 
Cvt Group – Conversion Handlers

(from to)

#define x_type_field_cvt(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(X)))))
 
#define x_type_field_from_stack(X)   x_firstobj(x_type_field_cvt((X)))
 
#define x_type_field_from(X)   x_firstobj(x_type_field_from_stack((X)))
 
#define x_type_field_to_stack(X)   x_firstobj(x_restobj(x_type_field_cvt((X))))
 
#define x_type_field_to(X)   x_firstobj(x_type_field_to_stack((X)))
 
I/O Group – Read, Write, and Display Handlers

(analyse delimit read write display)

#define x_type_field_io(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(X))))))
 
#define x_type_field_analyse_stack(X)   x_firstobj(x_type_field_io((X)))
 
#define x_type_field_analyse(X)   x_firstobj(x_type_field_analyse_stack((X)))
 
#define x_type_field_delimit_stack(X)   x_firstobj(x_restobj(x_type_field_io((X))))
 
#define x_type_field_delimit(X)   x_firstobj(x_type_field_delimit_stack((X)))
 
#define x_type_field_read_stack(X)   x_firstobj(x_restobj(x_restobj(x_type_field_io((X)))))
 
#define x_type_field_read(X)   x_firstobj(x_type_field_read_stack((X)))
 
#define x_type_field_write_stack(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_type_field_io((X))))))
 
#define x_type_field_write(X)   x_firstobj(x_type_field_write_stack((X)))
 
#define x_type_field_display_stack(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_type_field_io((X)))))))
 
#define x_type_field_display(X)   x_firstobj(x_type_field_display_stack((X)))
 
Iter Group – Iterator Handler

(iter)

#define x_type_field_iter_group(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(X)))))))
 
#define x_type_field_iter_stack(X)   x_firstobj(x_type_field_iter_group((X)))
 
#define x_type_field_iter(X)   x_firstobj(x_type_field_iter_stack((X)))
 
Ops Group – Generic-Operator Dispatch

(ops) – the per-type generic-operator alist. A typed operand dispatches + - * / % = < to its type's registered handler; a type with a nil ops alist never dispatches (ints keep the pure-C fast path).

#define x_type_field_ops_group(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(X))))))))
 
#define x_type_field_ops_stack(X)   x_firstobj(x_type_field_ops_group((X)))
 
#define x_type_field_ops(X)   x_firstobj(x_type_field_ops_stack((X)))
 
Image group: '(save-stack load-stack) – docs/state-image-format.md
#define x_type_field_image_group(X)   x_firstobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(x_restobj(X)))))))))
 
#define x_type_field_save_stack(X)   x_firstobj(x_type_field_image_group((X)))
 
#define x_type_field_save(X)   x_firstobj(x_type_field_save_stack((X)))
 
#define x_type_field_load_stack(X)   x_firstobj(x_restobj(x_type_field_image_group((X))))
 
#define x_type_field_load(X)   x_firstobj(x_type_field_load_stack((X)))
 
Unit Kinds

A type's p_units slot says how many units an instance has and, in its pair form, what each unit is. The kind decides who may touch the unit: only X_TYPE_UNIT_REF holds a heap object pointer, so only X_TYPE_UNIT_REF may be handed to x_heap_tree_mark() – which sets a mark bit through the pointer before it can establish that the pointer is a heap object, so a traced X_TYPE_UNIT_BYTES would corrupt the bytes it names.

The mask packs X_TYPE_UNIT_BITS bits per unit, unit 0 lowest. Units past the described prefix take the kind of the last described unit, which is what gives a dynamic-size type its payload kind without a repeat marker: a count of -1 with mask (ref, ref) traces slot 0 and slot-0-many payload units after it.

X_TYPE_UNIT_WORD MEANS A RAW MACHINE VALUE, NOT A SMALL ONE. The slot-0-counted convention keeps its length in slot 0 as a heap INTEGER OBJECT, so (word, ref) is wrong for it: the collector would skip slot 0 and free the length under the instance, leaving the slot dangling rather than nil. X_TYPE_UNIT_WORD is for a unit that holds a machine value the collector must not follow – what the atom types carry, an int or a character code. Ask what the unit HOLDS, not how big it looks.

X_TYPE_UNIT_REF is 0, so a zero mask means "every unit a reference" – the bare-count form's meaning, unchanged.

#define X_TYPE_UNIT_REF   0
 
#define X_TYPE_UNIT_WORD   1
 
#define X_TYPE_UNIT_BYTES   2
 
#define X_TYPE_UNIT_FOREIGN   3
 
#define X_TYPE_UNIT_BITS   2
 
#define X_TYPE_UNIT_KIND_MASK   3
 
#define X_TYPE_UNIT_DESCRIBED_MAX    ((x_int_t)(sizeof(x_int_t) * 8 / X_TYPE_UNIT_BITS))
 

Functions

x_int_t x_type_units_count (x_obj_t *p_units)
 
x_int_t x_type_units_mask (x_obj_t *p_units)
 
x_int_t x_type_units_described (x_obj_t *p_units)
 
int x_type_unit_kind (x_int_t mask, x_int_t i, x_int_t described)
 
x_obj_tx_type_prim_length (x_obj_t *p_base, x_obj_t *p_args)
 
Type Heap Callbacks
x_obj_tx_type_heap_mark (x_obj_t *p_base, x_obj_t *p_obj, x_obj_flag_t flags)
 
void x_type_heap_free (x_obj_t *p_base, x_obj_t *p_obj)
 

Type Functions

x_satom_t x_type_save_default_prim
 
x_obj_tx_type_struct_make (x_obj_t *p_base, struct x_type_t type)
 
x_obj_tx_type_save_default (x_obj_t *p_base, x_obj_t *p_args)
 The default save: the units the type's shape declares, each with the kind the shape's mask gives it (a bare count: all references). Args are already evaluated: (obj buf).
 
x_obj_tx_type_save_units (x_obj_t *p_obj, x_int_t *buf, x_int_t n, const int *kinds, int nkinds)
 
int x_type_op_try (x_obj_t *p_base, x_char_t *op, x_obj_t *p_a, x_obj_t *p_b, x_obj_t **pp_result)
 
x_obj_tx_type_struct_get (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_prim_type_name (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_type_prim_units (x_obj_t *p_base, x_obj_t *p_args)
 

Detailed Description

Type system field accessors and type struct definition.

Defines the x_type_t struct that mirrors the pair-tree layout of a type descriptor, along with macros to navigate each field group (name, data, heap, proc, cvt, io, iter). Each field has a _stack variant returning the full (current . saved) cell, and a bare variant returning the current value.

Type descriptor pair-tree layout (all leaf fields are stack-wrapped):

'(
name [S] type name symbol
data [S] arbitrary type-specific data
(mark [S] GC mark callback
make [S] constructor
free [S] destructor
clone [S] clone callback
units [S] element count (for GC traversal)
length) [S] length callback
(call [S] call handler (for callable types)
eval) [S] eval handler (for self-evaluating types)
(from [S] inbound conversion alist
to) [S] outbound conversion alist
(analyse [S] tokenizer scoring callback
delimit [S] delimiter predicate
read [S] reader (token -> object)
write [S] writer (s-expression output)
display) [S] display (human-readable output)
(iter) [S] iterator constructor
(ops) [S] generic-operator alist ((op-sym . handler) ...)
)

Every field is stack-wrapped: stored as (current . saved). The _stack macros return the cell, the bare macros return x_firstobj(cell) (the current value). Stack-wrapping enables type-push-write / type-pop-write to temporarily override handlers (e.g. for write-to-str capture).

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

Macro Definition Documentation

◆ x_mktype

#define x_mktype (   B,
  T,
 
)    x_obj_make((B), (T), 0, 1, (X))

Allocate a new type object with the given payload.

◆ x_type_arg_type

#define x_type_arg_type (   X)    x_firstobj((X))

Extract the type object from a type-dispatch argument list.

◆ X_TYPE_NO_CVT_TEXT

#define X_TYPE_NO_CVT_TEXT   "no declared promotion; declare the cvt relation for"

The op-arbitration refusal (#584); x_eval_error appends the type name.

◆ x_type_settypes

#define x_type_settypes (   B,
 
)    (x_type_types((B)) = (X))

Set the type alist on a base object.

◆ x_type_types

#define x_type_types (   B)    (x_firstobj((B)))

Get the type alist from a base object.

◆ X_TYPE_UNIT_BITS

#define X_TYPE_UNIT_BITS   2

Mask bits per unit.

◆ X_TYPE_UNIT_BYTES

#define X_TYPE_UNIT_BYTES   2

A pointer to bytes the type can measure.

◆ X_TYPE_UNIT_DESCRIBED_MAX

#define X_TYPE_UNIT_DESCRIBED_MAX    ((x_int_t)(sizeof(x_int_t) * 8 / X_TYPE_UNIT_BITS))

Units a mask can describe before the repeat rule takes over.

◆ X_TYPE_UNIT_FOREIGN

#define X_TYPE_UNIT_FOREIGN   3

An address C owns.

◆ X_TYPE_UNIT_KIND_MASK

#define X_TYPE_UNIT_KIND_MASK   3

Low-bit mask of one kind field.

◆ X_TYPE_UNIT_REF

#define X_TYPE_UNIT_REF   0

A heap object pointer; the GC traces it.

◆ X_TYPE_UNIT_WORD

#define X_TYPE_UNIT_WORD   1

An immediate; nothing dereferences it.

Function Documentation

◆ x_type_heap_free()

void x_type_heap_free ( x_obj_t p_base,
x_obj_t p_obj 
)

GC free callback – free a typed object's resources.

GC free hook for typed heap objects.

If the object's type has a free callback, invokes it to release type-specific resources before the heap cell is reclaimed.

Parameters
p_basex_obj_t* – Base (execution context)
p_objx_obj_t* – Object being freed

◆ x_type_heap_mark()

x_obj_t * x_type_heap_mark ( x_obj_t p_base,
x_obj_t p_obj,
x_obj_flag_t  flags 
)

GC mark callback – mark a typed object and its contents.

GC mark hook for typed heap objects.

For child base objects (type == x_eval_obj), returns the data pointer so the GC traverses the base's pair tree. For custom types, calls the type's mark callback if present. Otherwise falls back to a generic N-slot traversal using the units count.

Parameters
p_basex_obj_t* – Base (execution context)
p_objx_obj_t* – Object being marked
flagsx_obj_flag_t – GC mark flags
Returns
x_obj_t* – Data pointer for base objects, or NULL

◆ x_type_op_try()

int x_type_op_try ( x_obj_t p_base,
x_char_t op,
x_obj_t p_a,
x_obj_t p_b,
x_obj_t **  pp_result 
)

Try generic-operator dispatch for a binary op; 1 if dispatched.

◆ x_type_prim_length()

x_obj_t * x_type_prim_length ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: return the length of an object.

Return the length for an object. x-lang: (length obj)

Dispatches to pair or atom length primitives for built-in types. For custom types, calls the type's length hook function.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (object)
Returns
x_obj_t* – Integer length, or NULL

◆ x_type_prim_type_name()

x_obj_t * x_type_prim_type_name ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: return the name of an object's type.

Return the type name for an object. x-lang: (type-name obj)

For stack atoms/pairs and untyped objects, returns the raw type pointer. For heap-typed objects, extracts the name from the type struct.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (object)
Returns
x_obj_t* – Type name object, or NULL

◆ x_type_prim_units()

x_obj_t * x_type_prim_units ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: return the units (element size) of an object.

Return the unit count for an object. x-lang: (units obj)

Dispatches to pair or atom unit primitives for built-in types. For custom types, reads the type's units count.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (object)
Returns
x_obj_t* – Integer unit count, or NULL

◆ x_type_save_default()

x_obj_t * x_type_save_default ( x_obj_t p_base,
x_obj_t p_args 
)

The default save: the units the type's shape declares, each with the kind the shape's mask gives it (a bare count: all references). Args are already evaluated: (obj buf).

The default save handler: every unit the type's units shape declares.

◆ x_type_save_units()

x_obj_t * x_type_save_units ( x_obj_t p_obj,
x_int_t buf,
x_int_t  n,
const int *  kinds,
int  nkinds 
)

Write n at buf[0] and the units of p_obj as [kind][word] pairs after it, kinds from kinds (the last repeats); every C save handler's helper. Returns p_obj.

◆ x_type_struct_get()

x_obj_t * x_type_struct_get ( x_obj_t p_base,
x_obj_t p_args 
)

Look up a type struct from a type-dispatch argument list.

Retrieve or create a type struct by name.

First checks the type alist cache. On miss, calls the callable in rest of p_args to construct the type, then caches it in the type alist for future lookups.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – (type-name . constructor-callable)
Returns
x_obj_t* – Type struct

◆ x_type_struct_make()

x_obj_t * x_type_struct_make ( x_obj_t p_base,
struct x_type_t  type 
)

Build a type pair tree from a C x_type_t struct.

Construct a type struct from a type descriptor.

Builds the canonical nested-pair structure that represents a type in the type alist: name-stack, data-stack, heap group (mark, make, free, clone, units, length), proc group (call, eval), cvt group (from, to), IO group (analyse, delimit, read, write, display, error), iter group, and ops group.

Parameters
p_basex_obj_t* – Base (execution context) (for allocation)
typestruct x_type_t – Type descriptor with all hook pointers
Returns
x_obj_t* – Newly allocated type struct (pair tree)

◆ x_type_unit_kind()

int x_type_unit_kind ( x_int_t  mask,
x_int_t  i,
x_int_t  described 
)

The kind of unit i, applying the repeat rule past described.

The kind of unit i.

Units at or past described take the kind of the last described unit. That is the repeat rule, and it is how a dynamic-size type says what its payload units are without a marker.

Parameters
maskx_int_t – The kind mask
ix_int_t – Unit index
describedx_int_t – Fields the mask describes
Returns
int – One of X_TYPE_UNIT_REF .. X_TYPE_UNIT_FOREIGN

◆ x_type_units_count()

x_int_t x_type_units_count ( x_obj_t p_units)

The declared unit count from either form of a p_units slot.

The declared unit count, from either form of a p_units slot.

A bare INT atom is the count itself; a pair is (count . mask) and the count is its first. Negative keeps its dynamic-size meaning in both.

Parameters
p_unitsx_obj_t* – A type's p_units slot, or NULL
Returns
x_int_t – The count, or 0 when the slot is unset

◆ x_type_units_described()

x_int_t x_type_units_described ( x_obj_t p_units)

How many leading units a p_units slot's mask describes.

How many leading units the mask describes before the repeat rule applies.

A fixed count describes exactly its own units. A dynamic count of -k describes the k leading units plus the kind of the payload that follows them – k + 1 fields – so a count of -1 with mask (ref, ref) covers slot 0 and the slot-0-many payload units after it, with no repeat marker.

Note that the slot-0-counted convention holds its length as a heap INTEGER OBJECT, so slot 0 is X_TYPE_UNIT_REF, not X_TYPE_UNIT_WORD – see the kind documentation in x-type.h.

Parameters
p_unitsx_obj_t* – A type's p_units slot, or NULL
Returns
x_int_t – Described field count, capped at the mask's capacity

◆ x_type_units_mask()

x_int_t x_type_units_mask ( x_obj_t p_units)

The kind mask from either form of a p_units slot (0 = all references).

The per-unit kind mask, from either form of a p_units slot.

The bare-count form has no mask; 0 is the honest answer for it, since X_TYPE_UNIT_REF is 0 and "every unit a reference" is what a bare count has always meant.

Parameters
p_unitsx_obj_t* – A type's p_units slot, or NULL
Returns
x_int_t – The mask, or 0

Variable Documentation

◆ x_type_save_default_prim

x_satom_t x_type_save_default_prim
extern