peg_pack/core/
graphvis.rs1use 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}