1use std::collections::BTreeSet;
2
3use crate::grammar::{Grammar, GrammarExpr, GrammarRule};
4use crate::rust_codec::{RustFieldShape, RustTypeKind, RustTypeShape};
5
6use super::pest::emit_pest;
7use super::{EmitReport, GrammarEmitError};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct RustParserArtifacts {
12 pub pest_grammar: String,
14 pub parser_struct: String,
16 pub ast_types: String,
18 pub ast_shapes: Vec<RustTypeShape>,
20}
21
22pub fn emit_rust_parser(
34 grammar: &Grammar,
35) -> Result<(RustParserArtifacts, EmitReport), GrammarEmitError> {
36 let (pest_grammar, report) = emit_pest(grammar)?;
37 let ast_shapes = ast_shapes_for_grammar(grammar);
38 let ast_types = render_rust_types(&ast_shapes);
39 let parser_struct = render_parser_struct(&parser_struct_name(grammar), &pest_grammar);
40
41 Ok((
42 RustParserArtifacts {
43 pest_grammar,
44 parser_struct,
45 ast_types,
46 ast_shapes,
47 },
48 report,
49 ))
50}
51
52#[must_use]
54pub fn render_rust_type(shape: &RustTypeShape) -> String {
55 match shape.kind() {
56 RustTypeKind::Struct => render_struct(shape),
57 RustTypeKind::Enum => render_enum(shape),
58 RustTypeKind::Primitive => {
59 format!(
60 "#[derive(Debug, Clone)]\npub struct {}(pub String);\n",
61 shape.name()
62 )
63 }
64 RustTypeKind::Trait => render_trait(shape),
65 RustTypeKind::Sequence => render_sequence(shape),
66 RustTypeKind::Option => render_option(shape),
67 RustTypeKind::Map => render_map(shape),
68 }
69}
70
71fn ast_shapes_for_grammar(grammar: &Grammar) -> Vec<RustTypeShape> {
72 grammar.rules().iter().map(shape_for_rule).collect()
73}
74
75fn shape_for_rule(rule: &GrammarRule) -> RustTypeShape {
76 let type_name = rust_type_name(rule.name());
77 if let GrammarExpr::Choice { alternatives, .. } = rule.expr() {
78 return RustTypeShape::enumeration(type_name, enum_variants(alternatives));
79 }
80
81 let fields = ast_fields(rule.expr());
82 if fields.is_empty() && is_terminal_only(rule.expr()) {
83 RustTypeShape::structure(type_name, [RustFieldShape::new("0", "String")])
84 } else {
85 RustTypeShape::structure(type_name, fields)
86 }
87}
88
89fn enum_variants(alternatives: &[GrammarExpr]) -> Vec<RustFieldShape> {
90 let mut used = BTreeSet::new();
91 alternatives
92 .iter()
93 .enumerate()
94 .map(|(index, alternative)| {
95 let name = unique_name(variant_name(alternative, index), &mut used);
96 RustFieldShape::new(name, variant_type(alternative))
97 })
98 .collect()
99}
100
101fn variant_name(expr: &GrammarExpr, index: usize) -> String {
102 match expr {
103 GrammarExpr::NonTerminal(name)
105 | GrammarExpr::Capture {
106 label: Some(name), ..
107 } => match rust_type_name_with_fallback(name, "Generated") {
108 variant if variant == "Self" => "SelfNode".to_string(),
109 variant => variant,
110 },
111 GrammarExpr::Capture { expr, .. } => variant_name(expr, index),
112 GrammarExpr::Terminal(value) | GrammarExpr::TerminalInsensitive(value) => {
113 rust_type_name_with_fallback(value, &format!("Literal{}", index + 1))
114 }
115 GrammarExpr::Empty => "Empty".to_string(),
116 GrammarExpr::CharRange(_, _) | GrammarExpr::CharClass { .. } => {
117 format!("Character{}", index + 1)
118 }
119 GrammarExpr::AnyChar => format!("Any{}", index + 1),
120 GrammarExpr::Sequence(_) => format!("Sequence{}", index + 1),
121 GrammarExpr::Choice { .. } => format!("Choice{}", index + 1),
122 GrammarExpr::Optional(_) => format!("Optional{}", index + 1),
123 GrammarExpr::ZeroOrMore(_) | GrammarExpr::OneOrMore(_) | GrammarExpr::Repeat { .. } => {
124 format!("Repeated{}", index + 1)
125 }
126 GrammarExpr::And(_) | GrammarExpr::Not(_) => format!("Predicate{}", index + 1),
127 GrammarExpr::Feature(_) => format!("Feature{}", index + 1),
128 }
129}
130
131fn variant_type(expr: &GrammarExpr) -> String {
132 match expr {
133 GrammarExpr::NonTerminal(name) => rust_type_name(name),
134 GrammarExpr::Capture { expr, .. } => variant_type(expr),
135 GrammarExpr::Empty => "()".to_string(),
136 _ => "String".to_string(),
137 }
138}
139
140fn ast_fields(expr: &GrammarExpr) -> Vec<RustFieldShape> {
141 let mut fields = Vec::new();
142 collect_fields(expr, Quantifier::Single, &mut fields);
143 fields
144 .into_iter()
145 .map(|field| {
146 let type_name = field.type_name();
147 RustFieldShape::new(field.name, type_name)
148 })
149 .collect()
150}
151
152fn collect_fields(expr: &GrammarExpr, quantifier: Quantifier, fields: &mut Vec<AstField>) {
153 match expr {
154 GrammarExpr::NonTerminal(name) => {
155 push_field(
156 fields,
157 AstField::new(rust_field_name(name), rust_type_name(name), quantifier),
158 );
159 }
160 GrammarExpr::Capture {
161 label: Some(label),
162 expr,
163 } => {
164 let (type_name, quantifier) = captured_type(expr, quantifier);
165 push_field(
166 fields,
167 AstField::new(rust_field_name(label), type_name, quantifier),
168 );
169 }
170 GrammarExpr::Capture { label: None, expr } => collect_fields(expr, quantifier, fields),
171 GrammarExpr::Sequence(items) => {
172 for item in items {
173 collect_fields(item, quantifier, fields);
174 }
175 }
176 GrammarExpr::Choice { alternatives, .. } => {
177 for alternative in alternatives {
178 collect_fields(
179 alternative,
180 combine_quantifier(quantifier, Quantifier::Optional),
181 fields,
182 );
183 }
184 }
185 GrammarExpr::Optional(inner) => {
186 collect_fields(
187 inner,
188 combine_quantifier(quantifier, Quantifier::Optional),
189 fields,
190 );
191 }
192 GrammarExpr::ZeroOrMore(inner)
193 | GrammarExpr::OneOrMore(inner)
194 | GrammarExpr::Repeat { expr: inner, .. } => {
195 collect_fields(
196 inner,
197 combine_quantifier(quantifier, Quantifier::Repeated),
198 fields,
199 );
200 }
201 GrammarExpr::And(_)
202 | GrammarExpr::Not(_)
203 | GrammarExpr::Empty
204 | GrammarExpr::Terminal(_)
205 | GrammarExpr::TerminalInsensitive(_)
206 | GrammarExpr::CharRange(_, _)
207 | GrammarExpr::CharClass { .. }
208 | GrammarExpr::Feature(_)
209 | GrammarExpr::AnyChar => {}
210 }
211}
212
213fn captured_type(expr: &GrammarExpr, quantifier: Quantifier) -> (String, Quantifier) {
214 match expr {
215 GrammarExpr::NonTerminal(name) => (rust_type_name(name), quantifier),
216 GrammarExpr::Capture { expr, .. } => captured_type(expr, quantifier),
217 GrammarExpr::Optional(inner) => {
218 captured_type(inner, combine_quantifier(quantifier, Quantifier::Optional))
219 }
220 GrammarExpr::ZeroOrMore(inner)
221 | GrammarExpr::OneOrMore(inner)
222 | GrammarExpr::Repeat { expr: inner, .. } => {
223 captured_type(inner, combine_quantifier(quantifier, Quantifier::Repeated))
224 }
225 _ => ("String".to_string(), quantifier),
226 }
227}
228
229fn push_field(fields: &mut Vec<AstField>, field: AstField) {
230 if let Some(existing) = fields
231 .iter_mut()
232 .find(|existing| existing.name == field.name && existing.base_type == field.base_type)
233 {
234 existing.quantifier = Quantifier::Repeated;
235 return;
236 }
237
238 if fields.iter().any(|existing| existing.name == field.name) {
239 let mut used = fields
240 .iter()
241 .map(|existing| existing.name.clone())
242 .collect::<BTreeSet<_>>();
243 let mut renamed = field;
244 renamed.name = unique_name(renamed.name, &mut used);
245 fields.push(renamed);
246 } else {
247 fields.push(field);
248 }
249}
250
251#[derive(Clone, Debug, PartialEq, Eq)]
252struct AstField {
253 name: String,
254 base_type: String,
255 quantifier: Quantifier,
256}
257
258impl AstField {
259 const fn new(name: String, base_type: String, quantifier: Quantifier) -> Self {
260 Self {
261 name,
262 base_type,
263 quantifier,
264 }
265 }
266
267 fn type_name(&self) -> String {
268 match self.quantifier {
269 Quantifier::Single => self.base_type.clone(),
270 Quantifier::Optional => format!("Option<{}>", self.base_type),
271 Quantifier::Repeated => format!("Vec<{}>", self.base_type),
272 }
273 }
274}
275
276#[derive(Clone, Copy, Debug, PartialEq, Eq)]
277enum Quantifier {
278 Single,
279 Optional,
280 Repeated,
281}
282
283const fn combine_quantifier(outer: Quantifier, inner: Quantifier) -> Quantifier {
284 match (outer, inner) {
285 (Quantifier::Repeated, _) | (_, Quantifier::Repeated) => Quantifier::Repeated,
286 (Quantifier::Optional, _) | (_, Quantifier::Optional) => Quantifier::Optional,
287 (Quantifier::Single, Quantifier::Single) => Quantifier::Single,
288 }
289}
290
291fn is_terminal_only(expr: &GrammarExpr) -> bool {
292 match expr {
293 GrammarExpr::Empty
294 | GrammarExpr::Terminal(_)
295 | GrammarExpr::TerminalInsensitive(_)
296 | GrammarExpr::CharRange(_, _)
297 | GrammarExpr::CharClass { .. }
298 | GrammarExpr::AnyChar => true,
299 GrammarExpr::NonTerminal(_) | GrammarExpr::Feature(_) => false,
300 GrammarExpr::Choice { alternatives, .. } | GrammarExpr::Sequence(alternatives) => {
301 alternatives.iter().all(is_terminal_only)
302 }
303 GrammarExpr::Optional(expr)
304 | GrammarExpr::ZeroOrMore(expr)
305 | GrammarExpr::OneOrMore(expr)
306 | GrammarExpr::And(expr)
307 | GrammarExpr::Not(expr)
308 | GrammarExpr::Capture { expr, .. }
309 | GrammarExpr::Repeat { expr, .. } => is_terminal_only(expr),
310 }
311}
312
313fn render_rust_types(shapes: &[RustTypeShape]) -> String {
314 let mut output = String::new();
315 for (index, shape) in shapes.iter().enumerate() {
316 if index > 0 {
317 output.push('\n');
318 }
319 output.push_str(&render_rust_type(shape));
320 }
321 output
322}
323
324fn render_parser_struct(name: &str, pest_grammar: &str) -> String {
325 format!(
326 "#[derive(pest_derive::Parser)]\n#[grammar_inline = {pest_grammar:?}]\npub struct {name};\n"
327 )
328}
329
330fn render_struct(shape: &RustTypeShape) -> String {
331 if shape.fields().is_empty() {
332 return format!("#[derive(Debug, Clone)]\npub struct {};\n", shape.name());
333 }
334
335 if tuple_fields(shape.fields()) {
336 let fields = shape
337 .fields()
338 .iter()
339 .map(|field| format!("pub {}", field.type_name()))
340 .collect::<Vec<_>>()
341 .join(", ");
342 return format!(
343 "#[derive(Debug, Clone)]\npub struct {}({fields});\n",
344 shape.name()
345 );
346 }
347
348 let mut output = format!("#[derive(Debug, Clone)]\npub struct {} {{\n", shape.name());
349 for field in shape.fields() {
350 output.push_str(" pub ");
351 output.push_str(field.name());
352 output.push_str(": ");
353 output.push_str(field.type_name());
354 output.push_str(",\n");
355 }
356 output.push_str("}\n");
357 output
358}
359
360fn render_enum(shape: &RustTypeShape) -> String {
361 let mut output = format!("#[derive(Debug, Clone)]\npub enum {} {{\n", shape.name());
362 for field in shape.fields() {
363 output.push_str(" ");
364 output.push_str(field.name());
365 if field.type_name() == "()" {
366 output.push_str(",\n");
367 } else {
368 output.push('(');
369 output.push_str(field.type_name());
370 output.push_str("),\n");
371 }
372 }
373 output.push_str("}\n");
374 output
375}
376
377fn render_trait(shape: &RustTypeShape) -> String {
378 let mut output = format!("pub trait {} {{\n", shape.name());
379 for field in shape.fields() {
380 output.push_str(" fn ");
381 output.push_str(field.name());
382 output.push_str("(&self) -> ");
383 output.push_str(field.type_name());
384 output.push_str(";\n");
385 }
386 output.push_str("}\n");
387 output
388}
389
390fn render_sequence(shape: &RustTypeShape) -> String {
391 let element_type = shape
392 .fields()
393 .first()
394 .map_or("()", RustFieldShape::type_name);
395 format!(
396 "#[derive(Debug, Clone)]\npub struct {}(pub Vec<{element_type}>);\n",
397 shape.name()
398 )
399}
400
401fn render_option(shape: &RustTypeShape) -> String {
402 let some_type = shape
403 .fields()
404 .first()
405 .map_or("()", RustFieldShape::type_name);
406 format!(
407 "#[derive(Debug, Clone)]\npub enum {} {{\n Some({some_type}),\n None,\n}}\n",
408 shape.name()
409 )
410}
411
412fn render_map(shape: &RustTypeShape) -> String {
413 let key_type = shape
414 .fields()
415 .iter()
416 .find(|field| field.name() == "key")
417 .map_or("()", RustFieldShape::type_name);
418 let value_type = shape
419 .fields()
420 .iter()
421 .find(|field| field.name() == "value")
422 .map_or("()", RustFieldShape::type_name);
423 format!(
424 "#[derive(Debug, Clone)]\npub struct {}(pub std::collections::BTreeMap<{key_type}, {value_type}>);\n",
425 shape.name()
426 )
427}
428
429fn tuple_fields(fields: &[RustFieldShape]) -> bool {
430 fields.iter().enumerate().all(|(index, field)| {
431 field
432 .name()
433 .parse::<usize>()
434 .is_ok_and(|field_index| field_index == index)
435 })
436}
437
438fn parser_struct_name(grammar: &Grammar) -> String {
439 let base = grammar.start_rule().map_or("Generated", GrammarRule::name);
440 format!("{}Parser", rust_type_name(base))
441}
442
443const RESERVED_TYPE_NAMES: &[&str] = &["Box", "Option", "Result", "Rule", "Self", "String", "Vec"];
446
447fn rust_type_name(value: &str) -> String {
448 let name = rust_type_name_with_fallback(value, "Generated");
449 if RESERVED_TYPE_NAMES.contains(&name.as_str()) {
450 format!("{name}Node")
451 } else {
452 name
453 }
454}
455
456fn rust_type_name_with_fallback(value: &str, fallback: &str) -> String {
457 let mut output = String::new();
458 let mut next_upper = true;
459 for character in value.chars() {
460 if character.is_ascii_alphanumeric() {
461 if output.is_empty() && character.is_ascii_digit() {
462 output.push_str(fallback);
463 }
464 if next_upper {
465 output.push(character.to_ascii_uppercase());
466 } else {
467 output.push(character.to_ascii_lowercase());
468 }
469 next_upper = false;
470 } else {
471 next_upper = true;
472 }
473 }
474
475 if output.is_empty() {
476 fallback.to_string()
477 } else {
478 output
479 }
480}
481
482fn rust_field_name(value: &str) -> String {
483 let mut output = String::new();
484 let mut previous_was_separator = false;
485
486 for (index, character) in value.chars().enumerate() {
487 if character.is_ascii_alphanumeric() {
488 if output.is_empty() && character.is_ascii_digit() {
489 output.push_str("field_");
490 }
491 if character.is_ascii_uppercase()
492 && !output.is_empty()
493 && index > 0
494 && !previous_was_separator
495 {
496 output.push('_');
497 }
498 output.push(character.to_ascii_lowercase());
499 previous_was_separator = false;
500 } else if !output.is_empty() && !previous_was_separator {
501 output.push('_');
502 previous_was_separator = true;
503 }
504 }
505
506 while output.ends_with('_') {
507 output.pop();
508 }
509
510 if output.is_empty() {
511 output.push_str("field");
512 }
513
514 if is_rust_keyword(&output) {
515 format!("r#{output}")
516 } else {
517 output
518 }
519}
520
521fn unique_name(name: String, used: &mut BTreeSet<String>) -> String {
522 if used.insert(name.clone()) {
523 return name;
524 }
525
526 for index in 2.. {
527 let candidate = format!("{name}{index}");
528 if used.insert(candidate.clone()) {
529 return candidate;
530 }
531 }
532
533 unreachable!("unbounded unique-name loop always returns")
534}
535
536fn is_rust_keyword(value: &str) -> bool {
537 matches!(
538 value,
539 "as" | "break"
540 | "const"
541 | "continue"
542 | "crate"
543 | "else"
544 | "enum"
545 | "extern"
546 | "false"
547 | "fn"
548 | "for"
549 | "if"
550 | "impl"
551 | "in"
552 | "let"
553 | "loop"
554 | "match"
555 | "mod"
556 | "move"
557 | "mut"
558 | "pub"
559 | "ref"
560 | "return"
561 | "self"
562 | "Self"
563 | "static"
564 | "struct"
565 | "super"
566 | "trait"
567 | "true"
568 | "type"
569 | "unsafe"
570 | "use"
571 | "where"
572 | "while"
573 | "async"
574 | "await"
575 | "dyn"
576 )
577}