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
5use crate::{
6    Language,
7    tree::green_tree::{GreenNode, GreenTree},
8};
9use core::range::Range;
10use std::fmt;
11
12/// A red tree element with absolute position information.
13pub enum RedTree<'a, L: Language> {
14    /// A red node with child elements
15    Node(RedNode<'a, L>),
16    /// A red leaf kind
17    Leaf(RedLeaf<L>),
18}
19
20// Manually implement Clone/Copy to avoid L: Copy bound
21impl<'a, L: Language> Clone for RedTree<'a, L> {
22    fn clone(&self) -> Self {
23        *self
24    }
25}
26
27impl<'a, L: Language> Copy for RedTree<'a, L> {}
28
29impl<'a, L: Language> fmt::Debug for RedTree<'a, L> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::Node(node) => fmt::Debug::fmt(node, f),
33            Self::Leaf(leaf) => fmt::Debug::fmt(leaf, f),
34        }
35    }
36}
37
38impl<'a, L: Language> PartialEq for RedTree<'a, L> {
39    fn eq(&self, other: &Self) -> bool {
40        match (self, other) {
41            (Self::Node(l0), Self::Node(r0)) => l0 == r0,
42            (Self::Leaf(l0), Self::Leaf(r0)) => l0 == r0,
43            _ => false,
44        }
45    }
46}
47
48impl<'a, L: Language> Eq for RedTree<'a, L> {}
49
50impl<'a, L: Language> RedTree<'a, L> {
51    /// Returns the absolute byte span of this red tree element.
52    #[inline]
53    pub fn span(&self) -> Range<usize> {
54        match self {
55            RedTree::Node(n) => n.span(),
56            RedTree::Leaf(t) => t.span,
57        }
58    }
59}
60
61/// A red node that wraps a green node with absolute offset information.
62pub struct RedNode<'a, L: Language> {
63    /// The underlying green node that contains the structural information
64    pub green: &'a GreenNode<'a, L>,
65    /// The absolute byte offset of this node in the source text
66    pub offset: usize,
67}
68
69// Manually implement Clone/Copy to avoid L: Copy bound
70impl<'a, L: Language> Clone for RedNode<'a, L> {
71    fn clone(&self) -> Self {
72        *self
73    }
74}
75
76impl<'a, L: Language> Copy for RedNode<'a, L> {}
77
78impl<'a, L: Language> PartialEq for RedNode<'a, L> {
79    fn eq(&self, other: &Self) -> bool {
80        self.green == other.green && self.offset == other.offset
81    }
82}
83
84impl<'a, L: Language> Eq for RedNode<'a, L> {}
85
86impl<'a, L: Language> fmt::Debug for RedNode<'a, L> {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        f.debug_struct("RedNode").field("green", &self.green).field("offset", &self.offset).finish()
89    }
90}
91
92/// A red leaf kind with absolute position information.
93pub struct RedLeaf<L: Language> {
94    /// The kind kind/category
95    pub kind: L::TokenType,
96    /// The absolute byte span of this kind in the source text
97    pub span: Range<usize>,
98}
99
100// Manually implement Clone/Copy to avoid L: Copy bound
101impl<L: Language> Clone for RedLeaf<L> {
102    fn clone(&self) -> Self {
103        *self
104    }
105}
106
107impl<L: Language> Copy for RedLeaf<L> {}
108
109impl<L: Language> PartialEq for RedLeaf<L> {
110    fn eq(&self, other: &Self) -> bool {
111        self.kind == other.kind && self.span == other.span
112    }
113}
114
115impl<L: Language> Eq for RedLeaf<L> {}
116
117impl<L: Language> fmt::Debug for RedLeaf<L> {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        f.debug_struct("RedLeaf").field("kind", &self.kind).field("span", &self.span).finish()
120    }
121}
122
123impl<'a, L: Language> RedNode<'a, L> {
124    /// Creates a new red node from a green node and offset.
125    #[inline]
126    pub fn new(green: &'a GreenNode<'a, L>, offset: usize) -> Self {
127        Self { green, offset }
128    }
129
130    /// Returns the absolute byte span of this red node.
131    #[inline]
132    pub fn span(&self) -> Range<usize> {
133        Range { start: self.offset, end: self.offset + self.green.text_len() as usize }
134    }
135
136    /// Gets the child element at the specified index.
137    pub fn child_at(&self, idx: usize) -> RedTree<'a, L> {
138        let children = self.green.children();
139        let green_child = &children[idx];
140
141        // Calculate offset by summing lengths of previous siblings
142        let mut offset = self.offset;
143        for i in 0..idx {
144            offset += children[i].len() as usize;
145        }
146
147        match green_child {
148            GreenTree::Node(n) => RedTree::Node(RedNode::new(n, offset)),
149            GreenTree::Leaf(t) => RedTree::Leaf(RedLeaf { kind: t.kind, span: Range { start: offset, end: offset + t.length as usize } }),
150        }
151    }
152
153    /// Returns an iterator over the child elements of this red node.
154    pub fn children(&self) -> RedChildren<'a, L> {
155        RedChildren { node: *self, index: 0, offset: self.offset }
156    }
157
158    /// Finds the child element at the specified absolute byte offset.
159    pub fn child_index_at_offset(&self, offset: usize) -> Option<usize> {
160        if offset < self.offset || offset >= self.offset + self.green.text_len() as usize {
161            return None;
162        }
163
164        let relative_offset = (offset - self.offset) as u32;
165        let mut current_pos = 0;
166
167        for (idx, child) in self.green.children().iter().enumerate() {
168            let len = child.len();
169            if relative_offset < current_pos + len {
170                return Some(idx);
171            }
172            current_pos += len;
173        }
174
175        None
176    }
177
178    /// Finds the child element at the specified absolute byte offset.
179    pub fn child_at_offset(&self, offset: usize) -> Option<RedTree<'a, L>> {
180        self.child_index_at_offset(offset).map(|idx| self.child_at(idx))
181    }
182}
183
184/// An iterator over the child elements of a red node.
185pub struct RedChildren<'a, L: Language> {
186    node: RedNode<'a, L>,
187    index: usize,
188    offset: usize,
189}
190
191impl<'a, L: Language> Iterator for RedChildren<'a, L> {
192    type Item = RedTree<'a, L>;
193
194    fn next(&mut self) -> Option<Self::Item> {
195        let children = self.node.green.children();
196        if self.index >= children.len() {
197            return None;
198        }
199
200        let ch = &children[self.index];
201        let offset = self.offset;
202        let elem = match ch {
203            GreenTree::Node(n) => RedTree::Node(RedNode::new(n, offset)),
204            GreenTree::Leaf(t) => RedTree::Leaf(RedLeaf { kind: t.kind, span: Range { start: offset, end: offset + t.length as usize } }),
205        };
206
207        self.offset += ch.len() as usize;
208        self.index += 1;
209        Some(elem)
210    }
211}