x-engine-c v0.2.31
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 Fields – 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 Fields – 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 Fields – 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 Fields – 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 Fields – Iterator Handler

(iter)

#define x_type_field_iter_fields(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_fields((X)))
 
#define x_type_field_iter(X)   x_firstobj(x_type_field_iter_stack((X)))
 
Ops Fields – 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_fields(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_fields((X)))
 
#define x_type_field_ops(X)   x_firstobj(x_type_field_ops_stack((X)))
 
Image fields: '(save-stack load-stack) – docs/state-image-format.md
#define x_type_field_image_fields(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_fields((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_fields((X))))
 
#define x_type_field_load(X)   x_firstobj(x_type_field_load_stack((X)))
 
Unit Labels

A type's p_units slot says how many units an instance has and, in its pair form, what each unit is. The label 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 label of the last described unit, which is what gives a dynamic-size type its payload label 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_LABEL_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_label (x_int_t mask, x_int_t i, x_int_t described)
 
x_obj_t * x_type_prim_length (x_obj_t *p_base, x_obj_t *p_args)
 
Type Heap Callbacks
x_obj_t * x_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_t * x_type_struct_make (x_obj_t *p_base, struct x_type_t type)
 
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 unit labels declare, each with the label the mask gives it (a bare count: all references). Args are already evaluated: (obj buf).
 
x_obj_t * x_type_save_units (x_obj_t *p_obj, x_int_t *buf, x_int_t n, const int *labels, int nlabels)
 
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_t * x_type_struct_get (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_type_prim_type_name (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_t * x_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 (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 
)    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 
)    (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_LABEL_MASK

#define X_TYPE_UNIT_LABEL_MASK   3

Low-bit mask of one label 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_argsx_obj_t* – Argument run: (object) – the object being freed
Returns
x_obj_t* – NULL

◆ 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, a primitive or a closure, with the object and the flags. Otherwise falls back to a generic N-slot traversal using the units count, which marks every reference unit but the last and returns that one for the caller's loop to take, so a list's rest is followed without a C frame per pair.

Parameters
p_basex_obj_t* – Base (execution context)
p_argsx_obj_t* – Argument run: (object, flags) – the object being marked, and the GC mark flags
Returns
x_obj_t* – Data pointer for base objects, the last reference unit of a generically traversed one, 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* – Argument run: (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* – Argument run: (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* – Argument run: (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 unit labels declare, each with the label the mask gives it (a bare count: all references). Args are already evaluated: (obj buf).

The default save handler: every unit the type's unit labels declare.

◆ 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 *  labels,
int  nlabels 
)

Write n at buf[0] and the units of p_obj as [label][word] pairs after it, labels from labels (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 fields (mark, make, free, clone, units, length), proc fields (call, eval), cvt fields (from, to), IO fields (analyse, delimit, read, write, display, error), iter fields, and ops fields.

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_label()

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

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

The label of unit i.

Units at or past described take the label 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 label 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 label 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 label 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 label mask from either form of a p_units slot (0 = all references).

The per-unit label 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