Skip to main content

eure_tree/
tree.rs

1mod span;
2
3use ahash::HashMap;
4use std::{collections::BTreeMap, convert::Infallible};
5use thiserror::Error;
6
7pub use span::*;
8
9use crate::{
10    CstConstructError,
11    node_kind::{NodeKind, NonTerminalKind, TerminalKind},
12    nodes::{BlockComment, LineComment, NewLine, RootHandle, Whitespace},
13    visitor::{BuiltinTerminalVisitor, CstVisitor},
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
17/// A dynamic token id that provided by the user land.
18pub struct DynamicTokenId(pub u32);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum CstNodeData<T, Nt> {
22    /// A terminal node with its kind and span
23    Terminal { kind: T, data: TerminalData },
24    /// A non-terminal node with its kind
25    NonTerminal { kind: Nt, data: NonTerminalData },
26}
27
28impl<T, Nt> CstNodeData<T, Nt> {
29    pub fn new_terminal(kind: T, data: TerminalData) -> Self {
30        Self::Terminal { kind, data }
31    }
32
33    pub fn new_non_terminal(kind: Nt, data: NonTerminalData) -> Self {
34        Self::NonTerminal { kind, data }
35    }
36
37    pub fn is_terminal(&self) -> bool {
38        matches!(self, CstNodeData::Terminal { .. })
39    }
40
41    pub fn is_non_terminal(&self) -> bool {
42        matches!(self, CstNodeData::NonTerminal { .. })
43    }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub enum TerminalData {
48    Input(InputSpan),
49    Dynamic(DynamicTokenId),
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub enum NonTerminalData {
54    Input(InputSpan),
55    Dynamic,
56}
57
58impl<T, Nt> CstNodeData<T, Nt>
59where
60    T: Copy,
61    Nt: Copy,
62{
63    pub fn node_kind(&self) -> NodeKind<T, Nt> {
64        match self {
65            CstNodeData::Terminal { kind, .. } => NodeKind::Terminal(*kind),
66            CstNodeData::NonTerminal { kind, .. } => NodeKind::NonTerminal(*kind),
67        }
68    }
69}
70
71impl<T, Nt> CstNodeData<T, Nt>
72where
73    T: PartialEq + Copy,
74    Nt: PartialEq + Copy,
75{
76    pub fn expected_terminal_or_error(
77        &self,
78        node: CstNodeId,
79        expected: T,
80    ) -> Result<(T, TerminalData), ViewConstructionError<T, Nt>> {
81        match self {
82            CstNodeData::Terminal { kind, data } if *kind == expected => Ok((*kind, *data)),
83            _ => Err(ViewConstructionError::UnexpectedNode {
84                node,
85                data: *self,
86                expected_kind: NodeKind::Terminal(expected),
87            }),
88        }
89    }
90
91    pub fn expected_non_terminal_or_error(
92        &self,
93        node: CstNodeId,
94        expected: Nt,
95    ) -> Result<(Nt, NonTerminalData), ViewConstructionError<T, Nt>> {
96        match self {
97            CstNodeData::NonTerminal { kind, data } if *kind == expected => Ok((*kind, *data)),
98            _ => Err(ViewConstructionError::UnexpectedNode {
99                node,
100                data: *self,
101                expected_kind: NodeKind::NonTerminal(expected),
102            }),
103        }
104    }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
108pub struct CstNodeId(pub usize);
109
110impl std::fmt::Display for CstNodeId {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        write!(f, "{}", self.0)
113    }
114}
115
116/// A generic concrete syntax tree with stable child ordering
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub struct ConcreteSyntaxTree<T, Nt> {
119    nodes: Vec<CstNodeData<T, Nt>>,
120    children: HashMap<CstNodeId, Vec<CstNodeId>>,
121    parent: HashMap<CstNodeId, CstNodeId>,
122    dynamic_tokens: BTreeMap<DynamicTokenId, String>,
123    next_dynamic_token_id: u32,
124    root: CstNodeId,
125}
126
127impl<T, Nt> ConcreteSyntaxTree<T, Nt>
128where
129    T: Clone,
130    Nt: Clone,
131{
132    pub fn new(root_data: CstNodeData<T, Nt>) -> Self {
133        let nodes = vec![root_data];
134        let root = CstNodeId(0);
135
136        Self {
137            nodes,
138            children: HashMap::default(),
139            parent: HashMap::default(),
140            dynamic_tokens: BTreeMap::new(),
141            next_dynamic_token_id: 0,
142            root,
143        }
144    }
145
146    pub fn root(&self) -> CstNodeId {
147        self.root
148    }
149
150    pub fn set_root(&mut self, new_root: CstNodeId) {
151        self.root = new_root;
152    }
153
154    pub fn change_parent(&mut self, id: CstNodeId, new_parent: CstNodeId) {
155        // Remove from old parent's children
156        if let Some(old_parent) = self.parent.get(&id).copied()
157            && let Some(children) = self.children.get_mut(&old_parent)
158        {
159            children.retain(|&child| child != id);
160        }
161
162        // Add to new parent's children
163        self.children.entry(new_parent).or_default().push(id);
164        self.parent.insert(id, new_parent);
165    }
166
167    pub fn add_node(&mut self, data: CstNodeData<T, Nt>) -> CstNodeId {
168        let id = CstNodeId(self.nodes.len());
169        self.nodes.push(data);
170        id
171    }
172
173    pub fn add_node_with_parent(
174        &mut self,
175        data: CstNodeData<T, Nt>,
176        parent: CstNodeId,
177    ) -> CstNodeId {
178        let node = self.add_node(data);
179        self.add_child(parent, node);
180        node
181    }
182
183    pub fn add_child(&mut self, parent: CstNodeId, child: CstNodeId) {
184        self.children.entry(parent).or_default().push(child);
185        self.parent.insert(child, parent);
186    }
187
188    pub fn has_no_children(&self, node: CstNodeId) -> bool {
189        self.children
190            .get(&node)
191            .is_none_or(|children| children.is_empty())
192    }
193
194    pub fn children(&self, node: CstNodeId) -> impl DoubleEndedIterator<Item = CstNodeId> + '_ {
195        self.children
196            .get(&node)
197            .into_iter()
198            .flat_map(|children| children.iter().copied())
199    }
200
201    pub fn parent(&self, node: CstNodeId) -> Option<CstNodeId> {
202        self.parent.get(&node).copied()
203    }
204
205    pub fn get_str<'a: 'c, 'b: 'c, 'c>(
206        &'a self,
207        terminal: TerminalData,
208        input: &'b str,
209    ) -> Option<&'c str> {
210        match terminal {
211            TerminalData::Input(span) => Some(span.as_str(input)),
212            TerminalData::Dynamic(id) => self.dynamic_token(id),
213        }
214    }
215
216    pub fn dynamic_token(&self, id: DynamicTokenId) -> Option<&str> {
217        self.dynamic_tokens.get(&id).map(|s| s.as_str())
218    }
219
220    pub fn update_node(
221        &mut self,
222        id: CstNodeId,
223        data: CstNodeData<T, Nt>,
224    ) -> Option<CstNodeData<T, Nt>> {
225        if id.0 < self.nodes.len() {
226            Some(std::mem::replace(&mut self.nodes[id.0], data))
227        } else {
228            None
229        }
230    }
231
232    pub fn update_children(
233        &mut self,
234        id: CstNodeId,
235        new_children: impl IntoIterator<Item = CstNodeId>,
236    ) {
237        let new_children: Vec<_> = new_children.into_iter().collect();
238
239        // Update parent pointers for old children (remove this parent)
240        if let Some(old_children) = self.children.get(&id) {
241            for &child in old_children {
242                self.parent.remove(&child);
243            }
244        }
245
246        // Update parent pointers for new children
247        for &child in &new_children {
248            self.parent.insert(child, id);
249        }
250
251        // Set new children
252        if new_children.is_empty() {
253            self.children.remove(&id);
254        } else {
255            self.children.insert(id, new_children);
256        }
257    }
258
259    pub fn insert_dynamic_terminal(&mut self, data: impl Into<String>) -> DynamicTokenId {
260        let id = DynamicTokenId(self.next_dynamic_token_id);
261        self.dynamic_tokens.insert(id, data.into());
262        self.next_dynamic_token_id += 1;
263        id
264    }
265}
266
267impl<T, Nt> ConcreteSyntaxTree<T, Nt>
268where
269    T: Copy,
270    Nt: Copy,
271{
272    pub fn node_data(&self, node: CstNodeId) -> Option<CstNodeData<T, Nt>> {
273        self.nodes.get(node.0).copied()
274    }
275
276    /// Remove a node from the tree by removing it from all parent-child relationships.
277    /// The node data remains in the vector but becomes unreachable through tree traversal.
278    pub fn remove_node(&mut self, id: CstNodeId) {
279        // Remove from parent's children list
280        if let Some(parent_id) = self.parent.remove(&id)
281            && let Some(parent_children) = self.children.get_mut(&parent_id)
282        {
283            parent_children.retain(|&child| child != id);
284        }
285
286        // Remove children mapping (but don't delete child nodes recursively)
287        self.children.remove(&id);
288    }
289}
290
291impl TerminalKind {
292    fn auto_ws_is_off(&self, _index: usize) -> bool {
293        matches!(
294            self,
295            TerminalKind::Ws | TerminalKind::GrammarNewline | TerminalKind::Text
296        )
297    }
298}
299
300impl ConcreteSyntaxTree<TerminalKind, NonTerminalKind> {
301    pub fn get_non_terminal(
302        &self,
303        id: CstNodeId,
304        kind: NonTerminalKind,
305    ) -> Result<NonTerminalData, CstConstructError> {
306        let node_data = self
307            .node_data(id)
308            .ok_or(ViewConstructionError::NodeIdNotFound { node: id })?;
309        let (_, data) = node_data.expected_non_terminal_or_error(id, kind)?;
310        Ok(data)
311    }
312
313    pub fn get_terminal(
314        &self,
315        id: CstNodeId,
316        kind: TerminalKind,
317    ) -> Result<TerminalData, CstConstructError> {
318        let node_data = self
319            .node_data(id)
320            .ok_or(ViewConstructionError::NodeIdNotFound { node: id })?;
321        let (_, data) = node_data.expected_terminal_or_error(id, kind)?;
322        Ok(data)
323    }
324
325    pub fn collect_nodes<
326        'v,
327        const N: usize,
328        V: BuiltinTerminalVisitor<E, F>,
329        O,
330        E,
331        F: CstFacade,
332    >(
333        &self,
334        facade: &F,
335        parent: CstNodeId,
336        nodes: [NodeKind<TerminalKind, NonTerminalKind>; N],
337        mut visitor: impl FnMut(
338            [CstNodeId; N],
339            &'v mut V,
340        ) -> Result<(O, &'v mut V), CstConstructError<E>>,
341        visit_ignored: &'v mut V,
342    ) -> Result<O, CstConstructError<E>> {
343        let children = self.children(parent).collect::<Vec<_>>();
344        let mut children = children.into_iter();
345        let mut result = Vec::with_capacity(N);
346        let mut ignored = Vec::with_capacity(N);
347        'outer: for expected_kind in nodes {
348            'inner: for (idx, child) in children.by_ref().enumerate() {
349                let child_data = self
350                    .node_data(child)
351                    .ok_or(ViewConstructionError::NodeIdNotFound { node: child })?;
352                match child_data {
353                    CstNodeData::Terminal { kind, data } => {
354                        if NodeKind::Terminal(kind) == expected_kind {
355                            result.push(child);
356                            continue 'outer;
357                        } else if kind.is_builtin_whitespace() || kind.is_builtin_new_line() {
358                            if kind.auto_ws_is_off(idx) {
359                                return Err(ViewConstructionError::UnexpectedNode {
360                                    node: child,
361                                    data: child_data,
362                                    expected_kind,
363                                });
364                            }
365                            ignored.push((child, kind, data));
366                            continue 'inner;
367                        } else if kind.is_builtin_line_comment() || kind.is_builtin_block_comment()
368                        {
369                            ignored.push((child, kind, data));
370                            continue 'inner;
371                        } else {
372                            return Err(ViewConstructionError::UnexpectedNode {
373                                node: child,
374                                data: child_data,
375                                expected_kind,
376                            });
377                        }
378                    }
379                    CstNodeData::NonTerminal { kind, .. } => {
380                        if NodeKind::NonTerminal(kind) == expected_kind {
381                            result.push(child);
382                            continue 'outer;
383                        } else {
384                            return Err(ViewConstructionError::UnexpectedNode {
385                                node: child,
386                                data: child_data,
387                                expected_kind,
388                            });
389                        }
390                    }
391                }
392            }
393            return Err(ViewConstructionError::UnexpectedEndOfChildren { parent });
394        }
395        for (child, kind, data) in ignored {
396            match kind {
397                TerminalKind::Whitespace => visit_ignored.visit_builtin_whitespace_terminal(
398                    Whitespace(child),
399                    data,
400                    facade,
401                )?,
402                TerminalKind::NewLine => {
403                    visit_ignored.visit_builtin_new_line_terminal(NewLine(child), data, facade)?
404                }
405                TerminalKind::LineComment => visit_ignored.visit_builtin_line_comment_terminal(
406                    LineComment(child),
407                    data,
408                    facade,
409                )?,
410                TerminalKind::BlockComment => visit_ignored.visit_builtin_block_comment_terminal(
411                    BlockComment(child),
412                    data,
413                    facade,
414                )?,
415                _ => unreachable!(),
416            }
417        }
418        let (result, visit_ignored) = visitor(
419            result
420                .try_into()
421                .expect("Result should have the same length as nodes"),
422            visit_ignored,
423        )?;
424        for child in children.by_ref() {
425            let child_data = self
426                .node_data(child)
427                .ok_or(ViewConstructionError::NodeIdNotFound { node: child })?;
428            match child_data {
429                CstNodeData::Terminal { kind, data } => {
430                    if kind.is_builtin_terminal() {
431                        match kind {
432                            TerminalKind::Whitespace => visit_ignored
433                                .visit_builtin_whitespace_terminal(
434                                    Whitespace(child),
435                                    data,
436                                    facade,
437                                )?,
438                            TerminalKind::NewLine => visit_ignored
439                                .visit_builtin_new_line_terminal(NewLine(child), data, facade)?,
440                            TerminalKind::LineComment => visit_ignored
441                                .visit_builtin_line_comment_terminal(
442                                    LineComment(child),
443                                    data,
444                                    facade,
445                                )?,
446                            TerminalKind::BlockComment => visit_ignored
447                                .visit_builtin_block_comment_terminal(
448                                    BlockComment(child),
449                                    data,
450                                    facade,
451                                )?,
452                            _ => unreachable!(),
453                        }
454                    } else {
455                        return Err(ViewConstructionError::UnexpectedNode {
456                            node: child,
457                            data: child_data,
458                            expected_kind: NodeKind::Terminal(kind),
459                        });
460                    }
461                }
462                CstNodeData::NonTerminal { kind, .. } => {
463                    return Err(ViewConstructionError::UnexpectedNode {
464                        node: child,
465                        data: child_data,
466                        expected_kind: NodeKind::NonTerminal(kind),
467                    });
468                }
469            }
470        }
471        Ok(result)
472    }
473
474    pub fn root_handle(&self) -> RootHandle {
475        RootHandle(self.root())
476    }
477
478    pub fn visit_from_root<V: CstVisitor<Self>>(&self, visitor: &mut V) -> Result<(), V::Error> {
479        visitor.visit_root_handle(self.root_handle(), self)
480    }
481}
482
483pub trait CstFacade: Sized {
484    fn get_str<'a: 'c, 'b: 'c, 'c>(
485        &'a self,
486        terminal: TerminalData,
487        input: &'b str,
488    ) -> Option<&'c str>;
489
490    fn node_data(&self, node: CstNodeId) -> Option<CstNodeData<TerminalKind, NonTerminalKind>>;
491
492    fn has_no_children(&self, node: CstNodeId) -> bool;
493
494    fn children(&self, node: CstNodeId) -> impl DoubleEndedIterator<Item = CstNodeId>;
495
496    fn get_terminal(
497        &self,
498        node: CstNodeId,
499        kind: TerminalKind,
500    ) -> Result<TerminalData, CstConstructError>;
501
502    fn get_non_terminal(
503        &self,
504        node: CstNodeId,
505        kind: NonTerminalKind,
506    ) -> Result<NonTerminalData, CstConstructError>;
507
508    fn collect_nodes<'v, const N: usize, V: BuiltinTerminalVisitor<E, Self>, O, E>(
509        &self,
510        parent: CstNodeId,
511        nodes: [NodeKind<TerminalKind, NonTerminalKind>; N],
512        visitor: impl FnMut([CstNodeId; N], &'v mut V) -> Result<(O, &'v mut V), CstConstructError<E>>,
513        visit_ignored: &'v mut V,
514    ) -> Result<O, CstConstructError<E>>;
515
516    fn dynamic_token(&self, id: DynamicTokenId) -> Option<&str>;
517
518    fn parent(&self, node: CstNodeId) -> Option<CstNodeId>;
519
520    fn root_handle(&self) -> RootHandle;
521
522    /// Returns the string representation of a terminal. Returns None if the terminal is a dynamic token and not found.
523    fn get_terminal_str<'a: 'c, 'b: 'c, 'c, T: TerminalHandle>(
524        &'a self,
525        input: &'b str,
526        handle: T,
527    ) -> Result<Result<&'c str, DynamicTokenId>, CstConstructError> {
528        let data = self.get_terminal(handle.node_id(), handle.kind())?;
529        match data {
530            TerminalData::Input(input_span) => Ok(Ok(
531                &input[input_span.start as usize..input_span.end as usize]
532            )),
533            TerminalData::Dynamic(id) => Ok(self.dynamic_token(id).ok_or(id)),
534        }
535    }
536
537    /// Returns a span that excludes leading and trailing trivia (whitespace, newlines, comments).
538    ///
539    /// For terminal nodes:
540    /// - Always returns the input span (even for trivia terminals like whitespace/comments)
541    /// - Returns None only for dynamic terminals
542    ///
543    /// For non-terminal nodes:
544    /// - Recursively finds the first and last non-trivia descendant spans
545    /// - Returns the merged span of those two endpoints
546    /// - Falls back to the original span if all descendants are trivia
547    ///
548    /// This is useful when you want to get the "meaningful" span of a syntax node,
549    /// excluding any surrounding whitespace or comments.
550    fn span(&self, node_id: CstNodeId) -> Option<InputSpan> {
551        match self.node_data(node_id)? {
552            CstNodeData::Terminal { data, .. } => {
553                // Always return the span for terminals (including trivia)
554                match data {
555                    TerminalData::Input(span) => Some(span),
556                    TerminalData::Dynamic(_) => None,
557                }
558            }
559            CstNodeData::NonTerminal { data, .. } => {
560                // Find first non-trivia span
561                let first_span = self
562                    .children(node_id)
563                    .find_map(|child| self.find_first_non_trivia_span(child));
564
565                // Find last non-trivia span
566                let last_span = self
567                    .children(node_id)
568                    .rev()
569                    .find_map(|child| self.find_last_non_trivia_span(child));
570
571                match (first_span, last_span) {
572                    (Some(first), Some(last)) => Some(first.merge(last)),
573                    (Some(span), None) | (None, Some(span)) => Some(span),
574                    (None, None) => {
575                        // All children are trivia or no children - fall back to original span
576                        match data {
577                            NonTerminalData::Input(span) if span != InputSpan::EMPTY => Some(span),
578                            _ => None,
579                        }
580                    }
581                }
582            }
583        }
584    }
585
586    /// Returns the span of a node, including the trivia.
587    fn concrete_span(&self, node_id: CstNodeId) -> Option<InputSpan> {
588        match self.node_data(node_id)? {
589            CstNodeData::NonTerminal {
590                data: NonTerminalData::Input(span),
591                ..
592            } => Some(span),
593            CstNodeData::Terminal { data, .. } => match data {
594                TerminalData::Input(span) => Some(span),
595                TerminalData::Dynamic(_) => None,
596            },
597            _ => None,
598        }
599    }
600
601    /// Helper: finds the first non-trivia span by depth-first search from the start.
602    fn find_first_non_trivia_span(&self, node_id: CstNodeId) -> Option<InputSpan> {
603        match self.node_data(node_id)? {
604            CstNodeData::Terminal { kind, data } => {
605                if kind.is_builtin_terminal() {
606                    None
607                } else {
608                    match data {
609                        TerminalData::Input(span) => Some(span),
610                        TerminalData::Dynamic(_) => None,
611                    }
612                }
613            }
614            CstNodeData::NonTerminal { .. } => self
615                .children(node_id)
616                .find_map(|child| self.find_first_non_trivia_span(child)),
617        }
618    }
619
620    /// Helper: finds the last non-trivia span by depth-first search from the end.
621    fn find_last_non_trivia_span(&self, node_id: CstNodeId) -> Option<InputSpan> {
622        match self.node_data(node_id)? {
623            CstNodeData::Terminal { kind, data } => {
624                if kind.is_builtin_terminal() {
625                    None
626                } else {
627                    match data {
628                        TerminalData::Input(span) => Some(span),
629                        TerminalData::Dynamic(_) => None,
630                    }
631                }
632            }
633            CstNodeData::NonTerminal { .. } => self
634                .children(node_id)
635                .rev()
636                .find_map(|child| self.find_last_non_trivia_span(child)),
637        }
638    }
639}
640
641impl CstFacade for ConcreteSyntaxTree<TerminalKind, NonTerminalKind> {
642    fn get_str<'a: 'c, 'b: 'c, 'c>(
643        &'a self,
644        terminal: TerminalData,
645        input: &'b str,
646    ) -> Option<&'c str> {
647        ConcreteSyntaxTree::get_str(self, terminal, input)
648    }
649
650    fn node_data(&self, node: CstNodeId) -> Option<CstNodeData<TerminalKind, NonTerminalKind>> {
651        ConcreteSyntaxTree::node_data(self, node)
652    }
653
654    fn has_no_children(&self, node: CstNodeId) -> bool {
655        ConcreteSyntaxTree::has_no_children(self, node)
656    }
657
658    fn children(&self, node: CstNodeId) -> impl DoubleEndedIterator<Item = CstNodeId> {
659        ConcreteSyntaxTree::children(self, node)
660    }
661
662    fn get_terminal(
663        &self,
664        node: CstNodeId,
665        kind: TerminalKind,
666    ) -> Result<TerminalData, CstConstructError> {
667        ConcreteSyntaxTree::get_terminal(self, node, kind)
668    }
669
670    fn get_non_terminal(
671        &self,
672        node: CstNodeId,
673        kind: NonTerminalKind,
674    ) -> Result<NonTerminalData, CstConstructError> {
675        ConcreteSyntaxTree::get_non_terminal(self, node, kind)
676    }
677
678    fn collect_nodes<'v, const N: usize, V: BuiltinTerminalVisitor<E, Self>, O, E>(
679        &self,
680        parent: CstNodeId,
681        nodes: [NodeKind<TerminalKind, NonTerminalKind>; N],
682        visitor: impl FnMut([CstNodeId; N], &'v mut V) -> Result<(O, &'v mut V), CstConstructError<E>>,
683        visit_ignored: &'v mut V,
684    ) -> Result<O, CstConstructError<E>> {
685        ConcreteSyntaxTree::collect_nodes(self, self, parent, nodes, visitor, visit_ignored)
686    }
687
688    fn dynamic_token(&self, id: DynamicTokenId) -> Option<&str> {
689        ConcreteSyntaxTree::dynamic_token(self, id)
690    }
691
692    fn parent(&self, node: CstNodeId) -> Option<CstNodeId> {
693        ConcreteSyntaxTree::parent(self, node)
694    }
695
696    fn root_handle(&self) -> RootHandle {
697        ConcreteSyntaxTree::root_handle(self)
698    }
699}
700
701#[derive(Debug, Clone, Error)]
702/// Error that occurs when constructing a view from a [NonTerminalHandle].
703pub enum ViewConstructionError<T, Nt, E = Infallible> {
704    /// Expected a specific kind of terminal node, but got an invalid node
705    #[error("Unexpected node for expected kind: {expected_kind:?} but got {data:?}")]
706    UnexpectedNode {
707        /// The index of the node.
708        node: CstNodeId,
709        /// The data of the node.
710        data: CstNodeData<T, Nt>,
711        /// The expected kind.
712        expected_kind: NodeKind<T, Nt>,
713    },
714    /// Expected an extra node, but got an invalid node
715    #[error("Unexpected extra node")]
716    UnexpectedExtraNode {
717        /// The index of the node.
718        node: CstNodeId,
719    },
720    /// Unexpected end of children
721    #[error("Unexpected end of children")]
722    UnexpectedEndOfChildren {
723        /// The index of the node.
724        parent: CstNodeId,
725    },
726    /// Unexpected empty children for a non-terminal
727    #[error("Unexpected empty children for a non-terminal: {node}")]
728    UnexpectedEmptyChildren {
729        /// The index of the node.
730        node: CstNodeId,
731    },
732    /// The node ID not found in the tree
733    #[error("Node ID not found in the tree: {node}")]
734    NodeIdNotFound {
735        /// The index of the node.
736        node: CstNodeId,
737    },
738    /// Error that occurs when constructing a view from a [NonTerminalHandle].
739    #[error(transparent)]
740    Error(#[from] E),
741}
742
743impl<T, Nt, E> ViewConstructionError<T, Nt, E> {
744    pub fn extract_error(self) -> Result<E, ViewConstructionError<T, Nt, Infallible>> {
745        match self {
746            ViewConstructionError::Error(e) => Ok(e),
747            ViewConstructionError::UnexpectedNode {
748                node,
749                data,
750                expected_kind,
751            } => Err(ViewConstructionError::UnexpectedNode {
752                node,
753                data,
754                expected_kind,
755            }),
756            ViewConstructionError::UnexpectedExtraNode { node } => {
757                Err(ViewConstructionError::UnexpectedExtraNode { node })
758            }
759            ViewConstructionError::UnexpectedEndOfChildren { parent } => {
760                Err(ViewConstructionError::UnexpectedEndOfChildren { parent })
761            }
762            ViewConstructionError::UnexpectedEmptyChildren { node } => {
763                Err(ViewConstructionError::UnexpectedEmptyChildren { node })
764            }
765            ViewConstructionError::NodeIdNotFound { node } => {
766                Err(ViewConstructionError::NodeIdNotFound { node })
767            }
768        }
769    }
770}
771
772impl<T, Nt> ViewConstructionError<T, Nt, Infallible> {
773    pub fn into_any_error<E>(self) -> ViewConstructionError<T, Nt, E> {
774        match self {
775            ViewConstructionError::UnexpectedNode {
776                node,
777                data,
778                expected_kind,
779            } => ViewConstructionError::UnexpectedNode {
780                node,
781                data,
782                expected_kind,
783            },
784            ViewConstructionError::UnexpectedExtraNode { node } => {
785                ViewConstructionError::UnexpectedExtraNode { node }
786            }
787            ViewConstructionError::UnexpectedEndOfChildren { parent } => {
788                ViewConstructionError::UnexpectedEndOfChildren { parent }
789            }
790            ViewConstructionError::UnexpectedEmptyChildren { node } => {
791                ViewConstructionError::UnexpectedEmptyChildren { node }
792            }
793            ViewConstructionError::NodeIdNotFound { node } => {
794                ViewConstructionError::NodeIdNotFound { node }
795            }
796        }
797    }
798}
799
800impl<T, Nt> ViewConstructionError<T, Nt, Infallible>
801where
802    T: Copy,
803    Nt: Copy,
804{
805    pub fn unexpected_node(&self) -> Option<UnexpectedNode<T, Nt>> {
806        match self {
807            ViewConstructionError::UnexpectedNode {
808                node,
809                data,
810                expected_kind,
811            } => Some(UnexpectedNode {
812                node: *node,
813                data: *data,
814                expected_kind: *expected_kind,
815            }),
816            _ => None,
817        }
818    }
819}
820
821#[derive(Debug, Clone, Copy, PartialEq, Eq)]
822pub struct UnexpectedNode<T, Nt> {
823    node: CstNodeId,
824    data: CstNodeData<T, Nt>,
825    expected_kind: NodeKind<T, Nt>,
826}
827
828struct DummyTerminalVisitor;
829
830impl<F: CstFacade> CstVisitor<F> for DummyTerminalVisitor {
831    type Error = Infallible;
832    fn visit_new_line_terminal(
833        &mut self,
834        _terminal: crate::nodes::NewLine,
835        _data: TerminalData,
836        _tree: &F,
837    ) -> Result<(), Self::Error> {
838        Ok(())
839    }
840
841    fn visit_whitespace_terminal(
842        &mut self,
843        _terminal: crate::nodes::Whitespace,
844        _data: TerminalData,
845        _tree: &F,
846    ) -> Result<(), Self::Error> {
847        Ok(())
848    }
849
850    fn visit_line_comment_terminal(
851        &mut self,
852        _terminal: crate::nodes::LineComment,
853        _data: TerminalData,
854        _tree: &F,
855    ) -> Result<(), Self::Error> {
856        Ok(())
857    }
858
859    fn visit_block_comment_terminal(
860        &mut self,
861        _terminal: crate::nodes::BlockComment,
862        _data: TerminalData,
863        _tree: &F,
864    ) -> Result<(), Self::Error> {
865        Ok(())
866    }
867}
868
869pub trait TerminalHandle {
870    /// Node ID of the terminal.
871    fn node_id(&self) -> CstNodeId;
872    /// Kind of the terminal.
873    fn kind(&self) -> TerminalKind;
874    /// Data of the terminal.
875    fn get_data<F: CstFacade>(&self, tree: &F) -> Result<TerminalData, CstConstructError> {
876        tree.get_terminal(self.node_id(), self.kind())
877    }
878}
879
880/// A trait that all generated non-terminal handles implements.
881pub trait NonTerminalHandle: Sized {
882    /// The type of the view for this non-terminal.
883    type View;
884
885    /// Node ID of the non-terminal.
886    fn node_id(&self) -> CstNodeId;
887
888    /// Create a new non-terminal handle from a node.
889    fn new<F: CstFacade>(index: CstNodeId, tree: &F) -> Result<Self, CstConstructError> {
890        Self::new_with_visit(index, tree, &mut DummyTerminalVisitor)
891    }
892
893    fn new_with_visit<F: CstFacade, E>(
894        index: CstNodeId,
895        tree: &F,
896        visit_ignored: &mut impl BuiltinTerminalVisitor<E, F>,
897    ) -> Result<Self, CstConstructError<E>>;
898
899    /// Get the view of the non-terminal.
900    fn get_view<C: CstFacade>(&self, tree: &C) -> Result<Self::View, CstConstructError> {
901        self.get_view_with_visit(
902            tree,
903            |view, visit_ignored| (view, visit_ignored),
904            &mut DummyTerminalVisitor,
905        )
906    }
907
908    /// Get the view of the non-terminal.
909    fn get_view_with_visit<'v, F: CstFacade, V: BuiltinTerminalVisitor<E, F>, O, E>(
910        &self,
911        tree: &F,
912        visit: impl FnMut(Self::View, &'v mut V) -> (O, &'v mut V),
913        visit_ignored: &'v mut V,
914    ) -> Result<O, CstConstructError<E>>;
915
916    /// Get the kind of the non-terminal.
917    fn kind(&self) -> NonTerminalKind;
918}
919
920/// A trait that generated recursive views implements.
921pub trait RecursiveView<F: CstFacade> {
922    /// The type of the item in the view.
923    type Item;
924    fn get_all(&self, tree: &F) -> Result<Vec<Self::Item>, CstConstructError> {
925        self.get_all_with_visit(tree, &mut DummyTerminalVisitor)
926    }
927
928    fn get_all_with_visit<E>(
929        &self,
930        tree: &F,
931        visit_ignored: &mut impl BuiltinTerminalVisitor<E, F>,
932    ) -> Result<Vec<Self::Item>, CstConstructError<E>>;
933}