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 fn enter(&mut self, _node: Cursor<'_>) -> Result<Flow, Self::Err> {
19 Ok(Flow::Continue)
20 }
21
22 fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
28 Ok(())
29 }
30
31 fn finish(self) -> Result<Self::Output, Self::Err>;
37}
38
39pub 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}