ast_description_lang/ast/
print.rs

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}