moonrockz/krueger/syntax does not have a README file

    EventSource

    pub(open) trait EventSource {
    fn next(Self) -> Event?
    fn skip_children(Self) -> Unit
    }

    A pull source of events in walk order. skip_children is valid right after an Enter: the next event is then that node's Leave. Elsewhere it does nothing.

    Handler

    pub(open) trait Handler {
    fn on_enter(Self, EnterEvent) -> Control = _
    fn on_leave(Self, LeaveEvent) -> Unit = _
    }

    Receives pushed events. on_enter steers the traversal like a walk's enter; both methods have defaults (Continue, nothing).

    Visitor

    pub(open) trait Visitor {
    fn visit_declaration(Self, NodeRef) -> Control = _
    fn visit_function(Self, NodeRef) -> Control = _
    fn visit_expression(Self, NodeRef) -> Control = _
    fn visit_pattern(Self, NodeRef) -> Control = _
    fn visit_type(Self, NodeRef) -> Control = _
    fn visit_case(Self, NodeRef) -> Control = _
    fn visit_import(Self, NodeRef) -> Control = _
    fn visit_comment(Self, NodeRef) -> Control = _
    fn visit_attribute(Self, NodeRef) -> Control = _
    fn visit_other(Self, NodeRef) -> Control = _
    fn leave(Self, NodeRef) -> Unit = _
    }

    A visitor over the node model: one method per group of node types (see accept for which method sees which node). Every method has a default: visit_* returns Continue and leave does nothing, so a visitor implements only what it needs. The visitor's state belongs to the caller.

    Control

    pub(all) enum Control {
    Continue
    SkipChildren
    Stop
    } derive(Eq,
    Debug
    )

    What a traversal does after it enters a node.

    EnterEvent

    pub struct EnterEvent {
    category : String
    kind : String
    field : String?
    start :
    Location

    depth : Int
    path : NodePath
    } derive(Eq,
    Debug
    )

    What an Enter event tells: only what a streaming parser knows when a node starts. field is the node's field in its parent and path the steps from the start node (None and the empty path for the start node); depth is path.depth().

    EnterEvent::new

    fn EnterEvent::new(category~ : String, kind~ : String, field~ : String?, start~ :
    Location
    , path~ : NodePath) -> EnterEvent

    An EnterEvent; its depth is path.depth(). Event sources outside this package build events with new, so fields added later need not break them.

    Event

    pub(all) enum Event {
    Enter(EnterEvent)
    Leave(LeaveEvent)
    } derive(Eq,
    Debug
    )

    A traversal event, in walk order.

    EventReader

    pub struct EventReader {
    // private fields
    }

    Reads the events of a tree one at a time (the walk engine, paused between next calls). Each reader owns its state; readers over one tree do not affect each other.

    EventReader::new

    fn EventReader::new(root : NodeRef) -> EventReader

    A reader positioned before root's Enter.

    LeaveEvent

    pub struct LeaveEvent {
    node : NodeRef
    depth : Int
    path : NodePath
    } derive(Eq,
    Debug
    )

    What a Leave event tells: the finished node, with the depth and path of its Enter.

    LeaveEvent::new

    fn LeaveEvent::new(node~ : NodeRef, path~ : NodePath) -> LeaveEvent

    A LeaveEvent; its depth is path.depth().

    NodePath

    pub struct NodePath {
    // private fields
    } derive(Eq, Hash,
    Debug
    )

    Where a node sits below a start node: the steps from the start node, each a field and an index, like a path into elm-syntax's JSON. A path is immutable; a child's path shares its parent's steps.
    impl Show for NodePath

    NodePath::child

    fn NodePath::child(self : NodePath, field : String, index : Int) -> NodePath

    The path of the node at index in this node's field.

    NodePath::depth

    fn NodePath::depth(self : NodePath) -> Int

    The number of steps (0 for the start node).

    NodePath::last

    fn NodePath::last(self : NodePath) -> PathStep?

    The last step: the node's field and index in its parent.

    NodePath::parent

    fn NodePath::parent(self : NodePath) -> NodePath?

    The parent's path, or None for the start node.

    NodePath::resolve

    fn NodePath::resolve(self : NodePath, start : NodeRef) -> NodeRef?

    The node this path leads to from start, or None when a step does not exist there.

    NodePath::root

    fn NodePath::root() -> NodePath

    The path of the start node: no steps, depth 0.

    NodePath::steps

    fn NodePath::steps(self : NodePath) -> Array[PathStep]

    The steps, from the start node down (a new array).

    NodeRef

    pub(all) enum NodeRef {
    File(
    File
    , ArrayView[
    AttributeGroup
    ])
    Module(
    Node
    [
    Module
    ])
    ModuleName(
    Node
    [ArrayView[String]])
    Exposing(
    Node
    [
    Exposing
    ])
    Expose(
    Node
    [
    TopLevelExpose
    ])
    Import(
    Node
    [
    Import
    ])
    Declaration(
    Node
    [
    Declaration
    ], ArrayView[
    DocAttribute
    ])
    Documentation(
    Node
    [String])
    Signature(
    Node
    [
    Signature
    ])
    Implementation(
    Node
    [
    FunctionImplementation
    ])
    Constructor(
    Node
    [
    ValueConstructor
    ])
    Expression(
    Node
    [
    Expression
    ])
    LetDeclaration(
    Node
    [
    LetDeclaration
    ])
    Case(
    Case
    )
    RecordSetter(
    Node
    [
    RecordSetter
    ])
    Pattern(
    Node
    [
    Pattern
    ])
    TypeAnnotation(
    Node
    [
    TypeAnnotation
    ])
    RecordField(
    Node
    [
    RecordField
    ])
    Name(
    Node
    [String])
    Comment(
    Node
    [String])
    Attribute(
    DocAttribute
    )
    } derive(Eq,
    Debug
    )

    A read-only reference to one node of a parse result. Each case points into the typed AST (nothing is copied). Generic code uses category, kind, range, children and field; typed code matches the cases.

    Kinds and field names follow the JSON that elm-syntax (and @ast.encode_*) writes. elm-syntax reuses tags across node types (record, list, unit, …), so (category, kind) identifies a node type.

    NodeRef::category

    fn NodeRef::category(self : NodeRef) -> String

    The node type: "expression", "pattern", "type", "declaration", …

    NodeRef::children

    fn NodeRef::children(self : NodeRef) -> Array[NodeRef]

    All child nodes in source order (a new array).

    NodeRef::field

    fn NodeRef::field(self : NodeRef, name : String) -> Array[NodeRef]

    The nodes in field name (a new array; empty for an absent or unknown field).

    NodeRef::field_of

    fn NodeRef::field_of(self : NodeRef, child : NodeRef) -> String?

    The field of this node that holds child, if any.

    NodeRef::fields

    fn NodeRef::fields(self : NodeRef) -> Array[String]

    The names of this node's fields, in elm-syntax JSON order.

    NodeRef::kind

    fn NodeRef::kind(self : NodeRef) -> String

    The elm-syntax JSON tag of the node, or its category when elm-syntax has no tag for it.

    NodeRef::of_result

    The root node of result: its file with the doc attributes, or None when the parse produced no AST.

    The attribute groups are copied; the AST is shared with result, so neither may be changed while nodes are in use.

    NodeRef::range

    The node's range. A case branch runs from its pattern to its expression; the file from line 1, column 1 to the end of its last node. A declaration with doc attributes starts no later than its first attribute (a port's doc comment is not part of its elm-syntax range).

    PathStep

    pub(all) struct PathStep {
    field : String
    index : Int
    } derive(Eq, Hash,
    Debug
    )

    One step of a node path: a field of the parent and the node's index in that field (0 for a field that holds one node).

    Tree

    pub struct Tree {
    // private fields
    }

    A parse result as a tree with random access: parents, ancestors, paths, the node at a position and the tokens in a range. It is built once and never changes; its indexes are private.

    Tree::ancestors

    fn Tree::ancestors(self : Tree, n : NodeRef) -> Array[NodeRef]

    The parents of n, nearest first, ending at the root (a new array).

    Tree::new

    The tree of result, or None when the parse produced no AST.

    Tree::node_at

    The innermost node whose range contains p, or None outside the file. Every branch that contains p is searched, because siblings can overlap: a comment (a child of the file) lies inside a declaration, and a port's doc comment holds the port's attributes. The smallest range wins; for equal ranges the deeper node wins, then the first in source order.

    Tree::node_path

    fn Tree::node_path(self : Tree, n : NodeRef) -> NodePath?

    The steps from the root to n, or None when n is not in the tree. With node_at, this takes an editor from a position to a path.

    Tree::parent

    fn Tree::parent(self : Tree, n : NodeRef) -> NodeRef?

    The parent of n, or None for the root and for nodes not in the tree.

    Tree::path

    fn Tree::path(self : Tree, n : NodeRef) -> Array[NodeRef]

    The nodes from the root down to n, both included (a new array).

    Tree::root

    fn Tree::root(self : Tree) -> NodeRef

    The file node at the top of the tree.

    Tree::tokens_in

    The tokens that lie inside r, in source order: new tokens with new trivia arrays, so changing them changes nothing in the tree.

    TreeCursor

    pub struct TreeCursor {
    // private fields
    }

    A tree-sitter-style cursor: the caller moves it with the goto_* methods. Each goto_* returns false and leaves the cursor in place when there is nowhere to go. Its state is a stack of frames, not recursion. A cursor belongs to its caller; copy gives an independent cursor.

    TreeCursor::copy

    fn TreeCursor::copy(self : TreeCursor) -> TreeCursor

    An independent cursor at the same place.

    TreeCursor::depth

    fn TreeCursor::depth(self : TreeCursor) -> Int

    The number of goto_* steps below the start node (0 at the start node).

    TreeCursor::field_name

    fn TreeCursor::field_name(self : TreeCursor) -> String?

    The node's field in its parent ("arguments", …); None at the start node.

    TreeCursor::goto_first_child

    fn TreeCursor::goto_first_child(self : TreeCursor) -> Bool

    TreeCursor::goto_first_child_for

    fn TreeCursor::goto_first_child_for(self : TreeCursor, p :
    Location
    ) -> Bool

    Move to the child whose range contains p, or else to the first child that starts after p. Where children overlap (a doc comment and its attributes), the innermost one that contains p wins, and the first in source order among equals.

    To reach Tree::node_at(p), descend while the new node contains p, and step back with goto_parent from the first one that does not: a loop that only calls goto_first_child_for goes one node too far whenever node_at(p) has children after p. (Where a port's doc comment with attributes overlaps the port declaration only in part, the descent stops at the comment, which contains node_at(p).)

    TreeCursor::goto_last_child

    fn TreeCursor::goto_last_child(self : TreeCursor) -> Bool

    TreeCursor::goto_next_sibling

    fn TreeCursor::goto_next_sibling(self : TreeCursor) -> Bool

    TreeCursor::goto_parent

    fn TreeCursor::goto_parent(self : TreeCursor) -> Bool

    TreeCursor::goto_previous_sibling

    fn TreeCursor::goto_previous_sibling(self : TreeCursor) -> Bool

    TreeCursor::new

    fn TreeCursor::new(root : NodeRef) -> TreeCursor

    A cursor at root (depth 0, no field).

    TreeCursor::node

    fn TreeCursor::node(self : TreeCursor) -> NodeRef

    The node at the cursor.

    TreeCursor::path

    fn TreeCursor::path(self : TreeCursor) -> NodePath

    The steps from the start node to the node (each frame keeps its parent's path, so this is O(1)).

    TreeCursor::reset

    fn TreeCursor::reset(self : TreeCursor, node : NodeRef) -> Unit

    Move the cursor to a new start node (depth 0).

    accept

    fn[V : Visitor] accept(root : NodeRef, visitor : V) -> Unit

    Walk root (see walk) and call one visitor method per node: functions (top-level or let) → visit_function; other declarations → visit_declaration; expressions, patterns, types → visit_expression, visit_pattern, visit_type; case branches → visit_case; imports, comments, doc attributes → visit_import, visit_comment, visit_attribute; every other node (doc comments included) → visit_other. The method's Control steers the walk; leave runs after each node's children.

    fold

    fn[A] fold(root : NodeRef, init : A, enter : (A, NodeRef) -> (A, Control), leave? : (A, NodeRef) -> A) -> A

    Walk root (see walk) with an accumulator: enter and leave take the current value and return the next one, in walk's callback order. The result is the value after the last callback. The accumulator belongs to the caller; fold does not copy it.

    kind_table

    fn kind_table() -> Array[(String, String, Array[String])]

    Every node type: (category, kind, fields), one row per kind. AGENTS.md lists the same table.

    push_events

    fn[S : EventSource, H : Handler] push_events(source : S, handler : H) -> Unit

    Pull every event from source and push it to handler: on_enter for Enter (its SkipChildren skips the node's children, its Stop ends the run) and on_leave for Leave.

    walk

    fn walk(root : NodeRef, enter : (NodeRef) -> Control, leave? : (NodeRef) -> Unit) -> Unit

    Visit root and every node below it in pre-order (source order). enter runs when a node is reached and decides what happens next; leave runs after all of a node's children, with the same node object. An explicit stack, not recursion, holds the open nodes, so trees of any depth work on every target. All traversal state belongs to this call.