ast_lang/node.rs
1//! The trait every AST node implements.
2
3use arena_lang::Id;
4use span_lang::Span;
5
6/// The contract a language's syntax-tree node satisfies so the generic traversals
7/// in this crate can walk and rebuild it.
8///
9/// ast-lang owns no grammar: a language defines its own node type — almost always
10/// a single `enum` with a variant per syntactic form — stores its nodes in an
11/// [`Arena`](arena_lang::Arena), and wires the tree with [`Id`] handles. Implementing
12/// `Node` for that type is what lets [`walk`](crate::walk) and
13/// [`transform`](crate::transform) operate on it without knowing what the variants
14/// are.
15///
16/// The contract is three operations, and nothing more:
17///
18/// - [`span`](Node::span) — the byte range of source this node covers.
19/// - [`each_child`](Node::each_child) — report the node's direct child handles, in
20/// source order. Read traversal is built on this.
21/// - [`map_children`](Node::map_children) — rebuild the node with each child handle
22/// replaced by another, preserving everything else. Rewriting is built on this.
23///
24/// The two traversal operations are kept separate so a leaf node — one with no
25/// children — is an empty `each_child` and a plain clone in `map_children`.
26///
27/// # Examples
28///
29/// A minimal expression tree. The node carries its span and its child handles; the
30/// three methods just thread those handles through.
31///
32/// ```
33/// use ast_lang::{Id, Node, Span};
34///
35/// enum Expr {
36/// Lit(i64, Span),
37/// Neg(Id<Expr>, Span),
38/// Add(Id<Expr>, Id<Expr>, Span),
39/// }
40///
41/// impl Node for Expr {
42/// fn span(&self) -> Span {
43/// match self {
44/// Expr::Lit(_, s) | Expr::Neg(_, s) | Expr::Add(_, _, s) => *s,
45/// }
46/// }
47///
48/// fn each_child(&self, f: &mut dyn FnMut(Id<Self>)) {
49/// match self {
50/// Expr::Lit(..) => {}
51/// Expr::Neg(a, _) => f(*a),
52/// Expr::Add(a, b, _) => {
53/// f(*a);
54/// f(*b);
55/// }
56/// }
57/// }
58///
59/// fn map_children(&self, f: &mut dyn FnMut(Id<Self>) -> Id<Self>) -> Self {
60/// match self {
61/// Expr::Lit(v, s) => Expr::Lit(*v, *s),
62/// Expr::Neg(a, s) => Expr::Neg(f(*a), *s),
63/// Expr::Add(a, b, s) => Expr::Add(f(*a), f(*b), *s),
64/// }
65/// }
66/// }
67/// ```
68pub trait Node: Sized {
69 /// Returns the byte range of source this node covers.
70 ///
71 /// A synthetic node with no source of its own returns an empty span (for
72 /// example [`Span::empty`](span_lang::Span::empty) at the insertion point);
73 /// every node has a span so a later pass can always point a diagnostic at it.
74 fn span(&self) -> Span;
75
76 /// Calls `f` once with each direct child handle, in source order.
77 ///
78 /// "Direct" means one level down — a child reports its own children when it is
79 /// visited in turn. A leaf node calls `f` zero times. The order `f` is called
80 /// in is the order the children appear in the source, which is the order
81 /// [`walk`](crate::walk) visits them.
82 fn each_child(&self, f: &mut dyn FnMut(Id<Self>));
83
84 /// Rebuilds this node with each child handle `c` replaced by `f(c)`,
85 /// preserving the span and every non-child field.
86 ///
87 /// This is the one language-specific step of a [`transform`](crate::transform):
88 /// the machinery supplies an `f` that maps each old child handle to its rebuilt
89 /// counterpart, and this method threads those new handles back into a fresh
90 /// node. A leaf node ignores `f` and returns a copy of itself.
91 fn map_children(&self, f: &mut dyn FnMut(Id<Self>) -> Id<Self>) -> Self;
92}