Skip to main content

regast_syntax/
visit.rs

1use crate::{Cursor, Pattern};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Flow {
5    Continue,
6    SkipChildren,
7}
8
9pub trait Visitor {
10    type Output;
11    type Err;
12
13    /// Called before visiting a node's children.
14    ///
15    /// # Errors
16    ///
17    /// Implementations may return their visitor-specific error.
18    fn enter(&mut self, _node: Cursor<'_>) -> Result<Flow, Self::Err> {
19        Ok(Flow::Continue)
20    }
21
22    /// Called after visiting a node's children.
23    ///
24    /// # Errors
25    ///
26    /// Implementations may return their visitor-specific error.
27    fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
28        Ok(())
29    }
30
31    /// Consume the visitor and return its output.
32    ///
33    /// # Errors
34    ///
35    /// Implementations may return their visitor-specific error.
36    fn finish(self) -> Result<Self::Output, Self::Err>;
37}
38
39/// Walk `pattern` without recursion and drive `visitor`.
40///
41/// # Errors
42///
43/// Returns the first error reported by `visitor`.
44pub fn visit<V: Visitor>(pattern: &Pattern, mut visitor: V) -> Result<V::Output, V::Err> {
45    let mut stack = vec![(pattern.root(), false)];
46    while let Some((node, leaving)) = stack.pop() {
47        if leaving {
48            visitor.leave(node)?;
49            continue;
50        }
51        let flow = visitor.enter(node)?;
52        stack.push((node, true));
53        if flow == Flow::Continue {
54            stack.extend(node.children().rev().map(|child| (child, false)));
55        }
56    }
57    visitor.finish()
58}
59
60#[cfg(test)]
61mod tests {
62    use std::convert::Infallible;
63
64    use crate::Pattern;
65
66    use super::*;
67
68    struct Recorder(Vec<String>);
69
70    impl Visitor for Recorder {
71        type Output = Vec<String>;
72        type Err = Infallible;
73
74        fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
75            self.0.push(format!("+{}", node.text()));
76            Ok(Flow::Continue)
77        }
78
79        fn leave(&mut self, node: Cursor<'_>) -> Result<(), Self::Err> {
80            self.0.push(format!("-{}", node.text()));
81            Ok(())
82        }
83
84        fn finish(self) -> Result<Self::Output, Self::Err> {
85            Ok(self.0)
86        }
87    }
88
89    #[test]
90    fn drives_enter_and_leave_without_recursion() {
91        let pattern = Pattern::parse("ab|c").unwrap();
92        let events = visit(&pattern, Recorder(Vec::new())).unwrap();
93        assert_eq!(events.first().unwrap(), "+ab|c");
94        assert_eq!(events.last().unwrap(), "-ab|c");
95        assert_eq!(events.len(), pattern.len() * 2);
96
97        let first_leaf = pattern
98            .root()
99            .walk()
100            .find(|node| node.text() == "a")
101            .unwrap();
102        assert_eq!(first_leaf.ancestors().next().unwrap().text(), "ab");
103        assert_eq!(first_leaf.next_sibling().unwrap().text(), "b");
104    }
105}