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.