|
x-engine-c v0.2.31
The C engine for x-lang
|
Environments – first-class values the evaluator binds and looks up in. More...
#include "x-obj.h"Go to the source code of this file.
Macros | |
The pair | |
| #define | x_env_bindings(E) x_firstobj(E) |
| #define | x_env_parent(E) x_restobj(E) |
| #define | x_env_isroot(B, E) x_obj_isnil((B), x_restobj(E)) |
| #define | x_env_istree(B, E) (x_env_isroot((B), (E)) || ! x_obj_type_isspair(E)) |
Functions | |
| x_obj_t * | x_env_make (x_obj_t *p_base, x_obj_t *p_parent) |
| x_obj_t * | x_env_lookup (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_env_bind (x_obj_t *p_base, x_obj_t *p_args) |
| x_obj_t * | x_env_extend (x_obj_t *p_base, x_obj_t *p_args) |
Environments – first-class values the evaluator binds and looks up in.
An environment is one pair, (bindings . parent). The root's parent is nil and its bindings are a tree (x-alist.c's BST, for the size of a loaded library); every other environment's bindings are an alist of (name . value) cells and its parent is the environment it was made in. A procedure call makes a child of the closure's environment; an operative body runs in a child of its static environment and receives the caller's environment as a value; def binds in the current environment; eval with an environment makes that one current. That is the whole of scope, and these four operations are all of it.
| #define x_env_bindings | ( | E | ) | x_firstobj(E) |
The alist, or the root's tree.
| #define x_env_isroot | ( | B, | |
| E | |||
| ) | x_obj_isnil((B), x_restobj(E)) |
A root has no parent.
| #define x_env_istree | ( | B, | |
| E | |||
| ) | (x_env_isroot((B), (E)) || ! x_obj_type_isspair(E)) |
Keeps its bindings as a tree: a root, and an environment whose spine the language made with pair – a list pair, where the engine makes its own frames of structural pairs. A module's scope is one: its hundreds of names would otherwise be an alist every root lookup from inside walks.
| #define x_env_parent | ( | E | ) | x_restobj(E) |
The enclosing environment, nil at the root.
Bind a symbol to a value in an environment itself: an existing binding there is updated in place, otherwise one is added. Never touches a parent. Returns the value. Argument run: (env, symbol, value).
Bind p_sym to p_val in p_env itself.
A binding the environment already holds is updated in place; otherwise one is added – to the tree of a root or a module's scope (x_env_istree), or in front of a frame's alist. A parent's binding of the same name is never touched: it is shadowed, which is what a definition in a child means. def is this on the current environment; the C binding doors and base bind are this on a root.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Argument run: (env, symbol, value) – the environment to bind in, the symbol, the value |
Make a child of an environment with parameters bound to values: the environment a procedure body or an operative body runs in. Argument vector: (parent, params, values).
Make a child environment with parameters bound to values.
The environment a procedure body or an operative body runs in: a fresh (bindings . parent) pair whose parent is p_parent, the closure's or the operative's static environment, and whose bindings are the parameters. Handles three cases: (1) variadic – a bare symbol binds to the entire remaining value list, (2) base – no more params, (3) one parameter to one value, then the rest.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Argument run: (parent, params, values) – the environment the new one is a child of, the parameter list (or a single symbol for variadic), and the value list |
The parent is never modified. The bindings are new cells in the new environment; p_parent is only pointed at. Fewer values than parameters binds the remainder to nil, symmetric with surplus values, which are ignored once the parameters run out.
(fn (a . rest) ...).def, the same binder one name at a time The (name . value) cell binding a symbol in an environment or an ancestor, or NULL when no environment on the chain binds it. Names are found by identity; a symbol interned in another base stands for this base's own symbol of its spelling. Argument run: (env, symbol).
The cell binding p_sym in p_env or an ancestor.
Walks from p_env to the root: a frame searches its alist of (name . value) cells by symbol identity; the root, and a module's scope (x_env_istree), search their tree, also by identity. The first hit wins, so a child's binding shadows a parent's. This is the whole of symbol lookup – x_type_symbol_eval and set! call nothing else.
Symbols intern per base, and a name is found by identity, not by spelling: a base's own symbol finds only what was bound under it, so a name the host bound into a child under the host's symbol is not found by the child's symbol of the same spelling. A FOREIGN symbol – one interned in another base, as every symbol of a form the host read and evaluates in a child is – has no identity here, so it stands for this base's own symbol of its spelling, and that is what is looked up. That is what lets (base eval B (lit (+ 2 3))) hand a child the host's + and reach the child's binding of its own +. The retry runs only when the identity lookup at the root missed.
Under X_PROFILE, each binding compared in an environment with a parent – a frame, or a module's environment – counts one in the base's profile-env-steps cell. The root's tree counts its own lookups, in profile-bst-hits and profile-bst-misses, so the walk to the root is what this one cell adds.
| p_base | x_obj_t* – Base (execution context) |
| p_args | x_obj_t* – Argument run: (env, symbol) – the environment to start from, and the symbol |
(name . value) cell, or NULL when unbound Make an empty environment whose parent is p_parent (nil for a root).
Make an empty environment whose parent is p_parent.
An environment is one pair, (bindings . parent). A nil parent makes a root, whose bindings are kept as a tree; any other environment keeps an alist. x_eval_make builds the base's root this way; procedure and operative calls make children through x_env_extend; guard makes one for its error variable.
| p_base | x_obj_t* – Base (execution context) |
| p_parent | x_obj_t* – The enclosing environment, or nil for a root |