1use regex_syntax::ast::Ast;
2
3use super::formatter;
4use super::ExplainNode;
5
6#[derive(Default)]
7pub struct ExplainVisitor {
8 nodes: Vec<ExplainNode>,
9 depth: usize,
10}
11
12impl ExplainVisitor {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn into_nodes(self) -> Vec<ExplainNode> {
18 self.nodes
19 }
20
21 fn push(&mut self, description: String) {
22 self.nodes.push(ExplainNode {
23 depth: self.depth,
24 description,
25 });
26 }
27
28 pub fn visit(&mut self, ast: &Ast) {
29 match ast {
30 Ast::Empty(_) => {}
31 Ast::Flags(flags) => {
32 self.push(formatter::format_flags_item(&flags.flags));
33 }
34 Ast::Literal(lit) => {
35 self.push(formatter::format_literal(lit));
36 }
37 Ast::Dot(_) => {
38 self.push("Any character (except newline by default)".to_string());
39 }
40 Ast::Assertion(assertion) => {
41 self.push(formatter::format_assertion(assertion));
42 }
43 Ast::ClassUnicode(class) => {
44 self.push(formatter::format_unicode_class(class));
45 }
46 Ast::ClassPerl(class) => {
47 self.push(formatter::format_perl_class(class));
48 }
49 Ast::ClassBracketed(class) => {
50 self.push(formatter::format_bracketed_class(class));
51 }
52 Ast::Repetition(rep) => {
53 self.push(formatter::format_repetition(rep));
54 self.depth += 1;
55 self.visit(&rep.ast);
56 self.depth -= 1;
57 }
58 Ast::Group(group) => {
59 self.push(formatter::format_group(group));
60 self.depth += 1;
61 self.visit(&group.ast);
62 self.depth -= 1;
63 }
64 Ast::Alternation(alt) => {
65 self.push("Either:".to_string());
66 self.depth += 1;
67 for (i, ast) in alt.asts.iter().enumerate() {
68 if i > 0 {
69 self.push("Or:".to_string());
70 }
71 self.visit(ast);
72 }
73 self.depth -= 1;
74 }
75 Ast::Concat(concat) => {
76 for ast in &concat.asts {
77 self.visit(ast);
78 }
79 }
80 }
81 }
82}