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}