-
-
Notifications
You must be signed in to change notification settings - Fork 0
env Env
This class is used to create environment objects. An environment allows binding variables to values or other variables, check if a variable is bound (only unbound variables can be bound), and rollback bindings in a generational fashion. This functionality is very important for a solver.
Env is the proto-chain reference implementation of the EnvLike contract. EnvMap is a sibling Map-stack implementation; both are interchangeable and selectable per unify() call.
It is defined in env and can be accessed like that:
import {Env} from 'deep6/env.js';const env = new Env();
env.isBound('a'); // false
env.isBound('b'); // false
env.isBound('c'); // false
// push a generation frame
env.push();
env.bindVal('a', 1);
env.isBound('a'); // true
env.isBound('b'); // false
env.isBound('c'); // false
env.get('a'); // 1
// push a generation frame
env.push();
env.isBound('a'); // true
env.isBound('b'); // false
env.isBound('c'); // false
env.bindVar('c', 'b');
env.isBound('a'); // true
env.isBound('b'); // false
env.isBound('c'); // false
env.isAlias('a', 'b'); // false
env.isAlias('b', 'c'); // true
env.isAlias('c', 'a'); // false
env.bindVal('b', 2);
env.isBound('a'); // true
env.isBound('b'); // true
env.isBound('c'); // true
env.get('a'); // 1
env.get('b'); // 2
env.get('c'); // 2
// drop a generation frame
env.pop();
env.isBound('a'); // true
env.isBound('b'); // false
env.isBound('c'); // falseThis class defines objects with the following public properties:
-
depth— an integer value of the depth, which is the current generation number. The initial value is 0. Use it with therevert(depth)method described below. -
options— a plain object holding the behavioural flags read byunify()(openObjects,openArrays,openMaps,openSets,circular,loose,ignoreFunctions,signedZero,symbols). Initially empty.unify()merges any options it receives into this bag, so chainingunify(a, b, env, opts)calls accumulates flags.
Internal storage (variables, values — or whatever an alternative implementation chooses) is not part of the public surface. Use the methods below to inspect bindings.
The class defines the following methods:
The constructor takes no arguments. It initializes an empty environment object as described above.
The method advances depth by 1 and returns nothing. Computationally it is very cheap (O(1)). Usually, it is used with pop() and revert(depth) described below.
The method reduces depth by 1 and returns nothing. While reducing the depth, it will undo all bindings that happened since the previous push(). Computationally it is inexpensive.
It will throw an error if depth becomes negative.
Example:
env.push(); // creates new frame
// multiple bindings of variables and values
env.pop();
// now we returned to the previous state
// and can try other ways to bind variablesThe method reverts to the previous depth and returns nothing. While going back to the requested depth, it will undo all bindings that happened since that time. It takes the following arguments:
-
depth— an integer value of the previous depth.- It will throw an error if the current depth is lower than the requested depth.
Example:
const depth = env.depth; // remember the current depth
// multiple bindings of variables and values
// possibly with pushing to a higher depth
env.revert(depth);
// now we returned to the previous state
// and can try other ways to bind variablesThe method declares two variables to be aliases of each other and returns nothing. Binding a value to one variable will automatically bind all its aliases. It takes the following arguments:
-
name1— a variable name as a string or a symbol. -
name2— a variable name as a string or a symbol.
Both names and all their existing aliases will be aliased. The procedure is completely symmetric and it doesn't matter in what order they are aliased.
No checks are done that variable names are not the same nor aliased already. No checks are done to ensure that they are not bound to different values. Correctness checks should be done externally before calling the method.
The method binds a variable (and all its aliases created with bindVar()) to a value. It takes the following arguments:
-
name— a variable name as a string or a symbol. -
value— an arbitrary value.
No checks are done that the variable is unbound, or bound to the same value. Correctness checks should be done externally before calling the method.
The method returns a truthy value if a variable is already bound to a value. Computationally it is very cheap (O(1)). It takes the following arguments:
-
name— a variable name as a string or a symbol.
The current implementation:
isBound(name) {
return name in this.values;
}The method returns a truthy value if variables are already aliased to each other. Computationally it is very cheap (O(1)). It takes the following arguments:
-
name1— a variable name as a string or a symbol. -
name2— a variable name as a string or a symbol.
The procedure is completely symmetric and it doesn't matter in what order they are aliased.
The current implementation:
isAlias(name1, name2) {
const u = this.variables[name2];
return u && u[name1] === 1;
}The method returns a value bound to a variable. Computationally it is very cheap (O(1)). It takes the following arguments:
-
name— a variable name as a string or a symbol.
No checks are done that the variable is bound. Correctness checks should be done externally before calling the method. If a variable is not bound in the environment, get() will return undefined.
Example:
const value = 1; // some arbitrary value
env.bindVal('a', value);
env.get('a') === value; // trueThe current implementation:
get(name) {
return this.values[name];
}This is a debugging method. It returns an array of objects with the following properties:
-
name— a variable name as a string or a symbol. -
value— an arbitrary value.
Only currently bound variables are listed. All aliases will be included.
Core functions
Environments and variables
Unification
Traverse
Unifiers
Utilities