# 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: - `name` for a named declaration; - `pattern` for a destructuring declaration; - `type` for an explicit type; - `value` for 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.