The resolver converts an abstract syntax tree (AST) into an abstract semantic graph (ASG). Type definitions for the AST, ASG and expression types are found in ast.ts, asg.ts and type.ts respectively. The resolver also performs:
Much of the work is done by the functions in DECL_RESOLVE_FUNCS
, EXPR_RESOLVE_FUNCS
, RULE_RESOLVE_FUNCS
and STMT_RESOLVE_FUNCS
. These constant object map each AST node kind to a function which checks and resolves AST nodes of that kind.
The Context
class represents the current lexical context, including the declared grids, current grid, symmetry group for patterns, and variables and their types. The class is mutable, and only one instance will be used to resolve an entire AST.
Most changes to the context are temporary; for example, when resolving a variable declaration, the variable will be added to the context for the duration of resolving the part of the AST where that variable is in scope, and the variable is then removed from the context. The methods withOutGrid
, withSymmetry
, withVariable
etc. are used for some temporary context changes.
The main exception to the above is that when a stmt.map
or stmt.use
statement changes the context’s current grid, the change persists beyond the statement’s own lexical scope. Additionally, when a runtime parameter is declared with a let param
declaration, another runtime parameter of the same name cannot later be declared even if the first parameter is no longer in scope.
To avoid excessive code repetition, most expressions contained within declarations, rules or statements are resolved through the _resolveProp
and _resolveProps
functions. These functions resolve and check an expression according to a PropSpec
, which is a string consisting of:
const
modifier, indicating the expression must be a compile-time constant. In this case the expression will be resolved to a Type.Value
rather than an ASG.Expression
.PropTypeSpec
which is either a primitive type name, or one of charset.in
, charset.out
, dict
, position
, object
, pattern.in
, pattern.out
, position
or str~
.
float
or fraction
and the expression’s actual type is int
, then the expression will be coerced to the expected type.charset.in
and charset.out
mean 1x1 pattern types for the current alphabet.dict
means any dictionary type.position
means a position type for the current grid.object
means either any dictionary type, or any position
type, or grid
.pattern.in
and pattern.out
mean a pattern type for the current alphabet with the appropriate dimensions; otherwise they mean any pattern type for the current alphabet.str~
means the type str
is expected but an expression of type bool
, float
, fraction
, grid
or int
may be coerced to str
.?
modifier, indicating that the expression may be absent from the corresponding AST node.The PROP_SPECS
object defines PropSpec
strings for resolving some properties of some kinds of AST nodes. These are used by the _resolveProps
function.
ASG expressions are additionally labelled with flags indicating some static properties. These are defined in the ExprFlags
enum, and have the following meanings:
RUNTIME_CONSTANT
: the expression’s value is fixed at runtime. It may be a compile-time constant, or it may depend on the grid dimensions or other runtime parameters (excluding the PRNG seed).DETERMINISTIC
: the expression does not invoke the PRNG when it is evaluated, and it does not depend on any variable whose initialiser is not deterministic.LOCALLY_DETERMINISTIC
: the expression does not invoke the PRNG when it is evaluated, but its value may depend on a variable whose initialiser is not deterministic or locally-deterministic.POSITION_INDEPENDENT
: the expression’s value does not depend on the “current position” in a rule context, but it may depend on a variable whose initialiser is not position-independent.GRID_INDEPENDENT
: the expression’s value does not depend on the current state of the grid, but it may depend on a variable whose initialiser is not grid-independent.The purpose of these flags is to allow certain optimisations to be made by the compiler; particularly, to avoid repeatedly evaluating expressions when it is statically-known that the result will not have changed.