Files
tree-sitter-lscript/docs/cst.md
T

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:

  • 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.