pretty_print_visitor/
pretty_print_visitor.rs1use std::fmt::Write;
9
10use gcode::core::{
11 BlockVisitor, CommandVisitor, ControlFlow, Diagnostics, HasDiagnostics,
12 Number, ProgramVisitor, Span, Value,
13};
14
15struct PrettyPrinter<'a> {
17 output: &'a mut String,
18 diagnostics: NoopDiagnostics,
19}
20
21struct NoopDiagnostics;
22
23impl Diagnostics for NoopDiagnostics {}
24
25impl HasDiagnostics for PrettyPrinter<'_> {
26 fn diagnostics(&mut self) -> &mut dyn Diagnostics {
27 &mut self.diagnostics
28 }
29}
30
31impl ProgramVisitor for PrettyPrinter<'_> {
32 fn start_block(&mut self) -> ControlFlow<impl BlockVisitor + '_> {
33 ControlFlow::Continue(PrettyPrintBlock {
34 output: self.output,
35 current_line: String::new(),
36 diagnostics: &mut self.diagnostics,
37 })
38 }
39}
40
41struct PrettyPrintBlock<'a> {
43 output: &'a mut String,
44 current_line: String,
45 diagnostics: &'a mut NoopDiagnostics,
46}
47
48impl PrettyPrintBlock<'_> {
49 fn space_if_needed(&mut self) {
50 if !self.current_line.is_empty() {
51 self.current_line.push(' ');
52 }
53 }
54}
55
56impl HasDiagnostics for PrettyPrintBlock<'_> {
57 fn diagnostics(&mut self) -> &mut dyn Diagnostics {
58 self.diagnostics
59 }
60}
61
62impl BlockVisitor for PrettyPrintBlock<'_> {
63 fn line_number(&mut self, n: u32, _span: Span) {
64 self.space_if_needed();
65 write!(self.current_line, "N{}", n).unwrap();
66 }
67
68 fn comment(&mut self, value: &str, _span: Span) {
69 self.space_if_needed();
70 self.current_line.push_str(value);
71 }
72
73 fn program_number(&mut self, number: u32, _span: Span) {
74 self.space_if_needed();
75 write!(self.current_line, "O{}", number).unwrap();
76 }
77
78 fn program_delimiter(&mut self, _span: Span) {
79 self.space_if_needed();
80 self.current_line.push('%');
81 }
82
83 fn word_address(&mut self, letter: char, value: Value<'_>, _span: Span) {
84 self.space_if_needed();
85 self.current_line.push(letter);
86 write!(self.current_line, "{}", value).unwrap();
87 }
88
89 fn start_general_code(
90 &mut self,
91 number: Number,
92 ) -> ControlFlow<impl CommandVisitor + '_> {
93 self.space_if_needed();
94 write!(self.current_line, "G{}", number).unwrap();
95 ControlFlow::Continue(PrettyPrintCommand {
96 line: &mut self.current_line,
97 diagnostics: self.diagnostics,
98 })
99 }
100
101 fn start_miscellaneous_code(
102 &mut self,
103 number: Number,
104 ) -> ControlFlow<impl CommandVisitor + '_> {
105 self.space_if_needed();
106 write!(self.current_line, "M{}", number).unwrap();
107 ControlFlow::Continue(PrettyPrintCommand {
108 line: &mut self.current_line,
109 diagnostics: self.diagnostics,
110 })
111 }
112
113 fn start_tool_change_code(
114 &mut self,
115 number: Number,
116 ) -> ControlFlow<impl CommandVisitor + '_> {
117 self.space_if_needed();
118 write!(self.current_line, "T{}", number).unwrap();
119 ControlFlow::Continue(PrettyPrintCommand {
120 line: &mut self.current_line,
121 diagnostics: self.diagnostics,
122 })
123 }
124
125 fn end_line(self, _span: Span) {
126 self.output.push_str(&self.current_line);
127 self.output.push('\n');
128 }
129}
130
131struct PrettyPrintCommand<'a> {
133 line: &'a mut String,
134 diagnostics: &'a mut NoopDiagnostics,
135}
136
137impl HasDiagnostics for PrettyPrintCommand<'_> {
138 fn diagnostics(&mut self) -> &mut dyn Diagnostics {
139 self.diagnostics
140 }
141}
142
143impl CommandVisitor for PrettyPrintCommand<'_> {
144 fn argument(&mut self, letter: char, value: Value<'_>, _span: Span) {
145 self.line.push(' ');
146 self.line.push(letter);
147 write!(self.line, "{}", value).unwrap();
148 }
149
150 fn end_command(self, _span: Span) {}
151}
152
153fn main() {
154 let src = r"
155N10 G21 G90 (metric, absolute)
156N20 G00 X50.0 Y-10.0
157N30 M03 S12000
158N40 G01 X1.5 Y-0.25 F100
159";
160 let mut output = String::new();
161 let mut visitor = PrettyPrinter {
162 output: &mut output,
163 diagnostics: NoopDiagnostics,
164 };
165 gcode::core::parse(src, &mut visitor);
166 println!("Pretty-printed program:\n{}", output);
167}