|
x-engine-c v0.2.31
The C engine for x-lang
|
The base's slot vector – the engine's routines, each at a fixed position, called through the position. More...
Go to the source code of this file.
Enumerations | |
Slot Positions | |
| enum | x_eval_slot_enum { X_SLOT_EVAL = 0 , X_SLOT_EVAL_LIST , X_SLOT_EVAL_BODY , X_SLOT_EVAL_BODY_TCO , X_SLOT_EVAL_TCO_TRAMPOLINE , X_SLOT_EVAL_OP_BODY , X_SLOT_CALLABLE_CALL , X_SLOT_CALLABLE_APPLY , X_SLOT_OBJ_PRIM_CALL , X_SLOT_ENV_LOOKUP , X_SLOT_ENV_BIND , X_SLOT_ENV_EXTEND , X_SLOT_ALIST_BST_LOOKUP , X_SLOT_TOKEN_READ , X_SLOT_TOKEN_ANALYSE , X_SLOT_TOKEN_DELIMIT , X_SLOT_HEAP_MARK , X_SLOT_HEAP_SWEEP , X_SLOT_OBJ_ALLOC , X_SLOT_LEN } |
Slot Access | |
| #define | x_slot(V, I) x_vectorfn((V), (I)) |
| #define | x_argrun(...) ((x_obj_t[]){ __VA_ARGS__ }) |
| #define | x_eval_slots(B) x_restobj((B)) |
| #define | x_eval_slot(B, I) x_slot(x_eval_slots((B)), (I)) |
| #define | x_eval_slots_isset(B) ((B) != NULL && x_eval_slots((B)) != NULL) |
| #define | x_eval_call(B, I, A) (x_eval_slot((B), (I))((B), (A))) |
| #define | x_eval_call_or(B, I, FN, A) ((x_eval_slots_isset((B)) ? x_eval_slot((B), (I)) : (FN))((B), (A))) |
| #define | x_eval_slot_isset(B, I) (x_eval_slots_isset((B)) && x_eval_slot((B), (I)) != NULL) |
| x_obj_t * | x_slots_make (x_obj_t *p_base, x_int_t length) |
The base's slot vector – the engine's routines, each at a fixed position, called through the position.
A base holds a slot vector: a vector (see x-vector.h) whose elements are function pointers, one per slot. The engine reaches a routine by its position in the vector, so a routine can be replaced while the engine runs by storing another function pointer in its slot.
A slot holds a function pointer and nothing more. Every routine in a slot has the engine's one signature, x_fn_t:
and p_args is the routine's argument run: a run of datum words, one per argument, in the order the slot's row in the layout contract gives them. A word holds what the argument is: an object pointer, an integer, a string. The run has no header and no length; the contract says how many words there are and what each holds. The caller writes the words, in stack storage, and the routine reads them back:
A call through a slot allocates nothing. The elements of a heap vector are a run of words too, so a caller that holds its arguments in a vector passes the address of its first element.
The slot vector is the base object's second data unit. x-expr makes a base of one unit holding the tree; x_eval_make() makes the engine's base of two, the tree first, where x-expr reads it, and the vector second, so a call locates the vector in one load from the base. Each base has a vector of its own, filled from the engine's table when the base is made, and a slot replaced in one base is replaced there alone. The positions are part of the layout contract: they are listed in tools/contract/base-slots.x, which tools/check/base-slots.sh diffs against this header, and a language that replaces a routine reads its position from there. Each slot's comment gives its arguments and the type of the word each travels in: an object, an integer or a string. The collector is the engine's: the mark and sweep phases and the allocation of an object are routines in the vector, written over x-expr's chain, traversal, sweep and hooks, which the engine calls by name and which are never in a slot.
| #define x_argrun | ( | ... | ) | ((x_obj_t[]){ __VA_ARGS__ }) |
An argument run written as an expression: the datum initializers of its words, in order. It lasts as long as the block the expression is in.
| #define x_eval_call | ( | B, | |
| I, | |||
| A | |||
| ) | (x_eval_slot((B), (I))((B), (A))) |
Call the function in slot I of base B with argument run A. The base must have a slot vector and the slot must hold a function: one load for the vector, one for the slot, and the call.
| #define x_eval_call_or | ( | B, | |
| I, | |||
| FN, | |||
| A | |||
| ) | ((x_eval_slots_isset((B)) ? x_eval_slot((B), (I)) : (FN))((B), (A))) |
Call the function in slot I of base B with argument run A, or the routine FN when there is no base or the base has no slot vector. For the engine's own calls, which may run before a base exists, or on a base x-expr made; a base x_eval_make() made always has its slots.
| #define x_eval_slot | ( | B, | |
| I | |||
| ) | x_slot(x_eval_slots((B)), (I)) |
The function pointer in slot I of base B (an lvalue).
| #define x_eval_slot_isset | ( | B, | |
| I | |||
| ) | (x_eval_slots_isset((B)) && x_eval_slot((B), (I)) != NULL) |
Test whether slot I of base B holds a function: the base has a slot vector and the slot is not empty.
| #define x_eval_slots | ( | B | ) | x_restobj((B)) |
The slot vector of base B (an lvalue): its second data unit.
| #define x_eval_slots_isset | ( | B | ) | ((B) != NULL && x_eval_slots((B)) != NULL) |
Test whether base B has a slot vector: one load. The base must have two units: an object standing as an allocation context is a pair with nothing in it, never an atom, since the second unit is read.
| #define x_slot | ( | V, | |
| I | |||
| ) | x_vectorfn((V), (I)) |
The function pointer in slot I of slot vector V (an lvalue).
| enum x_eval_slot_enum |
The positions in the slot vector.
| Enumerator | |
|---|---|
| X_SLOT_EVAL | x_eval(). Arguments: (expression). Types: (object). |
| X_SLOT_EVAL_LIST | x_eval_list(). Arguments: (args). Types: (object). |
| X_SLOT_EVAL_BODY | x_eval_body(). Arguments: (body). Types: (object). |
| X_SLOT_EVAL_BODY_TCO | x_eval_body_tco(). Arguments: (body). Types: (object). |
| X_SLOT_EVAL_TCO_TRAMPOLINE | x_eval_tco_trampoline(). Arguments: (result). Types: (object). |
| X_SLOT_EVAL_OP_BODY | x_eval_op_body(). Arguments: (body, caller). Types: (object, object). |
| X_SLOT_CALLABLE_CALL | x_callable_call(). Arguments: (args). Types: (object). |
| X_SLOT_CALLABLE_APPLY | x_callable_apply(). Arguments: (args). Types: (object). |
| X_SLOT_OBJ_PRIM_CALL | x_obj_prim_call(). Arguments: (args). Types: (object). |
| X_SLOT_ENV_LOOKUP | x_env_lookup(). Arguments: (env, symbol). Types: (object, object). |
| X_SLOT_ENV_BIND | x_env_bind(). Arguments: (env, symbol, value). Types: (object, object, object). |
| X_SLOT_ENV_EXTEND | x_env_extend(). Arguments: (parent, params, values). Types: (object, object, object). |
| X_SLOT_ALIST_BST_LOOKUP | x_alist_bst_lookup(). Arguments: (tree, symbol). Types: (object, object). |
| X_SLOT_TOKEN_READ | x_token_read(). Arguments: (args). Types: (object). |
| X_SLOT_TOKEN_ANALYSE | x_token_analyse(). Arguments: (args, label). Types: (object, integer). The routine stores the label it declares in the second word. |
| X_SLOT_TOKEN_DELIMIT | x_token_delimit(). Arguments: (args). Types: (object). |
| X_SLOT_HEAP_MARK | x_heap_mark_phase(), the collector's mark phase. Arguments: (). Types: (). |
| X_SLOT_HEAP_SWEEP | x_heap_sweep_phase(), the collector's sweep phase. Arguments: (). Types: (). |
| X_SLOT_OBJ_ALLOC | x_eval_alloc(), allocate an object. Arguments: (type, flags, units). Types: (object, integer, integer). |
| X_SLOT_LEN | The length of the slot vector. |
Make a slot vector of length slots, every one empty.
Make a slot vector of length slots, every one empty.
The slot vector is a vector: its first data unit holds its length, and its slots follow. It has no type, and must not be given one: the vector sits in the base's tree, where the collector's mark reaches it, and an object with no type is marked and not descended – its elements are function pointers, not objects. It is allocated with X_OBJ_FLAG_SHARED, so a sweep keeps it for as long as the base lives, and its length is a static atom or a SHARED one for the same reason.
| p_base | Base the vector belongs to (allocation context). |
| length | The number of slots. |