1use super::{
2 collapsed::{Ast, Choice, ChoiceKind, Group, GroupKind, Node, NodeKind},
3 Modifier,
4};
5use crate::{collections::NamedItem, is_rust_keyword, Ident, Specs};
6use heck::ToPascalCase;
7use proc_macro2::TokenStream;
8use quote::{format_ident, quote, ToTokens};
9
10impl Ast<'_> {
11 pub fn print(
12 &self,
13 specs: &Specs<'_>,
14 error: TokenStream,
15 tokens_mod: TokenStream,
16 span: Option<TokenStream>,
17 ) -> TokenStream {
18 let span = span.map(|span| quote! { type Span = #span; });
19 let member_span = span.as_ref().map(|_| quote! { pub span: Span });
20
21 let nodes = self.iter().filter_map(|node| match &node.kind {
22 NodeKind::Node(_)
23 | NodeKind::StaticToken(_)
24 | NodeKind::DynamicToken(_)
25 | NodeKind::Choice(Choice {
26 kind: ChoiceKind::Option { .. },
27 inline: _,
28 }) => None,
29 NodeKind::Group(Group {
30 members,
31 kind,
32 inline: _,
33 }) => match kind {
34 GroupKind::One(_) => None,
35 GroupKind::Many(indices) => {
36 let mut members = indices
37 .iter()
38 .copied()
39 .map(|idx| &members[idx])
40 .filter(|node| !self.is_node_kind_zero_sized(&node.kind))
41 .map(|node| {
42 let ident = node.tag.unwrap_or(node.ident);
43 let ty = self.print_as_type(&node.kind, Some(node.ident));
44 quote! { pub #ident: #ty }
45 })
46 .peekable();
47
48 if members.peek().is_none() {
49 None
50 } else {
51 let ident = node.ident.as_type();
52 Some(quote! {
53 #[derive(Clone, Debug)]
54 pub struct #ident { #(#members),*, #member_span }
55 })
56 }
57 }
58 },
59 NodeKind::SubGroup(_) => unreachable!("top level sub-group"),
60 NodeKind::Choice(Choice {
61 kind: ChoiceKind::Regular(choices),
62 inline: _,
63 }) => {
64 let variants = choices.iter().map(|choice| {
65 let name = choice
66 .tag
67 .unwrap_or(choice.ident)
68 .to_string()
69 .to_pascal_case();
70 let name = Ident(&name);
71 let body = if self.is_node_kind_zero_sized(&choice.kind) {
72 quote! {}
73 } else {
74 let ty = self.print_as_type(&choice.kind, Some(choice.ident));
75 quote! { (#ty) }
76 };
77 quote! { #name #body }
78 });
79
80 let ident = format_ident!("{}", node.ident.0.to_pascal_case());
81 Some(quote! {
82 #[derive(Clone, Debug)]
83 pub enum #ident { #(#variants),* }
84 })
85 }
86 NodeKind::Delimited(inner, _delimiter) => match &**inner {
87 NodeKind::Node(_) | NodeKind::StaticToken(_) | NodeKind::DynamicToken(_) => None,
88 NodeKind::Group(Group {
89 members,
90 kind,
91 inline: _,
92 }) => match kind {
93 GroupKind::One(_) => None,
94 GroupKind::Many(indices) => {
95 let members = indices
96 .iter()
97 .copied()
98 .map(|idx| &members[idx])
99 .filter(|node| !self.is_node_kind_zero_sized(&node.kind))
100 .map(|node| {
101 let ident = node.tag.unwrap_or(node.ident);
102 let ty = self.print_as_type(&node.kind, Some(node.ident));
103 quote! { pub #ident: #ty }
104 });
105
106 let ident = node.ident.as_type();
107 Some(quote! {
108 #[derive(Clone, Debug)]
109 pub struct #ident { #(#members),*, #member_span }
110 })
111 }
112 },
113 NodeKind::SubGroup(_)
114 | NodeKind::Choice(_)
115 | NodeKind::Delimited(_, _)
116 | NodeKind::Modified(_, _)
117 | NodeKind::Todo => None,
118 NodeKind::End => unreachable!(),
119 },
120 NodeKind::Modified(..) => None,
121 NodeKind::Todo => None,
122 NodeKind::End => None,
123 });
124
125 let parsers = self
126 .nodes
127 .iter()
128 .map(|node| self.print_parser(node, specs, span.is_some()));
129
130 let recursive_parsers = self.print_recursive_parsers(specs, span.is_some());
131
132 quote! {
133 #![allow(dead_code)]
134
135 use #tokens_mod::*;
136 #(#nodes)*
137
138 #span
139
140 pub mod parse {
141 use super::*;
142 use chumsky::prelude::*;
143 use #tokens_mod::{parse::*, Token};
144
145 type Error = #error;
146
147 #(#parsers)*
148 #recursive_parsers
149 }
150 }
151 }
152
153 fn print_as_type(&self, kind: &NodeKind<'_>, hint: Option<Ident<'_>>) -> TokenStream {
154 match kind {
155 NodeKind::Node(child) => match self.get(*child) {
156 Some(child) => self.print_as_type(&child.kind, Some(child.ident)),
157 None => {
158 let message = format!("missing node `{child}`");
159 quote! { compile_error!(#message) }
160 }
161 },
162 NodeKind::StaticToken(_) => unreachable!("tried to print type of static token"),
163 NodeKind::DynamicToken(ident) => ident.as_type().to_token_stream(),
164 NodeKind::Group(Group {
165 members,
166 kind,
167 inline: _,
168 }) => match kind {
169 GroupKind::One(idx) => {
170 let node = &members[*idx];
171 self.print_as_type(&node.kind, Some(node.ident))
172 }
173 GroupKind::Many(_) => hint.unwrap().as_type().to_token_stream(),
174 },
175 NodeKind::SubGroup(_) => quote! { () },
176 NodeKind::Choice(Choice {
177 kind: ChoiceKind::Regular(_),
178 inline: _,
179 }) => hint.unwrap().as_type().to_token_stream(),
180 NodeKind::Choice(Choice {
181 kind: ChoiceKind::Option {
182 primary,
183 secondary: _,
184 },
185 inline: _,
186 }) => {
187 let ty = self.print_as_type(&primary.kind, Some(primary.ident));
188 quote! { Option<#ty> }
189 }
190 NodeKind::Delimited(inner, _) => self.print_as_type(inner, hint),
191 NodeKind::Modified(inner, modifier) => self.print_modified_type(&**inner, None, *modifier),
192 NodeKind::Todo | NodeKind::End => quote! { () },
193 }
194 }
195
196 fn print_modified_type(
197 &self,
198 kind: &NodeKind<'_>,
199 hint: Option<Ident<'_>>,
200 modifier: Modifier,
201 ) -> TokenStream {
202 match modifier {
203 Modifier::Repeat | Modifier::Csv | Modifier::OnePlus | Modifier::CsvOnePlus => {
204 if self.is_node_kind_zero_sized(kind) {
205 quote! { usize }
206 } else {
207 let ty = self.print_as_type(kind, hint);
208 quote! { Vec<#ty> }
209 }
210 }
211 Modifier::Optional => {
212 if self.is_node_kind_zero_sized(kind) {
213 quote! { bool }
214 } else {
215 let ty = self.print_as_type(kind, None);
216 quote! { Option<#ty> }
217 }
218 }
219 Modifier::Boxed => {
220 let ty = self.print_as_type(kind, hint);
221 quote! { Box<#ty> }
222 }
223 }
224 }
225
226 fn print_parser(&self, node: &Node<'_>, specs: &Specs<'_>, include_span: bool) -> TokenStream {
227 let ident = node.ident;
228 let ty = if self.is_node_kind_zero_sized(&node.kind) {
229 quote! { () }
230 } else {
231 self.print_as_type(&node.kind, Some(node.ident))
232 };
233 let body = if self.is_node_cyclic(node) {
234 let idx = self.index_of(node.ident).unwrap();
235 let idx = self.cyclic.binary_search(&idx).unwrap();
236 let idx = proc_macro2::Literal::usize_unsuffixed(idx);
237 quote! { RECURSIVE.with(|parsers| parsers.borrow().#idx.clone()) }
238 } else {
239 self.print_parser_body(&node.kind, Some(node.ident), specs, include_span)
240 };
241
242 quote! {
243 pub fn #ident() -> impl Parser<Token, #ty, Error = Error> { #body }
244 }
245 }
246
247 fn print_parser_body(
248 &self,
249 node_kind: &NodeKind<'_>,
250 hint: Option<Ident<'_>>,
251 specs: &Specs<'_>,
252 include_span: bool,
253 ) -> TokenStream {
254 match node_kind {
255 NodeKind::Node(child) => quote! { #child() },
256 NodeKind::StaticToken(ident) | NodeKind::DynamicToken(ident) => quote! { #ident() },
257 NodeKind::Group(group) => self.print_group_parser(group, hint, specs, include_span),
258 NodeKind::SubGroup(members) => {
259 let mut members = members.iter();
260 let first = self.print_sub_parser(members.next().unwrap(), specs, false, include_span);
261 let members: Vec<_> = members
262 .map(|node| {
263 let parser = self.print_sub_parser(node, specs, false, include_span);
264 quote! { .then(#parser) }
265 })
266 .collect();
267
268 if members.is_empty() {
269 first
270 } else {
271 quote! { #first #(#members)*.ignored() }
272 }
273 }
274 NodeKind::Choice(Choice {
275 kind: ChoiceKind::Regular(choices),
276 inline: _,
277 }) => {
278 let ty = self.print_as_type(node_kind, hint);
279 let choices = choices.iter().enumerate().map(|(idx, choice)| {
280 let variant = choice.tag.unwrap_or(choice.ident).as_type();
281
282 let parser = self.print_sub_parser(choice, specs, false, include_span);
283
284 let func =
285 self.print_func_for_choice_mapping(&choice.kind, ty.clone(), variant.to_token_stream());
286
287 let choice = quote! { #parser.map(#func) };
288 if idx == 0 {
289 choice
290 } else {
291 quote! { .or(#choice) }
292 }
293 });
294 quote! { #(#choices)* }
295 }
296 NodeKind::Choice(Choice {
297 kind: ChoiceKind::Option { primary, secondary },
298 inline: _,
299 }) => {
300 let primary = self.print_sub_parser(primary, specs, false, include_span);
301 quote! { #primary.map(Some).or(#secondary().map(|_| None)) }
302 }
303 NodeKind::Delimited(inner, delimiter) => self.delimit_parser(
304 self.print_parser_body(inner, hint, specs, include_span),
305 *delimiter,
306 specs,
307 ),
308 NodeKind::Modified(inner, modifier) => {
309 self.print_modified_parser(inner, *modifier, specs, false, include_span)
310 }
311 NodeKind::Todo => print_todo(),
312 NodeKind::End => quote! { end() },
313 }
314 }
315
316 fn print_sub_parser(
317 &self,
318 node: &Node<'_>,
319 specs: &Specs<'_>,
320 inline: bool,
321 include_span: bool,
322 ) -> TokenStream {
323 if inline {
324 self.print_parser_body(&node.kind, None, specs, include_span)
325 } else {
326 let ident = node.ident;
327 let parser = quote! { #ident() };
328 match &node.kind {
329 NodeKind::Node(child) => quote! { #child() },
330 NodeKind::StaticToken(_) | NodeKind::DynamicToken(_) => parser,
331 NodeKind::Group(group @ Group { inline: true, .. }) => {
332 self.print_group_parser(group, None, specs, include_span)
333 }
334 NodeKind::Group(Group { inline: false, .. }) => parser,
335 NodeKind::SubGroup(_) => self.print_parser_body(&node.kind, None, specs, include_span),
336 NodeKind::Choice(Choice { inline: true, .. }) => {
337 self.print_parser_body(&node.kind, None, specs, include_span)
338 }
339 NodeKind::Choice(Choice { inline: false, .. }) => parser,
340 NodeKind::Delimited(inner, delimiter) => {
341 let parser = match &**inner {
342 NodeKind::Node(child) => quote! { #child() },
343 NodeKind::Modified(inner, modifier) => {
344 self.print_modified_parser(inner, *modifier, specs, false, include_span)
345 }
346 _ => parser,
347 };
348 self.delimit_parser(parser, *delimiter, specs)
349 }
350 NodeKind::Modified(inner, modifier) => {
351 self.print_modified_parser(inner, *modifier, specs, false, include_span)
352 }
353 NodeKind::Todo => print_todo(),
354 NodeKind::End => parser,
355 }
356 }
357 }
358
359 fn print_group_parser(
360 &self,
361 Group {
362 members,
363 kind,
364 inline,
365 }: &Group<'_>,
366 hint: Option<Ident<'_>>,
367 specs: &Specs<'_>,
368 include_span: bool,
369 ) -> TokenStream {
370 match kind {
371 GroupKind::One(idx) => {
372 let binding = print_tuple_binding(members.len());
373 let members = self.print_group_members(members, specs, *inline, include_span);
374 let idx = ident_from_idx(*idx);
375 quote! { #members.map(|#binding| #idx ) }
376 }
377 GroupKind::Many(_) => {
378 let ty = hint.unwrap().as_type().to_token_stream();
379 let member_init = self.print_group_members_init(members, include_span);
380 let binding = print_tuple_binding(members.len());
381 let binding = if include_span {
382 quote! { #binding, span }
383 } else {
384 binding
385 };
386 let members = self.print_group_members(members, specs, *inline, include_span);
387 let map_fn = if include_span {
388 quote! { map_with_span }
389 } else {
390 quote! { map }
391 };
392 quote! { #members.#map_fn(|#binding| #ty { #member_init }) }
393 }
394 }
395 }
396
397 fn print_group_members_init(&self, members: &[Node<'_>], include_span: bool) -> TokenStream {
398 let members = members
399 .iter()
400 .enumerate()
401 .filter(|(_, member)| !self.is_node_kind_zero_sized(&member.kind))
402 .map(|(idx, member)| {
403 let ident = member.tag.unwrap_or(member.ident);
404 let idx = ident_from_idx(idx);
405 quote! { #ident: #idx }
406 });
407 let span = include_span.then(|| quote! { span });
408 quote! { #(#members),*, #span }
409 }
410
411 fn print_group_members(
412 &self,
413 members: &[Node<'_>],
414 specs: &Specs<'_>,
415 inline: bool,
416 include_span: bool,
417 ) -> TokenStream {
418 let members = members.iter().enumerate().map(|(current_idx, node)| {
419 let parser = self.print_sub_parser(node, specs, inline, include_span);
420 if current_idx == 0 {
421 parser
422 } else {
423 quote! { .then(#parser) }
424 }
425 });
426 quote! { #(#members)* }
427 }
428
429 fn is_node_cyclic(&self, node: &Node<'_>) -> bool {
430 match node.kind {
431 NodeKind::Node(_) | NodeKind::Group(_) | NodeKind::Choice(_) => {
432 let idx = self.nodes.index_of(node.name()).unwrap();
433 self.cyclic.binary_search(&idx).is_ok()
434 }
435 NodeKind::StaticToken(_)
436 | NodeKind::DynamicToken(_)
437 | NodeKind::Delimited(_, _)
438 | NodeKind::SubGroup(_)
439 | NodeKind::Modified(_, _)
440 | NodeKind::Todo
441 | NodeKind::End => false,
442 }
443 }
444
445 fn delimit_parser(
446 &self,
447 parser: TokenStream,
448 delimiter: Ident<'_>,
449 specs: &Specs<'_>,
450 ) -> TokenStream {
451 match specs.delimiters.get(&delimiter) {
452 Some(delimiter) => {
453 let open = format_ident!("{}", delimiter.open);
454 let close = format_ident!("{}", delimiter.close);
455 quote! { #parser.delimited_by(#open(), #close()) }
456 }
457 None => {
458 let message = format!("missing delimiter: {delimiter}");
459 quote! { compile_error!(#message) }
460 }
461 }
462 }
463
464 fn print_recursive_parsers(&self, specs: &Specs<'_>, include_span: bool) -> TokenStream {
465 let nodes: Vec<_> = self
466 .cyclic
467 .iter()
468 .map(|idx| self.nodes.get_index(*idx).unwrap())
469 .collect();
470
471 let idents = nodes.iter().map(|node| node.ident.to_token_stream());
472 let idents = quote! { (#(#idents),*) };
473
474 let parser_types = nodes.iter().map(|node| {
475 let ty = self.print_as_type(&node.kind, Some(node.ident));
476 quote! { Recursive<'static, Token, #ty, Error> }
477 });
478
479 let decls = nodes.iter().map(|node| {
480 let ident = node.ident;
481 quote! {
482 #[allow(unused_assignments)]
483 let mut #ident = recursive(|_| todo());
484 }
485 });
486
487 let body = nodes.iter().fold(TokenStream::new(), |accum, node| {
488 let ident = node.ident;
489 let parser =
490 self.print_recursive_sub_parser(&node.kind, Some(node.ident), specs, include_span);
491 quote! {
492 #ident = recursive(|#[allow(unused_variables)] #ident| {
493 #accum
494 #parser
495 });
496 }
497 });
498
499 quote! {
500 thread_local! {
501 static RECURSIVE: std::cell::RefCell<RecursiveParsers> =
502 std::cell::RefCell::new(recursive_parsers());
503 }
504 type RecursiveParsers = (#(#parser_types),*);
505 fn recursive_parsers() -> RecursiveParsers {
506 #(#decls)*
507 #body
508 #idents
509 }
510 }
511 }
512
513 fn print_recursive_sub_parser(
514 &self,
515 node_kind: &NodeKind<'_>,
516 hint: Option<Ident<'_>>,
517 specs: &Specs<'_>,
518 include_span: bool,
519 ) -> TokenStream {
520 let do_recursion = |node: &Node<'_>, hint: Option<Ident<'_>>| {
521 let ident = node.ident;
522 if self.is_node_cyclic(node) {
523 quote! { #ident.clone() }
524 } else {
525 self.print_recursive_sub_parser(
526 &node.kind,
527 Some(hint.unwrap_or(ident)),
528 specs,
529 include_span,
530 )
531 }
532 };
533
534 match node_kind {
535 NodeKind::Node(child) => do_recursion(self.get(*child).unwrap(), None),
536 NodeKind::StaticToken(ident) | NodeKind::DynamicToken(ident) => quote! { #ident() },
537 NodeKind::Group(Group {
538 members,
539 kind,
540 inline: _,
541 }) => match kind {
542 GroupKind::One(idx) => {
543 let binding = print_tuple_binding(members.len());
544
545 let members = members.iter().enumerate().map(|(current_idx, node)| {
546 let parser = if self.is_node_cyclic(node) {
547 let ident = node.ident;
548 quote! { #ident.clone() }
549 } else {
550 self.print_recursive_sub_parser(&node.kind, Some(node.ident), specs, include_span)
551 };
552 if current_idx == 0 {
553 parser
554 } else {
555 quote! { .then(#parser) }
556 }
557 });
558
559 let idx = ident_from_idx(*idx);
560
561 quote! { #(#members)*.map(|#binding| #idx ) }
562 }
563 GroupKind::Many(_) => {
564 let ty = self.print_as_type(node_kind, hint);
565 let member_init = self.print_group_members_init(members, include_span);
566 let binding = print_tuple_binding(members.len());
567 let map_fn = if include_span {
568 quote! { map_with_span }
569 } else {
570 quote! { map }
571 };
572 let binding = if include_span {
573 quote! { #binding, span }
574 } else {
575 binding
576 };
577
578 let members = members.iter().enumerate().map(|(current_idx, node)| {
579 let parser = do_recursion(node, None);
580 if current_idx == 0 {
581 parser
582 } else {
583 quote! { .then(#parser) }
584 }
585 });
586
587 quote! { #(#members)*.#map_fn(|#binding| #ty { #member_init }) }
588 }
589 },
590 NodeKind::SubGroup(_) => self.print_parser_body(node_kind, None, specs, include_span),
591 NodeKind::Choice(Choice {
592 kind: ChoiceKind::Regular(choices),
593 inline: _,
594 }) => {
595 let ty = self.print_as_type(node_kind, hint);
596 let choices = choices.iter().enumerate().map(|(idx, node)| {
597 let variant = node.tag.unwrap_or(node.ident).as_type();
598 let parser = do_recursion(node, None);
599 let func =
600 self.print_func_for_choice_mapping(&node.kind, ty.clone(), variant.to_token_stream());
601 let choice = quote! { #parser.map(#func) };
602 if idx == 0 {
603 choice
604 } else {
605 quote! { .or(#choice) }
606 }
607 });
608 quote! { #(#choices)* }
609 }
610 NodeKind::Choice(Choice {
611 kind: ChoiceKind::Option { primary, secondary },
612 inline: _,
613 }) => {
614 let primary = if self.is_node_cyclic(primary) {
615 let ident = primary.ident;
616 quote! { #ident.clone() }
617 } else {
618 match &primary.kind {
619 NodeKind::Group(_) => self.print_recursive_sub_parser(
620 &primary.kind,
621 Some(primary.ident),
622 specs,
623 include_span,
624 ),
625 _ => {
626 let ident = primary.ident;
627 quote! { #ident() }
628 }
629 }
630 };
631 quote! { #primary.map(Some).or(#secondary().map(|_| None)) }
632 }
633 NodeKind::Delimited(inner, delimiter) => self.delimit_parser(
634 self.print_recursive_sub_parser(inner, hint, specs, include_span),
635 *delimiter,
636 specs,
637 ),
638 NodeKind::Modified(inner, modifier) => {
639 self.print_modified_parser(inner, *modifier, specs, true, include_span)
640 }
641 NodeKind::Todo => print_todo(),
642 NodeKind::End => quote! { end() },
643 }
644 }
645
646 fn print_func_for_choice_mapping(
647 &self,
648 kind: &NodeKind<'_>,
649 ty: TokenStream,
650 variant: TokenStream,
651 ) -> TokenStream {
652 match kind {
653 NodeKind::Node(child) => {
654 self.print_func_for_choice_mapping(&self.get(*child).unwrap().kind, ty, variant)
655 }
656 NodeKind::StaticToken(_) => quote! { |_| #ty::#variant },
657 NodeKind::DynamicToken(_) => quote! { #ty::#variant },
658 NodeKind::Group(Group {
659 members: _,
660 kind,
661 inline: _,
662 }) => match kind {
663 GroupKind::One(_) => quote! { #ty::#variant },
664 GroupKind::Many(_) => quote! { #ty::#variant },
665 },
666 NodeKind::SubGroup(_) => quote! { |_| #ty::#variant },
667 NodeKind::Choice(_) => quote! { #ty::#variant },
668 NodeKind::Delimited(_, _) => quote! { #ty::#variant },
669 NodeKind::Modified(_, _) => quote! { #ty::#variant },
670 NodeKind::Todo => quote! { |_| #ty::#variant },
671 NodeKind::End => quote! { |_| #ty::#variant },
672 }
673 }
674
675 fn print_modified_parser(
676 &self,
677 inner: &NodeKind<'_>,
678 modifier: Modifier,
679 specs: &Specs<'_>,
680 recursive: bool,
681 include_span: bool,
682 ) -> TokenStream {
683 if self.is_node_kind_zero_sized(inner) {
684 let inner = self.print_parser_body(inner, None, specs, include_span);
685
686 match modifier {
687 Modifier::Repeat => quote! { #inner.repeated().map(|items| items.len()) },
688 Modifier::Csv => quote! { #inner.separated_by(comma()).map(|items| items.len()) },
689 Modifier::OnePlus => quote! { #inner.repeated().at_least(1).map(|items| items.len()) },
690 Modifier::CsvOnePlus => {
691 quote! { #inner.separated_by(comma()).at_least(1).map(|items| items.len()) }
692 }
693 Modifier::Optional => quote! { #inner.or_not().map(|opt| opt.is_some()) },
694 Modifier::Boxed => unreachable!("empty box"),
695 }
696 } else {
697 let inner = if recursive {
698 self.print_recursive_sub_parser(inner, None, specs, include_span)
699 } else {
700 self.print_parser_body(inner, None, specs, include_span)
701 };
702
703 match modifier {
704 Modifier::Repeat => quote! { #inner.repeated() },
705 Modifier::Csv => quote! { #inner.separated_by(comma()) },
706 Modifier::OnePlus => quote! { #inner.repeated().at_least(1) },
707 Modifier::CsvOnePlus => {
708 quote! { #inner.separated_by(comma()).at_least(1) }
709 }
710 Modifier::Optional => quote! { #inner.or_not() },
711 Modifier::Boxed => quote! { #inner.map(Box::new) },
712 }
713 }
714 }
715
716 #[must_use]
717 fn is_node_kind_zero_sized(&self, node_kind: &NodeKind<'_>) -> bool {
718 match node_kind {
719 NodeKind::Node(child) => self.is_node_kind_zero_sized(&self.get(*child).unwrap().kind),
720 NodeKind::StaticToken(_) => true,
721 NodeKind::DynamicToken(_) => false,
722 NodeKind::Group(_) => false,
723 NodeKind::SubGroup(_) => true,
724 NodeKind::Choice(_) => false,
725 NodeKind::Delimited(inner, _) => self.is_node_kind_zero_sized(inner),
726 NodeKind::Modified(_, _) => false,
727 NodeKind::Todo => true,
728 NodeKind::End => true,
729 }
730 }
731}
732
733impl ToTokens for Ident<'_> {
734 fn to_tokens(&self, tokens: &mut TokenStream) {
735 let ident = if is_rust_keyword(self.0) {
736 format_ident!("{}_", self.0)
737 } else {
738 format_ident!("{}", self.0)
739 };
740 tokens.extend(quote! { #ident })
741 }
742}
743
744fn print_todo() -> TokenStream {
745 quote! { todo::<Token, (), Error>() }
746}
747
748fn print_tuple_binding(len: usize) -> TokenStream {
749 (1..len).fold(ident_from_idx(0).to_token_stream(), |accum, idx| {
750 let ident = ident_from_idx(idx);
751 quote! { (#accum, #ident) }
752 })
753}
754
755fn ident_from_idx(idx: usize) -> proc_macro2::Ident {
756 format_ident!("_{idx}")
757}
758
759#[cfg(test)]
760#[test]
761fn snapshots() {
762 use super::raw::Ast;
763 use crate::Config;
764 use insta::{assert_snapshot, with_settings};
765 use std::{
766 fs,
767 io::Write,
768 path::Path,
769 process::{Command, Stdio},
770 str::FromStr,
771 };
772
773 for name in crate::SNAPSHOT_CASES {
774 let mut path = Path::new(env!("CARGO_MANIFEST_DIR"))
775 .join("examples")
776 .join(name)
777 .join("example");
778
779 path.set_extension("toml");
780 let specs = fs::read_to_string(&path).unwrap();
781 let specs = toml::de::from_str(&specs).unwrap();
782
783 path.set_extension("ast");
784 let text = fs::read_to_string(&path).unwrap();
785
786 let config = Config::default();
787
788 let printed = Ast::parse(&text)
789 .unwrap()
790 .transform(&specs)
791 .unwrap()
792 .transform()
793 .unwrap()
794 .print(
795 &specs,
796 TokenStream::from_str(config.error).unwrap(),
797 TokenStream::from_str(config.tokens_mod).unwrap(),
798 None,
799 )
800 .to_string();
801 let rustfmt = Command::new("rustfmt")
802 .stdin(Stdio::piped())
803 .stdout(Stdio::piped())
804 .spawn()
805 .expect("starting rustfmt process");
806 rustfmt
807 .stdin
808 .as_ref()
809 .unwrap()
810 .write_all(printed.as_bytes())
811 .unwrap();
812 let output = rustfmt
813 .wait_with_output()
814 .expect("collect output from rustfmt");
815 let status = output.status;
816 if !status.success() {
817 let message = std::str::from_utf8(&output.stderr).unwrap();
818 panic!("rustfmt failed: {status}\n{message}");
819 }
820 let printed = std::str::from_utf8(&output.stdout).unwrap();
821
822 with_settings!({input_file => Some(path)}, {
823 assert_snapshot!(printed);
824 });
825 }
826}