metrale_grammar/grammar/
printer.rs1use std::collections::HashMap;
11
12use super::data::{GrammarData, Rule};
13use super::expr::{GrammarExpr, GrammarExprType};
14use crate::support::escape::print_str_as_escaped;
15use crate::support::{char_to_utf8, print_as_escaped};
16
17pub struct GrammarPrinter<'g> {
19 grammar: &'g GrammarData,
20}
21
22impl<'g> GrammarPrinter<'g> {
23 pub fn new(grammar: &'g GrammarData) -> Self {
25 Self { grammar }
26 }
27
28 pub fn render(&self) -> String {
30 let mut result = String::new();
31 for i in 0..self.grammar.num_rules() {
32 result.push_str(&self.print_rule(self.grammar.rule(i)));
33 result.push('\n');
34 }
35 result
36 }
37
38 pub fn print_rule(&self, rule: &Rule) -> String {
40 let mut res = format!(
41 "{} ::= {}",
42 rule.name,
43 self.print_expr_id(rule.body_expr_id)
44 );
45 if rule.lookahead_assertion_id != -1 {
46 res.push_str(" (=");
47 res.push_str(&self.print_expr_id(rule.lookahead_assertion_id));
48 res.push(')');
49 }
50 res
51 }
52
53 pub fn print_rule_id(&self, rule_id: i32) -> String {
55 self.print_rule(self.grammar.rule(rule_id))
56 }
57
58 pub fn print_expr_id(&self, expr_id: i32) -> String {
60 self.print_expr(&self.grammar.expr(expr_id))
61 }
62
63 pub fn print_expr(&self, e: &GrammarExpr<'_>) -> String {
65 match e.kind {
66 GrammarExprType::ByteString => Self::print_byte_string(e),
67 GrammarExprType::CharacterClass => Self::print_character_class(e),
68 GrammarExprType::CharacterClassStar => {
69 format!("{}*", Self::print_character_class(e))
70 }
71 GrammarExprType::EmptyStr => "\"\"".to_string(),
72 GrammarExprType::RuleRef => self.print_rule_ref(e),
73 GrammarExprType::Sequence => self.print_sequence(e),
74 GrammarExprType::Choices => self.print_choices(e),
75 GrammarExprType::TagDispatch => self.print_tag_dispatch(e),
76 GrammarExprType::Repeat => self.print_repeat(e),
77 }
78 }
79
80 fn print_byte_string(e: &GrammarExpr<'_>) -> String {
81 let bytes: Vec<u8> = e.data.iter().map(|&b| b as u8).collect();
82 format!("\"{}\"", print_str_as_escaped(&bytes))
83 }
84
85 fn print_character_class(e: &GrammarExpr<'_>) -> String {
86 let custom: HashMap<i32, String> = HashMap::from([
87 ('-' as i32, "\\-".to_string()),
88 (']' as i32, "\\]".to_string()),
89 ]);
90 let mut result = String::from("[");
91 if e[0] != 0 {
92 result.push('^');
93 }
94 let mut i = 1;
95 while i < e.len() {
96 result.push_str(&print_as_escaped(e[i], &custom));
97 if e[i] != e[i + 1] {
98 result.push('-');
99 result.push_str(&print_as_escaped(e[i + 1], &custom));
100 }
101 i += 2;
102 }
103 result.push(']');
104 result
105 }
106
107 fn print_rule_ref(&self, e: &GrammarExpr<'_>) -> String {
108 self.grammar.rule(e[0]).name.clone()
109 }
110
111 fn print_sequence(&self, e: &GrammarExpr<'_>) -> String {
112 let parts: Vec<String> = e.data.iter().map(|&id| self.print_expr_id(id)).collect();
113 format!("({})", parts.join(" "))
114 }
115
116 fn print_choices(&self, e: &GrammarExpr<'_>) -> String {
117 let parts: Vec<String> = e.data.iter().map(|&id| self.print_expr_id(id)).collect();
118 format!("({})", parts.join(" | "))
119 }
120
121 fn print_repeat(&self, e: &GrammarExpr<'_>) -> String {
122 format!("{}{{{}, {}}}", self.grammar.rule(e[0]).name, e[1], e[2])
123 }
124
125 fn print_string(s: &str) -> String {
126 format!("\"{}\"", print_str_as_escaped(s.as_bytes()))
127 }
128
129 fn print_tag_dispatch(&self, e: &GrammarExpr<'_>) -> String {
130 let td = self.grammar.tag_dispatch(self.expr_id_of(e));
131 let mut result = String::from("TagDispatch(\n");
132 let indent = " ";
133 for (tag, rule_id) in &td.tag_rule_pairs {
134 result.push_str(&format!(
135 "{indent}({}, {}),\n",
136 Self::print_string(tag),
137 self.grammar.rule(*rule_id).name
138 ));
139 }
140 result.push_str(&format!("{indent}stop_eos={},\n", td.stop_eos));
141 let stop: Vec<String> = td.stop_str.iter().map(|s| Self::print_string(s)).collect();
142 result.push_str(&format!("{indent}stop_str=({}),\n", stop.join(", ")));
143 result.push_str(&format!(
144 "{indent}loop_after_dispatch={},\n",
145 td.loop_after_dispatch
146 ));
147 let excl: Vec<String> = td
148 .excluded_str
149 .iter()
150 .map(|s| Self::print_string(s))
151 .collect();
152 result.push_str(&format!("{indent}excludes=({})\n)", excl.join(", ")));
153 result
154 }
155
156 fn expr_id_of(&self, e: &GrammarExpr<'_>) -> i32 {
159 for id in 0..self.grammar.num_exprs() {
160 let cand = self.grammar.expr(id);
161 if cand.kind == e.kind && std::ptr::eq(cand.data.as_ptr(), e.data.as_ptr()) {
162 return id;
163 }
164 }
165 panic!("printer: tag dispatch expr not found in grammar");
166 }
167}
168
169pub fn print_grammar(grammar: &GrammarData) -> String {
171 GrammarPrinter::new(grammar).render()
172}
173
174pub(crate) fn codepoint_to_bytes(cp: i32) -> Vec<i32> {
177 char_to_utf8(cp).into_iter().map(|b| b as i32).collect()
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::grammar::parse_ebnf_default;
184
185 fn roundtrip(ebnf: &str) -> String {
186 let g = parse_ebnf_default(ebnf).expect("parse");
187 print_grammar(&g)
188 }
189
190 #[test]
191 fn prints_byte_string_rule() {
192 let out = roundtrip("root ::= \"abc\"\n");
193 assert!(out.contains("root ::="));
194 assert!(out.contains("\"abc\""));
195 }
196
197 #[test]
198 fn prints_character_class() {
199 let out = roundtrip("root ::= [a-z]\n");
200 assert!(out.contains("[a-z]"));
201 }
202
203 #[test]
204 fn prints_character_class_star() {
205 let out = roundtrip("root ::= [a-z]*\n");
206 assert!(out.contains("[a-z]*"));
207 }
208
209 #[test]
210 fn prints_negated_class() {
211 let out = roundtrip("root ::= [^a-z]\n");
212 assert!(out.contains("[^a-z]"));
213 }
214
215 #[test]
216 fn prints_choices() {
217 let out = roundtrip("root ::= \"a\" | \"b\"\n");
218 assert!(out.contains(" | "));
219 }
220
221 #[test]
222 fn prints_empty_string() {
223 let out = roundtrip("root ::= \"\"\n");
224 assert!(out.contains("\"\""));
225 }
226}