pear/
debug.rs

1use std::collections::HashMap;
2use inlinable_string::InlinableString;
3
4use crate::input::{Show, Input, Debugger, ParserInfo};
5
6type Index = usize;
7
8struct Tree<T> {
9    // All of the nodes in the tree live in this vector.
10    nodes: Vec<T>,
11    // Maps from an index (`parent`) index `nodes` to a set of indexes in
12    // `nodes` corresponding to the children of `key`.
13    children: HashMap<Index, Vec<Index>>,
14    // This "tree" keeps track of which parent children are currently being
15    // pushed to. A `push` adds to this stack while a `pop` removes from this
16    // stack. If the stack is empty, the root is being pushed to.
17    stack: Vec<Index>
18}
19
20impl<T> Tree<T> {
21    fn new() -> Tree<T> {
22        Tree {
23            nodes: vec![],
24            children: HashMap::new(),
25            stack: Vec::with_capacity(8)
26        }
27    }
28
29    fn push(&mut self, node: T) -> Index {
30        // Add the node to the tree and get its index.
31        self.nodes.push(node);
32        let index = self.nodes.len() - 1;
33
34        // If the stack indicates we have a parent, add to its children.
35        if !self.stack.is_empty() {
36            let parent = self.stack[self.stack.len() - 1];
37            self.children.entry(parent).or_default().push(index);
38        }
39
40        // Make this the new parent.
41        self.stack.push(index);
42        index
43    }
44
45    fn pop_level(&mut self) -> Option<Index> {
46        self.stack.pop()
47    }
48
49    fn clear(&mut self) {
50        *self = Self::new();
51    }
52
53    fn get(&self, index: Index) -> &T {
54        &self.nodes[index]
55    }
56
57    fn get_mut(&mut self, index: Index) -> &mut T {
58        &mut self.nodes[index]
59    }
60
61    fn get_children(&self, index: Index) -> &[Index] {
62        match self.children.get(&index) {
63            Some(children) => &children[..],
64            None => &[]
65        }
66    }
67}
68
69impl Tree<Info> {
70    fn debug_print(&self, sibling_map: &mut Vec<bool>, node: Index) {
71        let parent_count = sibling_map.len();
72        for (i, &has_siblings) in sibling_map.iter().enumerate() {
73            if i < parent_count - 1 {
74                match has_siblings {
75                    true => print!(" │   "),
76                    false => print!("     ")
77                }
78            } else {
79                match has_siblings {
80                    true => print!(" ├── "),
81                    false => print!(" └── ")
82                }
83            }
84        }
85
86        let info = self.get(node);
87        let success = match info.success {
88            Some(true) => " ✓",
89            Some(false) => " ✗",
90            None => ""
91        };
92
93        #[cfg(feature = "color")]
94        use yansi::{Style, Paint, Color::*};
95
96        #[cfg(feature = "color")]
97        let style = match info.success {
98            Some(true) => Green.into(),
99            Some(false) => Red.into(),
100            None => Style::default(),
101        };
102
103        #[cfg(feature = "color")]
104        println!("{}{} ({})", info.parser.name.paint(style), success.paint(style), info.context);
105
106        #[cfg(not(feature = "color"))]
107        println!("{}{} ({})", info.parser.name, success, info.context);
108
109        let children = self.get_children(node);
110        let num_children = children.len();
111        for (i, &child) in children.iter().enumerate() {
112            let have_siblings = i != (num_children - 1);
113            sibling_map.push(have_siblings);
114            self.debug_print(sibling_map, child);
115            sibling_map.pop();
116        }
117    }
118}
119
120struct Info {
121    parser: ParserInfo,
122    context: InlinableString,
123    success: Option<bool>,
124}
125
126impl Info {
127    fn new(parser: ParserInfo) -> Self {
128        Info { parser, context: iformat!(), success: None }
129    }
130}
131
132pub struct TreeDebugger {
133    tree: Tree<Info>,
134}
135
136impl Default for TreeDebugger {
137    fn default() -> Self {
138        Self { tree: Tree::new() }
139    }
140}
141
142impl<I: Input> Debugger<I> for TreeDebugger {
143    fn on_entry(&mut self, p: &ParserInfo) {
144        if !((p.raw && is_parse_debug!("full")) || (!p.raw && is_parse_debug!())) {
145            return;
146        }
147
148        self.tree.push(Info::new(*p));
149    }
150
151    fn on_exit(&mut self, p: &ParserInfo, ok: bool, ctxt: I::Context) {
152        if !((p.raw && is_parse_debug!("full")) || (!p.raw && is_parse_debug!())) {
153            return;
154        }
155
156        let index = self.tree.pop_level();
157        if let Some(last_node) = index {
158            let last = self.tree.get_mut(last_node);
159            last.success = Some(ok);
160            last.context = iformat!("{}", &ctxt as &dyn Show);
161        }
162
163        // We've reached the end. Print the whole thing and clear the tree.
164        if let Some(0) = index {
165            self.tree.debug_print(&mut vec![], 0);
166            self.tree.clear();
167        }
168    }
169}