1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// This file is generated automatically by infrastructure scripts. Please don't edit by hand.

use std::ops::ControlFlow;
use std::rc::Rc;

use super::{cst::*, cursor::Cursor};

/// A Visitor pattern for traversing the CST.
///
/// The trait supports fallible iteration, i.e. the visitor can early return an error from the visit.
pub trait Visitor<E> {
    /// Called when the [`Visitor`] enters a [`RuleNode`].
    fn rule_enter(
        &mut self,
        _node: &Rc<RuleNode>,
        _cursor: &Cursor,
    ) -> Result<ControlFlow<(), Step>, E> {
        Ok(ControlFlow::Continue(Step::In))
    }

    /// Called when the [`Visitor`] exits a [`RuleNode`].
    fn rule_exit(&mut self, _node: &Rc<RuleNode>, _cursor: &Cursor) -> Result<ControlFlow<()>, E> {
        Ok(ControlFlow::Continue(()))
    }

    /// Called when the [`Visitor`] enters a [`TokenNode`].
    fn token(&mut self, _node: &Rc<TokenNode>, _cursor: &Cursor) -> Result<ControlFlow<()>, E> {
        Ok(ControlFlow::Continue(()))
    }
}

/// Whether the [`Visitor`] should should enter the children of a [`RuleNode`] or not.
pub enum Step {
    In,
    Over,
}

impl Cursor {
    pub fn drive_visitor<E, V: Visitor<E>>(
        &mut self,
        visitor: &mut V,
    ) -> Result<ControlFlow<()>, E> {
        if self.is_completed() {
            return Ok(ControlFlow::Continue(()));
        }

        loop {
            // Node clone is cheap because it's just an enum around an Rc
            match self.node() {
                Node::Rule(rule_node) => {
                    match visitor.rule_enter(&rule_node, self)? {
                        ControlFlow::Break(()) => return Ok(ControlFlow::Break(())),
                        ControlFlow::Continue(Step::In) => {
                            if self.go_to_first_child() {
                                self.drive_visitor(visitor)?;
                                self.go_to_parent();
                            }
                        }
                        ControlFlow::Continue(Step::Over) => {}
                    }
                    if visitor.rule_exit(&rule_node, self)? == ControlFlow::Break(()) {
                        return Ok(ControlFlow::Break(()));
                    }
                }

                Node::Token(token_node) => {
                    if visitor.token(&token_node, self)? == ControlFlow::Break(()) {
                        return Ok(ControlFlow::Break(()));
                    }
                }
            }

            if !self.go_to_next_sibling() {
                return Ok(ControlFlow::Continue(()));
            }
        }
    }
}