lady_deirdre/syntax/
tree.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Lady Deirdre", a compiler front-end foundation       //
3// technology.                                                                //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/lady-deirdre/blob/master/EULA.md           //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::iter::FusedIterator;
36
37use crate::{
38    arena::{Entry, Identifiable},
39    lexis::TokenRef,
40    syntax::{AbstractNode, ErrorRef, Node, NodeRef, RefKind, SyntaxError},
41};
42
43/// An object that provides access to the syntax structure of
44/// a compilation unit.
45///
46/// The syntax structure consists of a set of [nodes](Node) forming an abstract
47/// syntax tree, and a set of syntax [errors](SyntaxError) that may occur during
48/// parsing or incremental reparsing.
49///
50/// In Lady Deirdre, instances of these objects are owned by the compilation
51/// units, rather than by the syntax tree nodes. This ownership structure allows
52/// compilation units to have full control over the syntax structure,
53/// especially for the purpose of incremental reparsing.
54///
55/// Syntax tree nodes reference their children, parents, and other nodes
56/// through a system of versioned indices ([Entry]).
57///
58/// This trait provides a low-level interface to borrow instance of syntax nodes
59/// and the syntax errors by index from the compilation unit.
60///
61/// Higher-level referential objects, such as [NodeRef] and [ErrorRef], offer
62/// a more convenient interface for borrowing these objects from the SyntaxTree.
63///
64/// Additionally, the SyntaxTree interface provides higher-level functions
65/// to retrieve the syntax tree root node, iterate through all nodes and errors
66/// currently managed by the compilation unit, and perform a depth-first
67/// traversal of the syntax tree.
68///
69/// Typically, manual implementation of this trait is unnecessary unless
70/// creating a new type of compilation unit manager.
71///
72/// To create a wrapper of an existing compilation unit,
73/// a [Syntax](crate::units::Syntax) facade-interface can be utilized,
74/// which auto-implements this trait through delegation.
75pub trait SyntaxTree: Identifiable {
76    /// Specifies the type of the tree node.
77    ///
78    /// [Node::Token] inherently specifies the lexical grammar of the language.
79    ///
80    /// [Node::parse] inherently specifies the syntax parser of the language.
81    type Node: Node;
82
83    /// Specifies the type of the iterator that walks through all node
84    /// [NodeRef] references currently managed by this SyntaxTree instance.
85    type NodeIterator<'tree>: Iterator<Item = NodeRef> + FusedIterator + 'tree
86    where
87        Self: 'tree;
88
89    /// Specifies the type of the iterator that walks through all syntax error
90    /// [ErrorRef] references currently managed by this SyntaxTree instance.
91    type ErrorIterator<'tree>: Iterator<Item = ErrorRef> + FusedIterator + 'tree
92    where
93        Self: 'tree;
94
95    /// Provides access to the root node of the syntax tree.
96    ///
97    /// **Panic**
98    ///
99    /// Depending on the implementation, this function may panic if
100    /// the SyntaxTree does not have a root node.
101    ///
102    /// However, all objects within this crate that implement
103    /// the SyntaxTree trait always have the root node regardless of the input.
104    /// Therefore, they would **never** panic.
105    #[inline(always)]
106    fn root(&self) -> &Self::Node
107    where
108        Self: Sized,
109    {
110        match self.root_node_ref().deref(self) {
111            Some(node) => node,
112            None => panic!("Syntax tree without root."),
113        }
114    }
115
116    /// Returns a [NodeRef] reference to the root node of this syntax tree.
117    fn root_node_ref(&self) -> NodeRef;
118
119    /// Returns an iterator over all nodes currently managed by this syntax tree.
120    ///
121    /// The order of iteration is not specified.
122    #[inline(always)]
123    fn nodes(&self) -> NodeIter<'_, Self>
124    where
125        Self: Sized,
126    {
127        NodeIter {
128            tree: self,
129            inner: self.node_refs(),
130        }
131    }
132
133    /// Returns an iterator of the [NodeRef] references over all nodes currently
134    /// managed by this syntax tree.
135    ///
136    /// The order of iteration is not specified.
137    fn node_refs(&self) -> Self::NodeIterator<'_>;
138
139    /// Returns an iterator over all syntax errors currently managed by
140    /// this syntax tree.
141    ///
142    /// The order of iteration is not specified.
143    #[inline(always)]
144    fn errors(&self) -> ErrorIter<'_, Self>
145    where
146        Self: Sized,
147    {
148        ErrorIter {
149            tree: self,
150            inner: self.error_refs(),
151        }
152    }
153
154    /// Returns an iterator of the [ErrorRef] references over all syntax errors
155    /// currently managed by this syntax tree.
156    ///
157    /// The order of iteration is not specified.
158    fn error_refs(&self) -> Self::ErrorIterator<'_>;
159
160    /// Performs a depth-first traverse of the syntax tree starting from
161    /// the root node.
162    ///
163    /// The `visitor` object will be called on each node entering and
164    /// leaving events, as well as the token entering event.
165    ///
166    /// The traverse algorithm will not visit descending nodes of the tree
167    /// branch if the [Visitor::enter_node] returns false. Thus, the visitor
168    /// can control the descending process.
169    ///
170    /// The algorithm relies on the [AbstractNode::children_iter] function
171    /// to determine the node's children to descend to, which in turn relies on
172    /// the node's captures description.
173    ///
174    /// In other words, the traverser will only visit the nodes for which you
175    /// have specified `#[child]` attribute:
176    ///
177    /// ```ignore
178    /// #[derive(Node)]
179    /// enum MyNode {
180    ///     #[rule(...)]
181    ///     SomeVariant {
182    ///         #[child]
183    ///         child_1: NodeRef, // will be visited
184    ///         #[child]
185    ///         child_2: NodeRef, // will be visited
186    ///         not_a_child: NodeRef, // will not be visited
187    ///     }
188    /// }
189    /// ```
190    #[inline(always)]
191    fn traverse_tree(&self, visitor: &mut impl Visitor)
192    where
193        Self: Sized,
194    {
195        self.traverse_subtree(&self.root_node_ref(), visitor);
196    }
197
198    /// Performs a depth-first traverse of a branch of the syntax tree.
199    ///
200    /// The `top` parameter specifies a reference into the top node of
201    /// the branch.
202    ///
203    /// For details, see [SyntaxTree::traverse_tree].
204    fn traverse_subtree(&self, top: &NodeRef, visitor: &mut impl Visitor)
205    where
206        Self: Sized,
207    {
208        if visitor.enter_node(top) {
209            let node: &Self::Node = match top.deref(self) {
210                Some(node) => node,
211                None => return,
212            };
213
214            for child in node.children_iter() {
215                match child.kind() {
216                    RefKind::Token => visitor.visit_token(child.as_token_ref()),
217                    RefKind::Node => self.traverse_subtree(child.as_node_ref(), visitor),
218                }
219            }
220        }
221
222        visitor.leave_node(top)
223    }
224
225    /// Checks if the node referred to by the versioned index exists in this
226    /// syntax tree.
227    fn has_node(&self, entry: &Entry) -> bool;
228
229    /// Provides immutable access to the node referred to by the versioned index.
230    ///
231    /// If the index parameter `entry` is not valid, returns None.
232    fn get_node(&self, entry: &Entry) -> Option<&Self::Node>;
233
234    /// Provides mutable access to the node referred to by the versioned index.
235    ///
236    /// If the index parameter `entry` is not valid, returns None.
237    fn get_node_mut(&mut self, entry: &Entry) -> Option<&mut Self::Node>;
238
239    /// Checks if the syntax error referred to by the versioned index exists in
240    /// this syntax tree.
241    fn has_error(&self, entry: &Entry) -> bool;
242
243    /// Provides access to the syntax error referred to by the versioned index.
244    ///
245    /// If the index parameter `entry` is not valid, returns None.
246    fn get_error(&self, entry: &Entry) -> Option<&SyntaxError>;
247}
248
249/// An iterator over all nodes of the [SyntaxTree].
250///
251/// This object is created by the [SyntaxTree::nodes] function.
252pub struct NodeIter<'tree, T: SyntaxTree> {
253    tree: &'tree T,
254    inner: <T as SyntaxTree>::NodeIterator<'tree>,
255}
256
257impl<'tree, T: SyntaxTree> Iterator for NodeIter<'tree, T> {
258    type Item = &'tree <T as SyntaxTree>::Node;
259
260    #[inline(always)]
261    fn next(&mut self) -> Option<Self::Item> {
262        loop {
263            let next = self.inner.next()?;
264
265            let Some(node) = self.tree.get_node(&next.entry) else {
266                continue;
267            };
268
269            return Some(node);
270        }
271    }
272}
273
274impl<'tree, T: SyntaxTree> FusedIterator for NodeIter<'tree, T> {}
275
276/// An iterator over all syntax errors of the [SyntaxTree].
277///
278/// This object is created by the [SyntaxTree::errors] function.
279pub struct ErrorIter<'tree, T: SyntaxTree> {
280    tree: &'tree T,
281    inner: <T as SyntaxTree>::ErrorIterator<'tree>,
282}
283
284impl<'tree, T: SyntaxTree> Iterator for ErrorIter<'tree, T> {
285    type Item = &'tree SyntaxError;
286
287    #[inline(always)]
288    fn next(&mut self) -> Option<Self::Item> {
289        loop {
290            let next = self.inner.next()?;
291
292            let Some(error) = self.tree.get_error(&next.entry) else {
293                continue;
294            };
295
296            return Some(error);
297        }
298    }
299}
300
301impl<'tree, T: SyntaxTree> FusedIterator for ErrorIter<'tree, T> {}
302
303/// Visits individual nodes and tokens during the syntax tree
304/// depth-first traversing.
305///
306/// See [SyntaxTree::traverse_tree] for details.
307pub trait Visitor {
308    /// Triggers when the traverser visits a token child of a node.
309    ///
310    /// ```ignore
311    /// #[derive(Node)]
312    /// enum MyNode {
313    ///     #[rule(...)]
314    ///     SomeVariant {
315    ///         #[child]
316    ///         node_child: NodeRef,
317    ///         #[child]
318    ///         token_child: TokenRef, // <- when this type of children is visited
319    ///     }
320    /// }
321    /// ```
322    fn visit_token(&mut self, token_ref: &TokenRef);
323
324    /// Triggers when the traverser enters a node.
325    ///
326    /// ```ignore
327    /// #[derive(Node)]
328    /// enum MyNode {
329    ///     #[rule(...)]
330    ///     SomeVariant {
331    ///         #[child]
332    ///         node_child: NodeRef, // <- when this type of children is visited
333    ///         #[child]
334    ///         token_child: TokenRef,
335    ///     }
336    /// }
337    /// ```
338    ///
339    /// Returning false prevents the traverser further descending into
340    /// the node's sub-branch.
341    fn enter_node(&mut self, node_ref: &NodeRef) -> bool;
342
343    /// Triggers when the traverser leaves a node.
344    ///
345    /// In practice, this function observes depth-first traversing
346    /// in reverse order.
347    fn leave_node(&mut self, node_ref: &NodeRef);
348}