3.6 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.
function_literal takes one input and owns the body field. Direct binding
appears as parameter: (typed_parameter); tuple destructuring appears as
parameter: (typed_tuple_pattern). A typed_tuple_pattern contains zero or at
least two typed_tuple_component nodes. These bind components of one tuple
input, not separate function arguments. () matches unit; singleton tuple
patterns are invalid. Typed bindings expose pattern and type; a header may
also expose effect (-> or =>) and result.
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.