peg_pack/core/
graphvis.rs

1use crate::core::character::Character;
2use crate::core::expected::Expected;
3use crate::core::series::{Class, Series};
4use crate::core::{Instruction, Parser};
5use std::collections::{HashMap, HashSet};
6
7impl Parser {
8    pub fn visualize(&self) -> String {
9        let mut result = String::from("digraph {\n");
10
11        self.visualize_instructions(&mut result);
12        self.visualize_debug_symbols(&mut result);
13
14        result.push_str("}");
15        result
16    }
17
18    fn visualize_instructions(&self, result: &mut String) {
19        let characters = self.characterize();
20
21        for (id, instruction) in self.instructions() {
22            let character = characters[&id];
23            let name = self.instruction_name(instruction, character);
24            let shape = self.instruction_shape(instruction);
25
26            let header = format!(
27                "    i{}[shape={}, label=\"{} #{}\"];\n",
28                id.0, shape, name, id.0
29            );
30            result.push_str(&header);
31
32            match instruction {
33                Instruction::Seq(first, second)
34                | Instruction::Choice(first, second)
35                | Instruction::FirstChoice(first, second) => {
36                    result.push_str(&format!("    i{}:w -> i{};\n", id.0, first.0));
37                    result.push_str(&format!("    i{}:e -> i{};\n", id.0, second.0));
38                }
39                Instruction::NotAhead(target)
40                | Instruction::Error(target, _)
41                | Instruction::Label(target, _)
42                | Instruction::Cache(target, _)
43                | Instruction::Delegate(target) => {
44                    result.push_str(&format!("    i{} -> i{};\n", id.0, target.0));
45                }
46                Instruction::Series(_) => {}
47            };
48        }
49
50        result.push_str(&format!("    i{}[peripheries=2];\n", self.start.0));
51    }
52
53    fn instruction_shape(&self, instruction: Instruction) -> &str {
54        match instruction {
55            Instruction::Seq(_, _)
56            | Instruction::Choice(_, _)
57            | Instruction::FirstChoice(_, _)
58            | Instruction::NotAhead(_)
59            | Instruction::Error(_, _)
60            | Instruction::Label(_, _)
61            | Instruction::Cache(_, _)
62            | Instruction::Delegate(_) => "oval",
63            Instruction::Series(_) => "box",
64        }
65    }
66
67    fn instruction_name(&self, instruction: Instruction, character: Character) -> String {
68        let mut name = match instruction {
69            Instruction::Seq(_, _) => String::from("Sequence"),
70            Instruction::Choice(_, _) => String::from("Choice"),
71            Instruction::FirstChoice(_, _) => String::from("First choice"),
72            Instruction::NotAhead(_) => String::from("Not ahead"),
73            Instruction::Error(_, expected) => {
74                let expected = &self.expecteds[expected];
75                format!("Error[{}]", self.expected_specifier(expected))
76            }
77            Instruction::Cache(_, id) => match id {
78                Some(id) => format!("Cache[{}]", id),
79                None => String::from("Cache[?]"),
80            },
81            Instruction::Delegate(_) => String::from("Delegate"),
82            Instruction::Label(_, label) => {
83                let label = &self.labels[label];
84                format!("Label[{}]", label)
85            }
86            Instruction::Series(series) => {
87                let series = &self.series[series];
88                format!("Series[{}]", self.series_specifier(series))
89            }
90        };
91
92        if character.antitransparent {
93            name.push_str(" (AT)");
94        }
95
96        if character.transparent {
97            name.push_str(" (T)");
98        }
99
100        if character.fallible {
101            name.push_str(" (F)");
102        }
103
104        name
105    }
106
107    fn series_specifier(&self, series: &Series) -> String {
108        let mut specifier = String::new();
109
110        for (i, class) in series.classes().iter().enumerate() {
111            if i != 0 {
112                specifier.push_str(", ");
113            }
114
115            specifier.push_str(&self.class_specifier(class));
116        }
117
118        specifier
119    }
120
121    fn class_specifier(&self, class: &Class) -> String {
122        let mut specifier = String::new();
123        let brackets = class.negated() || class.ranges().len() != 1;
124
125        if brackets {
126            specifier.push_str("[");
127        }
128
129        if class.negated() {
130            specifier.push_str("^");
131        }
132
133        for (i, (start, end)) in class.ranges().iter().enumerate() {
134            if i != 0 {
135                specifier.push_str(", ");
136            }
137
138            if start == end {
139                specifier.push_str(&self.format_class_bound(*start));
140            } else {
141                specifier.push_str(&format!(
142                    "{}-{}",
143                    self.format_class_bound(*start),
144                    self.format_class_bound(*end)
145                ));
146            }
147        }
148
149        if brackets {
150            specifier.push_str("]");
151        }
152
153        specifier
154    }
155
156    fn format_class_bound(&self, bound: u8) -> String {
157        let format_char =
158            bound == 0 || bound == 9 || bound == 10 || bound == 13 || bound >= 32 && bound <= 126;
159
160        if format_char {
161            format!("{:?}", bound as char)
162                .replace('\\', "\\\\")
163                .replace('"', "\\\"")
164        } else {
165            format!("0x{:x}", bound)
166        }
167    }
168
169    fn expected_specifier(&self, expected: &Expected) -> String {
170        let mut parts = Vec::new();
171
172        for label in expected.labels() {
173            parts.push(String::from(label));
174        }
175
176        for literal in expected.literals() {
177            let mut series = Series::empty();
178            for char in literal {
179                let mut class = Class::new(false);
180                class.insert(*char, *char);
181                series.append(class);
182            }
183
184            parts.push(self.series_specifier(&series));
185        }
186
187        format!("[{}]", parts.join(", "))
188    }
189
190    fn visualize_debug_symbols(&self, result: &mut String) {
191        let mut groups = HashMap::<_, HashSet<_>>::new();
192
193        for (instruction, symbol) in &self.debug_symbols {
194            if let Some(set) = groups.get_mut(symbol) {
195                set.insert(*instruction);
196            } else {
197                groups.insert(symbol.clone(), HashSet::from([*instruction]));
198            }
199        }
200
201        for (i, (symbol, instructions)) in groups.into_iter().enumerate() {
202            let names = if symbol.names.is_empty() {
203                String::from("<anonymous>")
204            } else {
205                symbol.names.iter().cloned().collect::<Vec<_>>().join(", ")
206            };
207
208            result.push_str(&format!("    subgraph cluster_{} {{\n", i));
209            result.push_str(&format!("        label=\"{}\";\n", names));
210
211            for instruction in instructions {
212                result.push_str(&format!("        i{};\n", instruction.0));
213            }
214
215            result.push_str("    }\n");
216        }
217    }
218}