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

Environments – make, look up, bind, and the child a call makes. More...

#include "x-env.h"
#include "x-alist.h"
#include "x-type/list.h"
#include "x-type/symbol.h"

Functions

x_obj_tx_env_make (x_obj_t *p_base, x_obj_t *p_parent)
 
static x_obj_tx_env_own_symbol (x_obj_t *p_base, x_obj_t *p_sym)
 
x_obj_tx_env_lookup (x_obj_t *p_base, x_obj_t *p_env, x_obj_t *p_sym)
 
x_obj_tx_env_bind (x_obj_t *p_base, x_obj_t *p_env, x_obj_t *p_sym, x_obj_t *p_val)
 
x_obj_tx_env_extend (x_obj_t *p_base, x_obj_t *p_parent, x_obj_t *p_params, x_obj_t *p_vals)
 

Detailed Description

Environments – make, look up, bind, and the child a call makes.

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

Function Documentation

◆ x_env_bind()

x_obj_t * x_env_bind ( x_obj_t p_base,
x_obj_t p_env,
x_obj_t p_sym,
x_obj_t p_val 
)

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 root's tree, or in front of another environment'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.

Parameters
p_basex_obj_t* – Base (execution context)
p_envx_obj_t* – The environment to bind in
p_symx_obj_t* – The symbol
p_valx_obj_t* – The value
Returns
x_obj_t* – p_val
Note
The tree insert mutates in place (x_alist_bst_insert), so every closure whose chain reaches this root sees the new binding at its next lookup – a top-level definition made after a closure was created is visible to it, as it must be.

◆ x_env_extend()

x_obj_t * x_env_extend ( x_obj_t p_base,
x_obj_t p_parent,
x_obj_t p_params,
x_obj_t p_vals 
)

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.

Parameters
p_basex_obj_t* – Base (execution context)
p_parentx_obj_t* – The environment the new one is a child of
p_paramsx_obj_t* – Parameter list (or single symbol for variadic)
p_valsx_obj_t* – Value list
Returns
x_obj_t* – The new environment

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.

Note
The variadic case (bare symbol for p_params) binds the ENTIRE remaining value list, not just one value. This implements rest-parameter semantics: (fn (a . rest) ...).
See also
x_env_binddef, the same binder one name at a time
x_eval_body_tco – saves/restores env around a body

◆ x_env_lookup()

x_obj_t * x_env_lookup ( x_obj_t p_base,
x_obj_t p_env,
x_obj_t p_sym 
)

The cell binding p_sym in p_env or an ancestor.

Walks from p_env to the root: an environment with a parent searches its alist of (name . value) cells by symbol identity; the root searches its 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.

Parameters
p_basex_obj_t* – Base (execution context)
p_envx_obj_t* – The environment to start from
p_symx_obj_t* – The symbol
Returns
x_obj_t* – The (name . value) cell, or NULL when unbound

◆ x_env_make()

x_obj_t * x_env_make ( x_obj_t p_base,
x_obj_t p_parent 
)

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.

Parameters
p_basex_obj_t* – Base (execution context)
p_parentx_obj_t* – The enclosing environment, or nil for a root
Returns
x_obj_t* – The new, empty environment

◆ x_env_own_symbol()

static x_obj_t * x_env_own_symbol ( x_obj_t p_base,
x_obj_t p_sym 
)
static

The base's own symbol spelled like p_sym, or NULL.

Symbols intern per base, so a symbol read or made in another base is a different object from this base's symbol of the same spelling. The intern table answers which object this base uses for the spelling.

Parameters
p_basex_obj_t* – Base (execution context)
p_symx_obj_t* – A symbol, this base's or another's
Returns
x_obj_t* – This base's symbol for the spelling, or NULL when it has none