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

The x-expr object system – atoms, pairs, flags, and type dispatch. More...

#include "x-lib.h"

Go to the source code of this file.

Data Structures

union  x_datum_union
 

Macros

#define x_0(X)   x_firstobj(X)
 
#define x_1(X)   x_restobj(X)
 
#define x_00(X)   x_0(x_0(X))
 
#define x_01(X)   x_0(x_1(X))
 
#define x_10(X)   x_1(x_0(X))
 
#define x_11(X)   x_1(x_1(X))
 
#define x_000(X)   x_0(x_00(X))
 
#define x_001(X)   x_0(x_01(X))
 
#define x_010(X)   x_0(x_10(X))
 
#define x_011(X)   x_0(x_11(X))
 
#define x_100(X)   x_1(x_00(X))
 
#define x_101(X)   x_1(x_01(X))
 
#define x_110(X)   x_1(x_10(X))
 
#define x_111(X)   x_1(x_11(X))
 
#define x_0000(X)   x_0(x_000(X))
 
#define x_0001(X)   x_0(x_001(X))
 
#define x_0010(X)   x_0(x_010(X))
 
#define x_0011(X)   x_0(x_011(X))
 
#define x_0100(X)   x_0(x_100(X))
 
#define x_0101(X)   x_0(x_101(X))
 
#define x_0110(X)   x_0(x_110(X))
 
#define x_0111(X)   x_0(x_111(X))
 
#define x_1000(X)   x_1(x_000(X))
 
#define x_1001(X)   x_1(x_001(X))
 
#define x_1010(X)   x_1(x_010(X))
 
#define x_1011(X)   x_1(x_011(X))
 
#define x_1100(X)   x_1(x_100(X))
 
#define x_1101(X)   x_1(x_101(X))
 
#define x_1110(X)   x_1(x_110(X))
 
#define x_1111(X)   x_1(x_111(X))
 
Type Names and Literal Text

All of these are plain C strings; x-expr has no interned-symbol type (that concept lives in the embedding layer), so nothing here is a "symbol".

#define X_TYPE_NIL_NAME   "NIL"
 
#define X_TYPE_ATOM_NAME   "ATOM"
 
#define X_TYPE_PAIR_NAME   "PAIR"
 
#define X_OBJ_TRUE_TEXT   "#t"
 
#define X_OBJ_FALSE_TEXT   "#f"
 
Metadata Accessors

Read or assign an object's metadata slots and locate its data.

Each macro is an lvalue, so it may appear on either side of an assignment.

#define x_obj_type(X)   ((X)[X_OBJ_META_TYPE].p)
 
#define x_obj_flags(X)   ((X)[X_OBJ_META_FLAGS].i)
 
#define x_obj_data_ptr(X)   ((X) + X_OBJ_META_LEN)
 
#define x_obj_data_i(X, I)   (x_obj_data_ptr((X))[(I)])
 
#define x_obj_data(X)   x_obj_data_i((X), 0)
 
#define x_obj_meta_i(X, I)   ((X)[-((I) + 1)])
 
#define x_obj_set(T, F, ...)   { { .p = (T) }, { .i = (F) }, __VA_ARGS__ }
 
Type Predicates and Constructors

The s in issatom/isspair and x_mks* is the built-in static type sense (see the note at x_satom_t): the predicates match x_type_atom_obj / x_type_pair_obj by pointer identity, and the constructors heap-allocate objects carrying those types – s says nothing about where the object is stored.

#define x_obj_type_isnil(B, X)   x_obj_isnil((B), x_obj_type(X))
 
#define x_obj_is_type(B, X, T)   (x_lib_strcmp(x_obj_type_name((B), (X)), (T)) == 0)
 
#define x_obj_type_issatom(X)   (x_obj_type((X)) == x_type_atom_obj)
 
#define x_obj_type_isspair(X)   (x_obj_type((X)) == x_type_pair_obj)
 
#define x_mksatom(B, F, X)   x_obj_make((B), x_type_atom_obj, (F), X_OBJ_LENGTH_ATOM, (X))
 
#define x_mksatomown(B, F, X)   x_obj_make((B), x_type_atom_obj, (F) | X_OBJ_FLAG_OWN, X_OBJ_LENGTH_ATOM, (X))
 
#define x_mkspair(B, F, X, Y)   x_obj_make((B), x_type_pair_obj, (F), X_OBJ_LENGTH_PAIR, (X), (Y))
 
Datum Member Accessors

Reinterpret a single datum through the chosen union member.

Each is an lvalue selecting one member of an x_datum_union.

#define x_obj(X)   ((X).p)
 
#define x_fn(X)   ((X).fn)
 
#define x_int(X)   ((X).i)
 
#define x_char(X)   ((X).c)
 
#define x_str(X)   ((X).s)
 
#define x_ptr(X)   ((X).v)
 
Data Unit Accessors

Read an object's data units, optionally typed.

The prefix selects the unit – first/atom are data unit 0, while second/rest are data unit 1 – and the suffix selects the union member (ptr, obj, int, char, str, fn). The atom* names are aliases of the first* names (an atom's single value); the rest* names are aliases of the second* names.

#define x_first(X)   x_obj_data_i((X),0)
 
#define x_second(X)   x_obj_data_i((X),1)
 
#define x_rest(X)   x_second((X))
 
#define x_firstptr(X)   x_ptr(x_first((X)))
 
#define x_firstobj(X)   x_obj(x_first((X)))
 
#define x_firstint(X)   x_int(x_first((X)))
 
#define x_firstchar(X)   x_char(x_first((X)))
 
#define x_firststr(X)   x_str(x_first((X)))
 
#define x_firstfn(X)   x_fn(x_first((X)))
 
#define x_secondptr(X)   x_ptr(x_rest((X)))
 
#define x_secondobj(X)   x_obj(x_rest((X)))
 
#define x_secondint(X)   x_int(x_rest((X)))
 
#define x_secondchar(X)   x_char(x_rest((X)))
 
#define x_secondstr(X)   x_str(x_rest((X)))
 
#define x_secondfn(X)   x_fn(x_rest((X)))
 
#define x_atomptr(X)   x_firstptr((X))
 
#define x_atomobj(X)   x_firstobj((X))
 
#define x_atomint(X)   x_firstint((X))
 
#define x_atomchar(X)   x_firstchar((X))
 
#define x_atomstr(X)   x_firststr((X))
 
#define x_atomfn(X)   x_firstfn((X))
 
#define x_restptr(X)   x_secondptr((X))
 
#define x_restobj(X)   x_secondobj((X))
 
#define x_restint(X)   x_secondint((X))
 
#define x_restchar(X)   x_secondchar((X))
 
#define x_reststr(X)   x_secondstr((X))
 
#define x_restfn(X)   x_secondfn((X))
 
Debug Utilities

Formatted debug output and object dumping (compiled only with DEBUG).

#define x_obj_debug_va(p_base, fmt, ap)   ;
 
#define x_obj_debug(p_base, fmt, ...)   ;
 
#define x_obj_dump(p_base, p_obj, msg)   ;
 

Typedefs

typedef enum x_obj_flag_enum x_obj_flag_t
 
typedef union x_datum_union x_obj_t
 
typedef x_obj_t *(* x_fn_t) (x_obj_t *p_base, x_obj_t *p_args)
 

Enumerations

enum  x_obj_flag_enum {
  X_OBJ_FLAG_NONE =0x0 , X_OBJ_FLAG_OBJ =0x0 , X_OBJ_FLAG_1 =0x1 , X_OBJ_FLAG_2 =0x2 ,
  X_OBJ_FLAG_3 =0x4 , X_OBJ_FLAG_4 =0x8 , X_OBJ_FLAG_ATTR_MASK =0xF , X_OBJ_FLAG_SIMPLE_TYPE =0x10 ,
  X_OBJ_FLAG_PRIM =0x10 , X_OBJ_FLAG_FN , X_OBJ_FLAG_INT , X_OBJ_FLAG_CHAR ,
  X_OBJ_FLAG_STR , X_OBJ_FLAG_PTR , X_OBJ_FLAG_TYPE_MASK =0xF0 , X_OBJ_FLAG_OWN =0x20 ,
  X_OBJ_FLAG_RO =0x40 , X_OBJ_FLAG_META =0x80 , X_OBJ_FLAG_MASK =0xFF
}
 

Functions

Object Functions
Warning
x-expr is not thread-safe. All functions that allocate objects, mutate the heap chain, or modify field stacks assume single-threaded execution. External synchronization is required for multi-threaded use.
int x_obj_isnil (x_obj_t *p_base, x_obj_t *p_obj)
 
x_obj_tx_obj_alloc (x_obj_t *p_base, x_obj_t *p_type, x_obj_flag_t flags, size_t units)
 
x_obj_tx_obj_make_va (x_obj_t *p_base, x_obj_t *p_type, x_obj_flag_t flags, size_t units, va_list ap)
 
x_obj_tx_obj_make (x_obj_t *p_base, x_obj_t *p_type, x_obj_flag_t flags, size_t units,...)
 
void x_obj_free (x_obj_t *p_base, x_obj_t *p_obj)
 
x_obj_tx_obj_prim_type_name (x_obj_t *p_base, x_obj_t *p_args)
 
x_char_tx_obj_type_name (x_obj_t *p_base, x_obj_t *p_obj)
 
x_obj_tx_atom_prim_units (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_pair_prim_units (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_obj_prim_units (x_obj_t *p_base, x_obj_t *p_args)
 
x_int_t x_obj_units (x_obj_t *p_base, x_obj_t *p_obj)
 
x_obj_tx_atom_prim_length (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_pair_prim_length (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_obj_prim_length (x_obj_t *p_base, x_obj_t *p_args)
 
x_int_t x_obj_length (x_obj_t *p_base, x_obj_t *p_obj)
 
x_obj_tx_obj_push_field (x_obj_t *p_base, x_obj_t **p_field, x_obj_t *p_value, x_obj_flag_t flags)
 
x_obj_tx_obj_pop_field (x_obj_t *p_base, x_obj_t **p_field)
 
x_obj_tx_obj_push (x_obj_t *p_base, x_obj_t *p_args)
 
x_obj_tx_obj_pop (x_obj_t *p_base, x_obj_t *p_args)
 
void x_obj_error (x_obj_t *p_base, x_char_t *message, x_obj_t *p_obj)
 

Object Layout

Metadata sizing and the offsets of an object's data units.

#define X_OBJ_UNITS_HEAP   0
 
#define X_OBJ_UNITS_TYPE   1
 
#define X_OBJ_UNITS_FLAGS   1
 
#define X_OBJ_UNITS_META   X_OBJ_META_LEN
 
#define X_OBJ_UNITS_ATOM   1
 
#define X_OBJ_UNITS_PAIR   2
 
#define X_OBJ_LENGTH_ATOM   X_OBJ_UNITS_ATOM
 
#define X_OBJ_LENGTH_PAIR   X_OBJ_UNITS_PAIR
 
enum  { X_OBJ_META_TYPE = X_OBJ_UNITS_HEAP , X_OBJ_META_FLAGS = (X_OBJ_UNITS_HEAP + X_OBJ_UNITS_TYPE) , X_OBJ_META_LEN = (X_OBJ_UNITS_HEAP + X_OBJ_UNITS_TYPE + X_OBJ_UNITS_FLAGS) }
 
typedef x_obj_t x_satom_t[X_OBJ_META_LEN+X_OBJ_UNITS_ATOM]
 
typedef x_obj_t x_spair_t[X_OBJ_META_LEN+X_OBJ_UNITS_PAIR]
 
x_satom_t x_type_atom_obj
 
x_satom_t x_type_pair_obj
 
x_satom_t x_type_units_atom_obj
 
x_satom_t x_type_units_pair_obj
 
x_satom_t x_type_length_atom_obj
 
x_satom_t x_type_length_pair_obj
 
x_satom_t x_true_obj
 
x_satom_t x_false_obj
 

Detailed Description

The x-expr object system – atoms, pairs, flags, and type dispatch.

Defines the universal object representation used throughout x-expr along with the macros and functions for creating, inspecting, and traversing objects.

Every value is an object: a contiguous array of x_obj_t units (a tagged-union datum, see x_datum_union) laid out as a small metadata header followed by one or more data units. A pointer to an object addresses the start of its metadata; the data units begin at offset X_OBJ_META_LEN, reached via the accessor macros x_obj_type(), x_obj_flags() and x_obj_data_ptr().

There are two fundamental shapes:

  • atom – one data unit (X_OBJ_UNITS_ATOM): a single datum such as an integer, character, string, pointer, or function pointer.
  • pair – two data units (X_OBJ_UNITS_PAIR): a first and a rest. Pairs are the building block for lists and trees.

nil is represented by a NULL object pointer (see x_obj_isnil()).

+---------+ +---------+
| heap | (X_HEAP only) | heap | (X_HEAP only)
| type | | type |
| flags | | flags |
+---------+ <- data start +---------+ <- data start
| datum | first | first |
+---------+ | rest |
+---------+
#define atom(X)
Definition x-eval.c:664
#define pair(X, Y)
Definition x-eval.c:663

When the base configures extra metadata units (see x_base_field_obj_meta_extra()), x_obj_alloc() prepends them before the standard header and advances the object pointer past them, so the layout above still holds; the extras sit at negative offsets reached via x_obj_meta_i() and the object is flagged X_OBJ_FLAG_META.

Type system. An object carries type information two ways:

  1. The type metadata slot (x_obj_type()) points at a type object whose atom value is the type-name string. The built-in static types x_type_atom_obj and x_type_pair_obj are matched by pointer identity (x_obj_type_issatom(), x_obj_type_isspair()); for any other type the base environment's hooks are consulted (see x_obj_prim_type_name()).
  2. A lightweight simple type tag may be carried in the type nibble of the object flags (X_OBJ_FLAG_PRIM ... X_OBJ_FLAG_PTR) for consumers that want a cheap datum-kind tag without allocating a type object. The x-expr core does not dispatch on it; it is provided for downstream use.

Primitive vs. wrapper functions. Type-introspection operations come in two forms. The x_*_prim_* functions follow the x_fn_t calling convention – (p_base, p_args) where p_args is a pair whose first element is the subject object – so they can be stored and dispatched as callables (e.g. installed as base hooks). The matching non-prim wrappers (x_obj_type_name(), x_obj_units(), x_obj_length()) take a plain object pointer, build the argument pair, invoke the primitive, and unwrap the result for C callers.

Note
See x-base.h for how an object's type/units/length/error hooks are stored in the base tree, and x-lisp.h for Lisp-style cons/car/cdr aliases over these pair operations.
Author
Jon Ruttan (jonru.nosp@m.ttan.nosp@m.@gmai.nosp@m.l.co.nosp@m.m)

Macro Definition Documentation

◆ x_atomchar

#define x_atomchar (   X)    x_firstchar((X))

Atom value as a character.

◆ x_atomfn

#define x_atomfn (   X)    x_firstfn((X))

Atom value as a function.

◆ x_atomint

#define x_atomint (   X)    x_firstint((X))

Atom value as an integer.

◆ x_atomobj

#define x_atomobj (   X)    x_firstobj((X))

Atom value as an object.

◆ x_atomptr

#define x_atomptr (   X)    x_firstptr((X))

Atom value as a pointer.

◆ x_atomstr

#define x_atomstr (   X)    x_firststr((X))

Atom value as a string.

◆ x_char

#define x_char (   X)    ((X).c)

Datum as a character.

◆ x_first

#define x_first (   X)    x_obj_data_i((X),0)

Data unit 0 (raw datum, lvalue).

◆ x_firstchar

#define x_firstchar (   X)    x_char(x_first((X)))

Data unit 0 as a character.

◆ x_firstfn

#define x_firstfn (   X)    x_fn(x_first((X)))

Data unit 0 as a function.

◆ x_firstint

#define x_firstint (   X)    x_int(x_first((X)))

Data unit 0 as an integer.

◆ x_firstobj

#define x_firstobj (   X)    x_obj(x_first((X)))

Data unit 0 as an object.

◆ x_firstptr

#define x_firstptr (   X)    x_ptr(x_first((X)))

Data unit 0 as a pointer.

◆ x_firststr

#define x_firststr (   X)    x_str(x_first((X)))

Data unit 0 as a string.

◆ x_fn

#define x_fn (   X)    ((X).fn)

Datum as a function pointer.

◆ x_int

#define x_int (   X)    ((X).i)

Datum as an integer.

◆ x_mksatom

#define x_mksatom (   B,
  F,
 
)    x_obj_make((B), x_type_atom_obj, (F), X_OBJ_LENGTH_ATOM, (X))

Heap-allocate an atom of the built-in atom type with flags F holding datum X.

◆ x_mksatomown

#define x_mksatomown (   B,
  F,
 
)    x_obj_make((B), x_type_atom_obj, (F) | X_OBJ_FLAG_OWN, X_OBJ_LENGTH_ATOM, (X))

Heap-allocate an atom of the built-in atom type that owns its datum X (adds X_OBJ_FLAG_OWN).

◆ x_mkspair

#define x_mkspair (   B,
  F,
  X,
 
)    x_obj_make((B), x_type_pair_obj, (F), X_OBJ_LENGTH_PAIR, (X), (Y))

Heap-allocate a pair of the built-in pair type with flags F holding first X and rest Y.

◆ x_obj

#define x_obj (   X)    ((X).p)

Datum as an object pointer.

◆ x_obj_data

#define x_obj_data (   X)    x_obj_data_i((X), 0)

The first data unit of object X.

◆ x_obj_data_i

#define x_obj_data_i (   X,
 
)    (x_obj_data_ptr((X))[(I)])

The data unit at index I of object X.

◆ x_obj_data_ptr

#define x_obj_data_ptr (   X)    ((X) + X_OBJ_META_LEN)

Pointer to the first data unit of object X.

◆ x_obj_debug

#define x_obj_debug (   p_base,
  fmt,
  ... 
)    ;

◆ x_obj_debug_va

#define x_obj_debug_va (   p_base,
  fmt,
  ap 
)    ;

◆ x_obj_dump

#define x_obj_dump (   p_base,
  p_obj,
  msg 
)    ;

◆ X_OBJ_FALSE_TEXT

#define X_OBJ_FALSE_TEXT   "#f"

Literal text of the canonical false atom (x_false_obj).

◆ x_obj_flags

#define x_obj_flags (   X)    ((X)[X_OBJ_META_FLAGS].i)

The object's flags slot (an x_obj_flag_t bitfield held as an integer).

◆ x_obj_is_type

#define x_obj_is_type (   B,
  X,
 
)    (x_lib_strcmp(x_obj_type_name((B), (X)), (T)) == 0)

True if the type name of object X equals the C string T.

◆ X_OBJ_LENGTH_ATOM

#define X_OBJ_LENGTH_ATOM   X_OBJ_UNITS_ATOM

Logical length of an atom.

◆ X_OBJ_LENGTH_PAIR

#define X_OBJ_LENGTH_PAIR   X_OBJ_UNITS_PAIR

Logical length of a pair.

◆ x_obj_meta_i

#define x_obj_meta_i (   X,
 
)    ((X)[-((I) + 1)])

The extra metadata unit at index I (negative offset before X).

◆ x_obj_set

#define x_obj_set (   T,
  F,
  ... 
)    { { .p = (T) }, { .i = (F) }, __VA_ARGS__ }

Brace initializer for a static object: type T, flags F, then data.

◆ X_OBJ_TRUE_TEXT

#define X_OBJ_TRUE_TEXT   "#t"

Literal text of the canonical true atom (x_true_obj).

◆ x_obj_type

#define x_obj_type (   X)    ((X)[X_OBJ_META_TYPE].p)

The object's type slot: a pointer to its type object, or NULL (nil).

◆ x_obj_type_isnil

#define x_obj_type_isnil (   B,
 
)    x_obj_isnil((B), x_obj_type(X))

True if object X has a nil (NULL) type slot.

◆ x_obj_type_issatom

#define x_obj_type_issatom (   X)    (x_obj_type((X)) == x_type_atom_obj)

True if X is typed as the built-in atom type (by pointer identity).

◆ x_obj_type_isspair

#define x_obj_type_isspair (   X)    (x_obj_type((X)) == x_type_pair_obj)

True if X is typed as the built-in pair type (by pointer identity).

◆ X_OBJ_UNITS_ATOM

#define X_OBJ_UNITS_ATOM   1

Number of data units in an atom.

◆ X_OBJ_UNITS_FLAGS

#define X_OBJ_UNITS_FLAGS   1

Metadata units consumed by the flags slot.

◆ X_OBJ_UNITS_HEAP

#define X_OBJ_UNITS_HEAP   0

Metadata units consumed by the heap-chain link (1 when X_HEAP, else 0).

◆ X_OBJ_UNITS_META

#define X_OBJ_UNITS_META   X_OBJ_META_LEN

Total number of standard metadata units preceding an object's data.

◆ X_OBJ_UNITS_PAIR

#define X_OBJ_UNITS_PAIR   2

Number of data units in a pair.

◆ X_OBJ_UNITS_TYPE

#define X_OBJ_UNITS_TYPE   1

Metadata units consumed by the type slot.

◆ x_ptr

#define x_ptr (   X)    ((X).v)

Datum as an opaque pointer.

◆ x_rest

#define x_rest (   X)    x_second((X))

Alias for x_second(): data unit 1.

◆ x_restchar

#define x_restchar (   X)    x_secondchar((X))

Rest value as a character.

◆ x_restfn

#define x_restfn (   X)    x_secondfn((X))

Rest value as a function.

◆ x_restint

#define x_restint (   X)    x_secondint((X))

Rest value as an integer.

◆ x_restobj

#define x_restobj (   X)    x_secondobj((X))

Rest value as an object.

◆ x_restptr

#define x_restptr (   X)    x_secondptr((X))

Rest value as a pointer.

◆ x_reststr

#define x_reststr (   X)    x_secondstr((X))

Rest value as a string.

◆ x_second

#define x_second (   X)    x_obj_data_i((X),1)

Data unit 1 (raw datum, lvalue).

◆ x_secondchar

#define x_secondchar (   X)    x_char(x_rest((X)))

Data unit 1 as a character.

◆ x_secondfn

#define x_secondfn (   X)    x_fn(x_rest((X)))

Data unit 1 as a function.

◆ x_secondint

#define x_secondint (   X)    x_int(x_rest((X)))

Data unit 1 as an integer.

◆ x_secondobj

#define x_secondobj (   X)    x_obj(x_rest((X)))

Data unit 1 as an object.

◆ x_secondptr

#define x_secondptr (   X)    x_ptr(x_rest((X)))

Data unit 1 as a pointer.

◆ x_secondstr

#define x_secondstr (   X)    x_str(x_rest((X)))

Data unit 1 as a string.

◆ x_str

#define x_str (   X)    ((X).s)

Datum as a string.

◆ X_TYPE_ATOM_NAME

#define X_TYPE_ATOM_NAME   "ATOM"

Type-name string for the built-in atom type (x_type_atom_obj).

◆ X_TYPE_NIL_NAME

#define X_TYPE_NIL_NAME   "NIL"

Type-name string returned for nil (untyped) objects.

◆ X_TYPE_PAIR_NAME

#define X_TYPE_PAIR_NAME   "PAIR"

Type-name string for the built-in pair type (x_type_pair_obj).

Typedef Documentation

◆ x_fn_t

typedef x_obj_t *(* x_fn_t) (x_obj_t *p_base, x_obj_t *p_args)

Calling convention for x-expr primitive functions.

Parameters
p_baseBase (execution context).
p_argsA pair list of arguments (nil when there are none).
Returns
The result object, or NULL.

◆ x_obj_flag_t

Object flags – a bitfield stored in each object's flags metadata slot.

The low nibble (X_OBJ_FLAG_ATTR_MASK) holds general-purpose attribute bits. The high nibble (X_OBJ_FLAG_TYPE_MASK) encodes an optional "simple type" tag. The remaining bits are storage- and GC-related.

Note
The simple-type enumeration (X_OBJ_FLAG_PRIM ... X_OBJ_FLAG_PTR) and the attribute bits share the low-order bits, so they are alternative interpretations rather than independently combinable. The storage bits X_OBJ_FLAG_OWN, X_OBJ_FLAG_RO and X_OBJ_FLAG_META – and, when X_HEAP is enabled, #X_OBJ_FLAG_SHARED and #X_OBJ_FLAG_MARK – are independent and may be OR-combined.

◆ x_obj_t

typedef union x_datum_union x_obj_t

A single object datum and the unit type from which objects are built.

◆ x_satom_t

Fixed-size storage for a statically allocated atom (metadata + 1 unit).

Note
The s prefix carries two senses in this header. Here (and in x_spair_t) it is storage: room for an object in static or stack storage instead of the heap. In x_obj_type_issatom() / x_obj_type_isspair() and in the x_mksatom() / x_mkspair() constructor family it is the built-in static type (x_type_atom_obj / x_type_pair_obj) – a property of the type slot, independent of where the object lives.

◆ x_spair_t

Fixed-size storage for a statically allocated pair (metadata + 2 units; see the s-prefix note at x_satom_t).

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Indices of the metadata units; X_OBJ_META_LEN is where data begins.

Enumerator
X_OBJ_META_TYPE 
X_OBJ_META_FLAGS 
X_OBJ_META_LEN 

◆ x_obj_flag_enum

Object flags – a bitfield stored in each object's flags metadata slot.

The low nibble (X_OBJ_FLAG_ATTR_MASK) holds general-purpose attribute bits. The high nibble (X_OBJ_FLAG_TYPE_MASK) encodes an optional "simple type" tag. The remaining bits are storage- and GC-related.

Note
The simple-type enumeration (X_OBJ_FLAG_PRIM ... X_OBJ_FLAG_PTR) and the attribute bits share the low-order bits, so they are alternative interpretations rather than independently combinable. The storage bits X_OBJ_FLAG_OWN, X_OBJ_FLAG_RO and X_OBJ_FLAG_META – and, when X_HEAP is enabled, #X_OBJ_FLAG_SHARED and #X_OBJ_FLAG_MARK – are independent and may be OR-combined.
Enumerator
X_OBJ_FLAG_NONE 

No flags set.

X_OBJ_FLAG_OBJ 

Full object typed via the type pointer; the default kind.

X_OBJ_FLAG_1 

General-purpose attribute bit 1 (application defined).

X_OBJ_FLAG_2 

General-purpose attribute bit 2 (application defined).

X_OBJ_FLAG_3 

General-purpose attribute bit 3 (application defined).

X_OBJ_FLAG_4 

General-purpose attribute bit 4 (application defined).

X_OBJ_FLAG_ATTR_MASK 

Mask selecting the four attribute bits.

X_OBJ_FLAG_SIMPLE_TYPE 

Base value of the simple-type enumeration.

X_OBJ_FLAG_PRIM 

Simple type: primitive / special form.

X_OBJ_FLAG_FN 

Simple type: function pointer (x_fn_t).

X_OBJ_FLAG_INT 

Simple type: integer (x_int_t).

X_OBJ_FLAG_CHAR 

Simple type: character (x_char_t).

X_OBJ_FLAG_STR 

Simple type: string (x_char_t *).

X_OBJ_FLAG_PTR 

Simple type: opaque pointer (void *).

X_OBJ_FLAG_TYPE_MASK 

Mask selecting the simple-type nibble.

X_OBJ_FLAG_OWN 

Object owns the allocation in its first datum; x_obj_free() releases it.

X_OBJ_FLAG_RO 

Read-only attribute (advisory; not enforced by the core).

X_OBJ_FLAG_META 

Object has extra metadata units prepended (see x_obj_meta_i()).

X_OBJ_FLAG_MASK 

Mask of all defined flag bits.

Function Documentation

◆ x_atom_prim_length()

x_obj_t * x_atom_prim_length ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: logical length of an atom (x_fn_t convention).

Primitive: the logical length of an atom.

Parameters
p_baseBase (execution context; unused).
p_argsArgument pair (unused).
Returns
The static atom x_type_length_atom_obj (value X_OBJ_LENGTH_ATOM).

◆ x_atom_prim_units()

x_obj_t * x_atom_prim_units ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: data-unit count of an atom (x_fn_t convention).

Primitive: the data-unit count of an atom.

Parameters
p_baseBase (execution context; unused).
p_argsArgument pair (unused).
Returns
The static atom x_type_units_atom_obj (value X_OBJ_UNITS_ATOM).

◆ x_obj_alloc()

x_obj_t * x_obj_alloc ( x_obj_t p_base,
x_obj_t p_type,
x_obj_flag_t  flags,
size_t  units 
)

Allocate an uninitialized object with units data units.

Allocate an uninitialized object.

Allocates space for units data units plus the standard metadata header. When the base configures extra metadata units (see x_base_field_obj_meta_extra()), that many leading units are also reserved; the returned pointer is advanced past them and X_OBJ_FLAG_META is set so x_obj_free() can recover the original allocation. When X_HEAP is enabled the object is linked onto the base's heap chain (and, under X_PROFILE, the allocation counter is incremented). The type and flags slots are set; the data units are left uninitialized.

Parameters
p_baseBase (execution context), or NULL to allocate without a base.
p_typeThe type object to assign, or NULL.
flagsInitial object flags.
unitsNumber of data units to allocate.
Returns
The new object, or NULL on allocation failure when no full base is attached (scratch/fixture use: the caller owns the null-check). With a full base attached the failure does not return – the runtime does not null-check allocations, so this function reports through the embedder-armed message (when set) and stops the process instead of handing back a NULL that would surface as a SIGSEGV in whatever code was running.
Note
When the base arms an allocation ceiling (see x_base_field_alloc_limit()), reaching it makes this function report through the base error path and stop the process rather than allocate past it – the runaway-memory guard.

◆ x_obj_error()

void x_obj_error ( x_obj_t p_base,
x_char_t message,
x_obj_t p_obj 
)

Output an error message to stderr.

Output an error message to stderr.

If the error hook is set in the base, delegates to it via a cast to void (*)(x_obj_t *, x_char_t *, x_obj_t *) – this differs from x_fn_t because error handlers take raw arguments (not a pair list). Otherwise, extracts the object's string text (if it is a static atom) and calls x_error().

Parameters
p_baseBase (execution context).
messageError message string.
p_objRelated object for context, or NULL.

◆ x_obj_free()

void x_obj_free ( x_obj_t p_base,
x_obj_t p_obj 
)

Free an object, releasing any owned datum and extra metadata units.

Free an object and any resources it owns.

If the object has X_OBJ_FLAG_OWN set, the allocation referenced by its first datum is freed first. When X_HEAP is enabled and X_OBJ_FLAG_META is set, the original allocation address is recovered by stepping back over the extra metadata units before freeing. This does not unlink the object from the heap chain – x_heap_sweep() relinks the chain around freed objects.

Parameters
p_baseBase (execution context; used to size extra metadata units).
p_objThe object to free.

◆ x_obj_isnil()

int x_obj_isnil ( x_obj_t p_base,
x_obj_t p_obj 
)

Test whether p_obj is nil (a NULL object pointer).

Test whether an object is nil.

nil is represented by a NULL object pointer. p_base is accepted for calling-convention uniformity but is not used.

Parameters
p_baseBase (execution context; unused).
p_objThe object to test.
Returns
Non-zero if p_obj is nil (NULL), zero otherwise.

◆ x_obj_length()

x_int_t x_obj_length ( x_obj_t p_base,
x_obj_t p_obj 
)

Get an object's logical length as an integer.

Get an object's logical length as an integer.

Builds the argument pair, calls x_obj_prim_length(), and unwraps the result.

Parameters
p_baseBase (execution context).
p_objThe object to inspect.
Returns
The logical length, defaulting to 0 when unknown.

◆ x_obj_make()

x_obj_t * x_obj_make ( x_obj_t p_base,
x_obj_t p_type,
x_obj_flag_t  flags,
size_t  units,
  ... 
)

Allocate an object and initialize its data units from varargs.

Allocate an object and initialize its data units from varargs.

Variadic wrapper around x_obj_make_va(); the x_mksatom() and x_mkspair() macros build on it.

Parameters
p_baseBase (execution context), or NULL.
p_typeThe type object to assign, or NULL.
flagsInitial object flags.
unitsNumber of data units, followed by that many x_obj_t * args.
Returns
The new object, or NULL on allocation failure.

◆ x_obj_make_va()

x_obj_t * x_obj_make_va ( x_obj_t p_base,
x_obj_t p_type,
x_obj_flag_t  flags,
size_t  units,
va_list  ap 
)

Allocate an object and initialize its data units from a va_list.

Allocate an object and initialize its data units from a va_list.

Calls x_obj_alloc(), then assigns units consecutive data units from ap (each consumed as an x_obj_t *).

Parameters
p_baseBase (execution context), or NULL.
p_typeThe type object to assign, or NULL.
flagsInitial object flags.
unitsNumber of data units to allocate and initialize.
apVariable argument list supplying the data units.
Returns
The new object, or NULL on allocation failure.

◆ x_obj_pop()

x_obj_t * x_obj_pop ( x_obj_t p_base,
x_obj_t p_args 
)

Callable wrapper for x_obj_pop_field() (x_fn_t convention).

Callable wrapper for x_obj_pop_field().

Follows the x_fn_t convention. p_args is (field-ptr) where field-ptr is an atom wrapping the x_obj_t ** field address.

Parameters
p_baseBase (execution context).
p_argsArgument pair whose first element wraps the field address.
Returns
The popped value.

◆ x_obj_pop_field()

x_obj_t * x_obj_pop_field ( x_obj_t p_base,
x_obj_t **  p_field 
)

Pop and return the head value of the pair-list stack at *p_field.

Pop the head value from a pair-list stack.

Returns the current head (x_firstobj(*p_field)) and advances *p_field to its rest. The popped pair is not freed; under X_HEAP the collector reclaims it.

Parameters
p_baseBase (execution context; unused).
p_fieldAddress of the field to pop from (updated in place).
Returns
The former head value.

◆ x_obj_prim_length()

x_obj_t * x_obj_prim_length ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: dispatch an object's logical length by type (x_fn_t convention).

Primitive: dispatch an object's logical length by type.

Returns x_pair_prim_length() for pairs and x_atom_prim_length() for atoms or nil-typed objects; for other types the base's length hook (x_base_field_hook_length()) is consulted.

Parameters
p_baseBase (execution context).
p_argsPair list whose first element is the subject object.
Returns
An integer atom with the logical length, or NULL.

◆ x_obj_prim_type_name()

x_obj_t * x_obj_prim_type_name ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: resolve an object's type object (x_fn_t convention).

Primitive: resolve an object's type object.

Follows the x_fn_t convention: p_args is a pair whose first element is the object to inspect. Built-in atoms and pairs, and any object with a nil type slot, return their type slot directly; for other types the base's type-name hook (x_base_field_hook_type_name()) is consulted.

Parameters
p_baseBase (execution context).
p_argsPair list whose first element is the subject object.
Returns
The type object, or NULL if the subject is nil or no type is found.

◆ x_obj_prim_units()

x_obj_t * x_obj_prim_units ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: dispatch an object's data-unit count by type (x_fn_t convention).

Primitive: dispatch an object's data-unit count by type.

Returns x_pair_prim_units() for pairs and x_atom_prim_units() for atoms or nil-typed objects; for other types the base's units hook (x_base_field_hook_units()) is consulted.

Parameters
p_baseBase (execution context).
p_argsPair list whose first element is the subject object.
Returns
An integer atom with the unit count, or NULL.

◆ x_obj_push()

x_obj_t * x_obj_push ( x_obj_t p_base,
x_obj_t p_args 
)

Callable wrapper for x_obj_push_field() (x_fn_t convention).

Callable wrapper for x_obj_push_field().

Follows the x_fn_t convention. p_args is (field-ptr value [flags]) where field-ptr is an atom wrapping the x_obj_t ** field address, value is the object to push, and the optional third element is an integer atom of flags (default X_OBJ_FLAG_NONE).

Parameters
p_baseBase (execution context).
p_argsArgument pair list as described above.
Returns
The pushed value.

◆ x_obj_push_field()

x_obj_t * x_obj_push_field ( x_obj_t p_base,
x_obj_t **  p_field,
x_obj_t p_value,
x_obj_flag_t  flags 
)

Push p_value onto the pair-list stack rooted at *p_field.

Push a value onto a pair-list stack.

Replaces *p_field with a new pair (p_value . old), so the field becomes a stack whose head is p_value. Used to save and restore base fields and to grow the heap hook/root lists.

Parameters
p_baseBase (execution context) for allocation.
p_fieldAddress of the field to push onto (updated in place).
p_valueThe value to push.
flagsFlags for the new pair.
Returns
The pushed value (p_value).

◆ x_obj_type_name()

x_char_t * x_obj_type_name ( x_obj_t p_base,
x_obj_t p_obj 
)

Get an object's type name as a C string (X_TYPE_NIL_NAME if nil).

Get an object's type name as a C string.

Builds the argument pair, calls x_obj_prim_type_name(), and unwraps the resulting type object's string value.

Parameters
p_baseBase (execution context).
p_objThe object to inspect.
Returns
The type-name string, or X_TYPE_NIL_NAME if the object has no resolvable type.

◆ x_obj_units()

x_int_t x_obj_units ( x_obj_t p_base,
x_obj_t p_obj 
)

Get an object's data-unit count as an integer.

Get an object's data-unit count as an integer.

Builds the argument pair, calls x_obj_prim_units(), and unwraps the result.

Parameters
p_baseBase (execution context).
p_objThe object to inspect.
Returns
The data-unit count, defaulting to X_OBJ_UNITS_ATOM when unknown.

◆ x_pair_prim_length()

x_obj_t * x_pair_prim_length ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: logical length of a pair (x_fn_t convention).

Primitive: the logical length of a pair.

Parameters
p_baseBase (execution context; unused).
p_argsArgument pair (unused).
Returns
The static atom x_type_length_pair_obj (value X_OBJ_LENGTH_PAIR).

◆ x_pair_prim_units()

x_obj_t * x_pair_prim_units ( x_obj_t p_base,
x_obj_t p_args 
)

Primitive: data-unit count of a pair (x_fn_t convention).

Primitive: the data-unit count of a pair.

Parameters
p_baseBase (execution context; unused).
p_argsArgument pair (unused).
Returns
The static atom x_type_units_pair_obj (value X_OBJ_UNITS_PAIR).

Variable Documentation

◆ x_false_obj

x_satom_t x_false_obj
extern

Canonical false atom (value X_OBJ_FALSE_TEXT).

◆ x_true_obj

x_satom_t x_true_obj
extern

Canonical true atom (value X_OBJ_TRUE_TEXT).

◆ x_type_atom_obj

x_satom_t x_type_atom_obj
extern

Built-in static atom type; its value is the "ATOM" type-name string.

◆ x_type_length_atom_obj

x_satom_t x_type_length_atom_obj
extern

Static atom holding the atom length, returned by x_atom_prim_length().

◆ x_type_length_pair_obj

x_satom_t x_type_length_pair_obj
extern

Static atom holding the pair length, returned by x_pair_prim_length().

◆ x_type_pair_obj

x_satom_t x_type_pair_obj
extern

Built-in static pair type; its value is the "PAIR" type-name string.

◆ x_type_units_atom_obj

x_satom_t x_type_units_atom_obj
extern

Static atom holding the atom data-unit count, returned by x_atom_prim_units().

◆ x_type_units_pair_obj

x_satom_t x_type_units_pair_obj
extern

Static atom holding the pair data-unit count, returned by x_pair_prim_units().