4.7 KiB
Concrete syntax tree contract
This document describes the named nodes and fields intended for consumers such
as editor integrations, formatters, and structural search. Rules prefixed with _
and rules listed as Tree-sitter supertypes are implementation details and do not
appear as named wrapper nodes in ordinary trees.
Source and declarations
source_file contains declarations, imports, publication declarations, and
standalone expressions directly. The choice-only module_item, expression,
and value_expression rules are hidden supertypes.
declaration uses these fields:
namefor a named declaration;patternfor a destructuring declaration;typefor an explicit type;valuefor an initializer.
The punctuation distinguishes immutable, mutable, typed, and deferred forms. Consumers should inspect that punctuation rather than infer the form from the set of fields alone.
Expressions
Only expressions that actually contain an operator produce an operator node:
| Node | Fields |
|---|---|
assignment_expression |
left, operator, right |
range_expression |
left, operator, right |
binary_expression |
left, operator, right |
unary_expression |
operator, operand |
postfix_expression |
value, repeated operator; member and index operators additionally expose member or index |
pipeline_expression |
input, followed by stage nodes |
Precedence-only rules are hidden. For example, a + b * -c has one outer and
one inner binary_expression, then a unary_expression; it does not contain a
wrapper for every precedence level.
Literal leaves are named. Boolean and nil values use boolean_literal and
nil_literal; numeric, string, character, and unit literals retain their
specific nodes. default_expression is also named.
some, ok, and err construct optional and result values. They are prefix
operators, so some value and ok {x->f} appear as unary_expression nodes
whose operator is the keyword. They bind like - and ~, so ok x->f
wraps x and then pipes the result into f, while ok {x->f} wraps the
pipeline. The older |.some/|.ok/|.err
constructors, postfix value!, and prefix !error are no longer accepted.
function_literal takes one input and owns the body field. A pattern with
one annotation for the whole input, such as @ value: i32 or
@ (left, right): (i32, i32), appears as parameter: (typed_parameter).
The annotation is optional: an input whose type comes from the expected
function type, such as @ value or @ (left, right), is also a
typed_parameter without a type field. Component-annotated tuple
destructuring, such as @ (left: i32, right), appears as
parameter: (typed_tuple_pattern). A typed_tuple_pattern contains at least
two typed_tuple_component nodes, each with an optional type. These bind
components of one tuple input, not separate function arguments. () matches
unit and is a typed_parameter over a unit_pattern; singleton tuple patterns
are invalid. Bindings expose pattern and, when annotated, type; a header
may also expose effect (-> or =>) and result.
Patterns
wrapper_pattern matches some, ok, or err applied to one pattern atom.
It exposes wrapper (the keyword) and value (the inner pattern). nil is
still a nil_literal pattern. Sum patterns retain sum_pattern with a
variant field.
Types
Meaningful type constructors are named directly:
| Node | Fields |
|---|---|
function_type |
input, effect, result |
result_type |
value, error |
optional_type |
value |
array_type |
element |
map_type |
key, value |
grouped_type |
value |
type_application |
constructor followed by its type arguments |
Primitive, unit, tuple, product, sum, and bits types retain their corresponding named nodes. Internal primary/container/result categories are hidden.
Trivia and physical lines
Comments are named extra nodes. Spaces, tabs, and structural newlines remain in the source gaps between nodes, so a formatter must retain the original source alongside the tree. Leading-operator and pipeline continuations use composite tokens containing their newline; this prevents a scope separator from stealing a valid continuation and preserves the language's physical-line rules.
Compatibility
Adding nodes or fields is compatible. Removing or renaming a named node or field, changing its meaning, or changing which source construct owns it is a breaking CST change. Until the package reaches 1.0, such changes require corpus snapshot updates and a version change, and must be called out in release notes.
The Tree-sitter tree is designed for source tooling and error recovery; it does not perform semantic validation.