Speak in meaning. Think beyond syntax. Built beyond language.

Universal AST

The Universal AST is the canonical semantic representation of the program.

More than syntax

A normal AST answers questions such as “what expression is inside this return statement?”. The Universal AST also carries language-independent semantic evidence about the program.

Examples include:

Area Examples
Structure assignment, call, loop, return, index, parameter
Identity stable node ID, scope ID
Types integer/float widths, pointer/reference, struct, function, aggregate
Semantics operation, evaluation mode, dispatch
Effects memory, I/O, allocation, exceptions, control flow
Relations syntax child, control branch, data operand, binding, type
Provenance source span, language origin

Direct execution

Parts of the UAST can be consumed directly by the semantic runtime, validators and backends. Other semantic structures are representable but not yet executable by every backend.

The key rule is representation is not the same as implementation. A schema-valid node may still be rejected by the native backend if its semantics cannot yet be preserved.

Sparse relation model

Relations are naturally represented as sparse matrices. This supports machine-readable program evidence without forcing every relation into recursive tree ownership.

flowchart LR N1[Node 12: call] -- data.operand --> N2[Node 14: arg] N1 -- call.calls --> N3[Node 52: function] N4[Node 9: declaration] -- binding.refers --> N2 N5[Node 3: scope] -- scope.parent --> N6[Node 1: module scope]

Fail-closed native lowering

If a native lowering path sees a node whose semantics it cannot preserve, it should stop with an explicit diagnostic such as:

UNIMPLEMENTED_NATIVE_GAP
NATIVE_UNRESOLVED_BINDING
NATIVE_EXTERNAL_VALUE_UNRESOLVED

Those failures are preferable to generating a binary with silently changed semantics.