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 nodes: Vec<T>,
11 children: HashMap<Index, Vec<Index>>,
14 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 self.nodes.push(node);
32 let index = self.nodes.len() - 1;
33
34 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 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 if let Some(0) = index {
165 self.tree.debug_print(&mut vec![], 0);
166 self.tree.clear();
167 }
168 }
169}