oak_core/tree/red_tree.rs
1//! Red-green tree implementation with position information for incremental parsing.
2//!
3//! This module provides the "red" side of the red-green tree architecture,
4//! where red nodes contain absolute position information computed from
5//! green nodes and their offsets.
6
7use crate::tree::green_tree::{GreenNode, GreenTree};
8
9use std::range::Range;
10use triomphe::Arc;
11
12/// A red tree element with absolute position information.
13///
14/// Red trees are the position-aware representation of kind trees,
15/// computed by applying offsets to green trees. They are used for
16/// incremental parsing, error reporting, and diagnostics.
17#[derive(Debug, Clone)]
18pub enum RedTree<K: Copy> {
19 /// A red node with child elements
20 Node(RedNode<K>),
21 /// A red leaf kind
22 Leaf(RedLeaf<K>),
23}
24
25impl<K: Copy> RedTree<K> {
26 /// Returns the absolute byte span of this red tree element.
27 ///
28 /// # Returns
29 ///
30 /// A [`Range<usize>`] representing the absolute byte positions
31 /// in the source text that this element occupies.
32 #[inline]
33 pub fn span(&self) -> Range<usize> {
34 match self {
35 RedTree::Node(n) => n.span(),
36 RedTree::Leaf(t) => t.span,
37 }
38 }
39}
40
41/// A red node that wraps a green node with absolute offset information.
42///
43/// Red nodes represent kind tree nodes with computed absolute positions,
44/// making them suitable for incremental parsing and position-based operations.
45#[derive(Debug, Clone)]
46pub struct RedNode<K: Copy> {
47 /// The underlying green node that contains the structural information
48 pub green: Arc<GreenNode<K>>,
49 /// The absolute byte offset of this node in the source text
50 pub offset: usize,
51}
52
53/// A red leaf kind with absolute position information.
54///
55/// Red leaves represent individual tokens (keywords, identifiers, literals, etc.)
56/// with their absolute positions in the source text.
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct RedLeaf<K: Copy> {
59 /// The kind kind/category (e.g., keyword, identifier, literal)
60 pub kind: K,
61 /// The absolute byte span of this kind in the source text
62 pub span: Range<usize>,
63}
64
65impl<K: Copy> RedNode<K> {
66 /// Creates a new red node from a green node and offset.
67 ///
68 /// # Arguments
69 ///
70 /// * `green` - The green node containing structural information
71 /// * `offset` - The absolute byte offset in the source text
72 ///
73 /// # Returns
74 ///
75 /// A new [`RedNode`] with the given green node and offset
76 #[inline]
77 pub fn new(green: Arc<GreenNode<K>>, offset: usize) -> Self {
78 Self { green, offset }
79 }
80
81 /// Returns the absolute byte span of this red node.
82 ///
83 /// The span is computed from the node's offset and the length
84 /// of the underlying green node.
85 ///
86 /// # Returns
87 ///
88 /// A [`Range<usize>`] representing the absolute byte positions
89 #[inline]
90 pub fn span(&self) -> Range<usize> {
91 Range { start: self.offset, end: self.offset + self.green.length }
92 }
93
94 /// Gets the child element at the specified index.
95 ///
96 /// # Arguments
97 ///
98 /// * `idx` - The index of the child element to retrieve
99 ///
100 /// # Returns
101 ///
102 /// An [`Option<RedTree<K>>`] containing the child element if it exists,
103 /// or `None` if the index is out of bounds
104 pub fn child(&self, idx: usize) -> Option<RedTree<K>> {
105 let mut cur = self.offset;
106 let ch = self.green.children.get(idx)?;
107 // Calculate the starting offset of this child element
108 for c in &self.green.children[..idx] {
109 cur += c.len();
110 }
111 Some(match ch {
112 GreenTree::Node(n) => RedTree::Node(RedNode::new(Arc::clone(n), cur)),
113 GreenTree::Leaf(t) => RedTree::Leaf(RedLeaf { kind: t.kind, span: Range { start: cur, end: cur + t.length } }),
114 })
115 }
116
117 /// Returns an iterator over all child elements.
118 ///
119 /// # Returns
120 ///
121 /// A [`RedChildren<K>`] iterator that yields all child elements
122 /// in order
123 pub fn children(&self) -> RedChildren<'_, K> {
124 RedChildren::new(self)
125 }
126}
127
128// Additional methods for incremental parsing support
129impl<K: Copy> RedNode<K> {
130 /// Finds the index of the child element that contains the given absolute offset.
131 ///
132 /// This method is essential for incremental parsing, allowing efficient
133 /// location of affected regions when source text changes.
134 ///
135 /// # Arguments
136 ///
137 /// * `offset` - The absolute byte offset to search for
138 ///
139 /// # Returns
140 ///
141 /// An [`Option<usize>`] containing the child index if found, or `None`
142 /// if the offset is outside this node's span
143 pub fn child_index_at_offset(&self, offset: usize) -> Option<usize> {
144 let start = self.offset;
145 let end = self.offset + self.green.length;
146 if offset < start || offset >= end {
147 return None;
148 }
149 let mut cur = start;
150 for (i, ch) in self.green.children.iter().enumerate() {
151 let next = cur + ch.len();
152 if offset < next {
153 return Some(i);
154 }
155 cur = next;
156 }
157 None
158 }
159
160 /// Gets the absolute starting offset of the child element at the given index.
161 ///
162 /// # Arguments
163 ///
164 /// * `idx` - The index of the child element
165 ///
166 /// # Returns
167 ///
168 /// An [`Option<usize>`] containing the absolute offset if the index is valid
169 pub fn offset_of_child(&self, idx: usize) -> Option<usize> {
170 if idx >= self.green.children.len() {
171 return None;
172 }
173 let mut cur = self.offset;
174 for c in &self.green.children[..idx] {
175 cur += c.len();
176 }
177 Some(cur)
178 }
179
180 /// Collects indices of child elements that overlap with the given span.
181 ///
182 /// This method is crucial for incremental parsing, identifying which
183 /// child elements are affected by a text change.
184 ///
185 /// # Arguments
186 ///
187 /// * `span` - The byte range to check for overlaps
188 ///
189 /// # Returns
190 ///
191 /// A [`Vec<usize>`] containing indices of all overlapping child elements
192 pub fn overlapping_indices(&self, span: Range<usize>) -> Vec<usize> {
193 let mut out = Vec::new();
194 let node_start = self.offset;
195 let node_end = self.offset + self.green.length;
196 // Return empty if there's no intersection
197 if span.end <= node_start || span.start >= node_end {
198 return out;
199 }
200 let mut cur = node_start;
201 for (i, ch) in self.green.children.iter().enumerate() {
202 let ch_start = cur;
203 let ch_end = cur + ch.len();
204 // Check if ranges overlap
205 if !(ch_end <= span.start || ch_start >= span.end) {
206 out.push(i);
207 }
208 cur = ch_end;
209 }
210 out
211 }
212}
213
214/// Iterator over the child elements of a red node.
215///
216/// This iterator yields [`RedTree<K>`] elements in order, providing
217/// access to all children with their absolute position information.
218#[derive(Debug)]
219pub struct RedChildren<'a, K: Copy> {
220 node: &'a RedNode<K>,
221 index: usize,
222 offset: usize,
223}
224
225impl<'a, K: Copy> RedChildren<'a, K> {
226 fn new(node: &'a RedNode<K>) -> Self {
227 Self { node, index: 0, offset: node.offset }
228 }
229}
230
231impl<'a, K: Copy> Iterator for RedChildren<'a, K> {
232 type Item = RedTree<K>;
233
234 fn next(&mut self) -> Option<Self::Item> {
235 if self.index >= self.node.green.children.len() {
236 return None;
237 }
238 let ch = &self.node.green.children[self.index];
239 let elem = match ch {
240 GreenTree::Node(n) => RedTree::Node(RedNode::new(Arc::clone(n), self.offset)),
241 GreenTree::Leaf(t) => {
242 RedTree::Leaf(RedLeaf { kind: t.kind, span: Range { start: self.offset, end: self.offset + t.length } })
243 }
244 };
245 self.offset += ch.len();
246 self.index += 1;
247 Some(elem)
248 }
249}