Skip to main content

eure_parol/
tree.rs

1use eure_tree::{
2    Cst,
3    node_kind::{NonTerminalKind, TerminalKind},
4    tree::{ConcreteSyntaxTree, CstNodeData, CstNodeId, InputSpan, NonTerminalData, TerminalData},
5};
6use parol_runtime::{ParolError, Token, parser::parse_tree_type::TreeConstruct};
7
8/// Eure-specific tree builder that handles the peculiarities of the Eure grammar,
9/// particularly the reversed ordering of list elements
10#[derive(Debug, Clone)]
11pub struct CstBuilder {
12    tree: ConcreteSyntaxTree<TerminalKind, NonTerminalKind>,
13    node_stack: Vec<NodeStackItem>,
14    root_node: Option<CstNodeId>,
15}
16
17#[derive(Debug, Clone)]
18struct NodeStackItem {
19    node: CstNodeId,
20    span: InputSpan,
21    children: Vec<CstNodeId>,
22}
23
24impl Default for CstBuilder {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl CstBuilder {
31    pub fn new() -> Self {
32        // Create a temporary root node that we'll replace later
33        let temp_root_data =
34            CstNodeData::new_non_terminal(NonTerminalKind::Root, NonTerminalData::Dynamic);
35        Self {
36            tree: ConcreteSyntaxTree::new(temp_root_data),
37            node_stack: Vec::new(),
38            root_node: None,
39        }
40    }
41
42    // Adds a terminal node to the current non-terminal in the stack
43    fn add_terminal_node(&mut self, kind: TerminalKind, span: InputSpan) -> CstNodeId {
44        let node = self.tree.add_node(CstNodeData::Terminal {
45            kind,
46            data: TerminalData::Input(span),
47        });
48
49        let parent = self.node_stack.last_mut().expect("node stack is empty");
50        parent.children.push(node);
51        parent.span = parent.span.merge(span);
52
53        node
54    }
55
56    // Opens a new non-terminal and adds it to the stack
57    fn open_non_terminal_node(&mut self, kind: NonTerminalKind) -> CstNodeId {
58        // span will be filled later
59        let node = self.tree.add_node(CstNodeData::NonTerminal {
60            kind,
61            data: NonTerminalData::Input(InputSpan::EMPTY),
62        });
63
64        if let Some(parent) = self.node_stack.last_mut() {
65            parent.children.push(node);
66        } else {
67            // This is a root level node
68            self.root_node = Some(node);
69        }
70
71        self.node_stack.push(NodeStackItem {
72            node,
73            span: InputSpan::EMPTY,
74            children: Vec::new(),
75        });
76        node
77    }
78
79    // Closes the current non-terminal
80    fn close_non_terminal_node(&mut self) -> Option<CstNodeId> {
81        let popped = self.node_stack.pop();
82        if let Some(item) = &popped {
83            let parent = item.node;
84
85            // Set children in original order (our HashMap-based implementation preserves insertion order)
86            self.tree.update_children(parent, item.children.clone());
87
88            // Update the node's span
89            if let Some(CstNodeData::NonTerminal { kind, .. }) = self.tree.node_data(parent) {
90                let updated_data = CstNodeData::NonTerminal {
91                    kind,
92                    data: NonTerminalData::Input(item.span),
93                };
94                self.tree.update_node(parent, updated_data);
95            }
96
97            if let Some(parent_item) = self.node_stack.last_mut() {
98                parent_item.span = parent_item.span.merge(item.span);
99            }
100        }
101        popped.map(|item| item.node)
102    }
103
104    /// Builds the tree
105    pub fn build_tree(mut self) -> Cst {
106        while !self.node_stack.is_empty() {
107            self.close_non_terminal_node();
108        }
109
110        // Set the actual root if we have one
111        if let Some(root_node) = self.root_node {
112            self.tree.set_root(root_node);
113        }
114
115        self.tree
116    }
117}
118
119impl<'t> TreeConstruct<'t> for CstBuilder {
120    type Error = ParolError;
121    type Tree = Cst;
122
123    fn open_non_terminal(
124        &mut self,
125        name: &'static str,
126        _size_hint: Option<usize>,
127    ) -> Result<(), Self::Error> {
128        let kind = NonTerminalKind::from_non_terminal_name(name);
129        self.open_non_terminal_node(kind);
130        Ok(())
131    }
132
133    fn close_non_terminal(&mut self) -> Result<(), Self::Error> {
134        self.close_non_terminal_node();
135        Ok(())
136    }
137
138    fn add_token(&mut self, token: &Token<'t>) -> Result<(), Self::Error> {
139        let kind = TerminalKind::from_terminal_index(token.token_type);
140        let span = InputSpan {
141            start: token.location.start,
142            end: token.location.end,
143        };
144        self.add_terminal_node(kind, span);
145        Ok(())
146    }
147
148    fn build(self) -> Result<Self::Tree, Self::Error> {
149        Ok(self.build_tree())
150    }
151}