1extern crate proc_macro;
2
3#[allow(warnings)]
4mod grammar;
5mod manual_grammar;
6
7use {
8 crate::{
9 grammar::{Item, *},
10 manual_grammar::*,
11 },
12 indexmap::{IndexMap, IndexSet},
13 itertools::{izip, zip, Itertools},
14 matches::{assert_matches, matches},
15 proc_macro2::{Span, TokenStream},
16 quote::{quote, TokenStreamExt},
17 syn::{parse_quote, spanned::Spanned, Ident, Result},
18 uuid::Uuid,
19};
20
21fn new_uuidv4_ident() -> Ident {
23 Ident::new(
24 &format!("_{}", Uuid::new_v4().to_simple()),
25 Span::call_site(),
26 )
27}
28
29#[proc_macro]
30pub fn pegcel_syn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
33 let ident = new_uuidv4_ident();
34 let input: proc_macro2::TokenStream = input.into();
35 (quote! {
36 #[derive(::pegcel_macros::__pegcel_syn_dummy_derive)]
37 #[real_input(#input)]
38 struct #ident;
39 })
40 .into()
41}
42
43#[doc(hidden)]
44#[proc_macro_derive(__pegcel_syn_dummy_derive, attributes(real_input))]
45pub fn pegcel_syn_real(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
46 let input: Parenthesized<proc_macro2::TokenStream> = syn::parse2(
47 syn::parse_macro_input!(tokens as syn::DeriveInput)
48 .attrs
49 .into_iter()
50 .find(|attr| attr.path.is_ident("real_input"))
51 .unwrap()
52 .tts,
53 )
54 .unwrap();
55 let input: proc_macro::TokenStream = input.0.into();
56
57 make_syn(syn::parse_macro_input!(input))
59 .unwrap_or_else(|err| err.to_compile_error())
60 .into()
62}
63
64struct Parenthesized<T>(T);
65impl<T: syn::parse::Parse> syn::parse::Parse for Parenthesized<T> {
66 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
67 let content;
68 syn::parenthesized!(content in input);
69 Ok(Parenthesized(content.parse()?))
70 }
71}
72
73impl Item {
74 fn unnamed(&self) -> &UnnamedItem {
75 match self {
76 Item::Unnamed(item) => item,
77 Item::Named(named) => &named.item,
78 }
79 }
80}
81
82impl Predicate {
83 fn positive(&self) -> bool {
84 match self {
85 Predicate::Positive(_) => true,
86 Predicate::Negative(_) => false,
87 }
88 }
89}
90
91fn make_syn(input: Grammar) -> Result<proc_macro2::TokenStream> {
92 assert_matches!(input.kind, GrammarUse::Syn(..));
94
95 let mut output = TokenStream::new();
96
97 output.append_all(quote! {
99 extern crate proc_macro2;
101 extern crate quote;
102 extern crate syn;
103 });
104
105 for Use { anchor, tree, .. } in &input.uses {
107 output.append_all(quote! {
108 use #anchor #tree ;
109 })
110 }
111
112 output.append_all(custom_tokens(&input));
114
115 for item in input.items {
116 output.append_all(make_production_def(item)?);
117 }
118
119 Ok(output)
120}
121
122fn custom_tokens(input: &Grammar) -> TokenStream {
123 #[derive(Debug, Default)]
124 struct Visitor {
125 custom_keywords: IndexSet<Ident>,
126 custom_punctuation: IndexMap<String, Ident>,
127 };
128
129 impl Visitor {
130 fn to_defs(&self) -> TokenStream {
131 let mut tokens = TokenStream::new();
132
133 let keywords = &self.custom_keywords;
134 let kws = &self.custom_keywords;
135 let punct_name: Vec<_> = self.custom_punctuation.values().collect();
136 let punct_name = &*punct_name;
137 let punct_val: Vec<TokenStream> = self
138 .custom_punctuation
139 .keys()
140 .map(|it| syn::parse_str(it).unwrap())
141 .collect();
142 let punct_val = &*punct_val;
143
144 let token_macro = new_uuidv4_ident();
145
146 tokens.append_all(quote! {
147 pub mod kw {
148 #(::syn::custom_keyword!(#keywords);)*
149 }
150 pub mod punct {
151 #(::syn::custom_punctuation!(#punct_name, #punct_val);)*
152 }
153 #[doc(hidden)]
154 macro_rules! #token_macro {
155 #((#keywords) => {self::kw::#kws};)*
156 #((#punct_val) => {self::punct::#punct_name};)*
157 ($($tt:tt)*) => {::syn::Token![$($tt)*]};
158 }
159 pub(crate) use #token_macro as Token;
163 });
164
165 tokens
166 }
167
168 fn visit_grammar(&mut self, grammar: &Grammar) -> &mut Self {
169 for named in &grammar.items {
170 self.visit_unnamed_item(&named.item);
171 }
172 self
173 }
174
175 fn visit_unnamed_item(&mut self, item: &UnnamedItem) -> &mut Self {
176 match item {
177 UnnamedItem::Predicated(_, item) => self.visit_unnamed_item(item),
178 UnnamedItem::Repeated(item, rep) => {
179 self.visit_unnamed_item(item);
180 match rep {
181 Repetition::OnePlus(_, Some(inter))
182 | Repetition::ZeroPlus(_, Some(inter)) => match inter {
183 Interspersion::Terminated(_, sym)
184 | Interspersion::Separated(_, sym) => self.visit_symbol(sym),
185 },
186 _ => self,
187 }
188 }
189 UnnamedItem::Block(items) => {
190 match &items.value {
191 Items::Sequence(items) => {
192 for item in items {
193 match &item {
194 Item::Named(named) => self.visit_unnamed_item(&named.item),
195 Item::Unnamed(item) => self.visit_unnamed_item(item),
196 };
197 }
198 }
199 Items::OrderedChoice(_, items) => {
200 for named in items {
201 self.visit_unnamed_item(&named.item);
202 }
203 }
204 }
205 self
206 }
207 UnnamedItem::Symbol(symb) => self.visit_symbol(symb),
208 }
209 }
210
211 fn visit_symbol(&mut self, symbol: &Symbol) -> &mut Self {
212 match symbol {
213 Symbol::Path(_) => (),
214 Symbol::Literal(lit) => match &*lit.value() {
215 "abstract" | "as" | "async" | "auto" | "become" | "box" | "break" | "const"
216 | "continue" | "crate" | "default" | "do" | "dyn" | "else" | "enum"
217 | "existential" | "extern" | "final" | "fn" | "for" | "if" | "impl" | "in"
218 | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "override"
219 | "priv" | "pub" | "ref" | "return" | "Self" | "self" | "static" | "struct"
220 | "super" | "trait" | "try" | "type" | "typeof" | "union" | "unsafe"
221 | "unsized" | "use" | "virtual" | "where" | "while" | "yield" | "+" | "+="
222 | "&" | "&&" | "&=" | "@" | "!" | "^" | "^=" | ":" | "::" | "," | "/"
223 | "/=" | "." | ".." | "..." | "..=" | "=" | "==" | ">=" | ">" | "<=" | "<"
224 | "*=" | "!=" | "|" | "|=" | "||" | "#" | "?" | "->" | "<-" | "%" | "%="
225 | "=>" | ";" | "<<" | "<<=" | ">>" | ">>=" | "*" | "-" | "-=" | "~" | "_" => (),
226 s => {
227 if s.chars()
228 .all(|c| 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z')
229 {
230 self.custom_keywords
231 .insert(Ident::new(s, Span::call_site()));
232 } else {
233 self.custom_punctuation
234 .insert(lit.value(), new_uuidv4_ident());
235 }
236 }
237 },
238 }
239 self
240 }
241 }
242
243 Visitor::default().visit_grammar(input).to_defs()
244}
245
246fn make_production_def(input: NamedItem) -> Result<TokenStream> {
247 let items = if let UnnamedItem::Block(Braced { value, .. }) = input.item {
248 value
249 } else {
250 Err(syn::Error::new(
251 input.item.span(),
252 "Root production must be braced",
253 ))?
254 };
255
256 match items {
257 Items::OrderedChoice(_, items) => {
258 make_enum_production_def(input.name, items.into_iter().collect())
259 }
260 Items::Sequence(items) => make_struct_production_def(input.name, items),
261 }
262}
263
264fn make_enum_production_def(name: Ident, variants: Vec<NamedItem>) -> Result<TokenStream> {
265 let variant_names = variants.iter().map(|item| item.name.clone()).collect_vec();
266 let variant_names = &*variant_names;
267 let name_ = variant_names.iter().map(|_| &name).collect_vec();
268 let variant_fields: Vec<syn::Fields> = variants
269 .iter()
270 .map(|item| match &item.item {
271 UnnamedItem::Block(Braced { value: block, .. }) => {
272 let items = match block {
273 Items::OrderedChoice(..) => Err(syn::Error::new(
275 item.item.span(),
276 "ordered choice not allowed here",
277 ))?,
278 Items::Sequence(items) => items,
279 };
280 Ok(make_fields(items, syn::Visibility::Inherited))
281 }
282 UnnamedItem::Symbol(_) | UnnamedItem::Repeated(..) => {
283 let ty =
285 make_type(&item.item).unwrap_or_else(|| panic!("Non-advancing repetition"));;
286 Ok(syn::Fields::Unnamed(syn::FieldsUnnamed {
287 paren_token: Default::default(),
288 unnamed: {
289 let mut punctuated = syn::punctuated::Punctuated::new();
290 punctuated.push(syn::Field {
291 attrs: vec![],
292 vis: syn::Visibility::Inherited,
293 ident: None,
294 colon_token: None,
295 ty,
296 });
297 punctuated
298 },
299 }))
300 }
301 UnnamedItem::Predicated(..) => Err(syn::Error::new(
302 item.item.span(),
303 "predicate not allowed here",
304 )),
305 })
306 .collect::<Result<_>>()?;
307
308 let param = new_uuidv4_ident();
309
310 let field_names: Vec<Vec<syn::Ident>> = variant_fields
313 .iter()
314 .map(|fields| match fields {
315 syn::Fields::Named(_) => fields
316 .iter()
317 .map(|field| field.ident.as_ref().unwrap().clone())
318 .collect_vec(),
319 syn::Fields::Unnamed(_) => fields.iter().map(|_| new_uuidv4_ident()).collect_vec(),
320 syn::Fields::Unit => unreachable!("Unexpected Unit type {:?}", name),
321 })
322 .collect_vec();
323 let field_pats: Vec<syn::Pat> = izip!(&field_names, &variant_fields)
324 .map(|(names, fields)| match fields {
325 syn::Fields::Named(_) => parse_quote!({ #(#names),* }),
326 syn::Fields::Unnamed(_) => parse_quote!(( #(#names),* )),
327 syn::Fields::Unit => unreachable!("Unexpected Unit type {:?}", name),
328 })
329 .collect_vec();
330
331 let mut to_tokens = TokenStream::new();
332
333 for (fields, field_pat, variant_name, variant) in
334 izip!(&field_names, &field_pats, variant_names, &variants)
335 {
336 let variant = &variant.item;
337 let dt = match variant {
338 UnnamedItem::Predicated(..) => unreachable!("ordered choice cannot be predicate"),
339 UnnamedItem::Repeated(..) | UnnamedItem::Symbol(..) => {
340 tokenize(parse_quote!(#field_pat), variant, ¶m)
342 }
343 UnnamedItem::Block(Braced { value: block, .. }) => {
344 let items = match block {
345 Items::OrderedChoice(..) => panic!("choice not allowed here"),
347 Items::Sequence(items) => items,
348 };
349 let items = items
350 .iter()
351 .filter(|item| make_type(item.unnamed()).is_some())
352 .collect_vec();
353
354 let mut dt = TokenStream::new();
355 assert_eq!(fields.len(), items.len());
356 for (field, item) in zip(fields, items) {
357 dt.extend(tokenize(parse_quote!(#field), item.unnamed(), ¶m));
358 }
359 dt
360 }
361 };
362 to_tokens.extend(quote! {
363 #name :: #variant_name #field_pat => { #dt },
364 })
365 }
366
367 let is_variant = (&variants[..variants.len() - 1])
369 .iter()
370 .map(|item| match &item.item {
371 UnnamedItem::Predicated(..) => unreachable!("checked before"),
372 UnnamedItem::Repeated(..) => {
373 unreachable!("cannot start non-last choice with repetition")
374 }
375 UnnamedItem::Block(Braced { value: block, .. }) => {
376 let items = match block {
377 Items::OrderedChoice(..) => panic!("choice not allowed here"),
379 Items::Sequence(items) => items,
380 };
381 block_la(&items, ¶m)
382 }
383 UnnamedItem::Symbol(symbol) => {
384 let ty = make_symbol_type(symbol);
385 quote!(#param.peek(#ty))
386 }
387 })
388 .chain(Some(quote!(true)))
389 .collect_vec();
390 let parse: Vec<TokenStream> = zip(&*variants, &*field_names)
391 .map(|(variant, fields)| {
392 match &variant.item {
393 UnnamedItem::Predicated(..) => TokenStream::new(), item @ UnnamedItem::Symbol(_) | item @ UnnamedItem::Repeated(..) => {
395 assert_eq!(fields.len(), 1);
396 let field = &fields[0];
397 detokenize(parse_quote!(#field), item, ¶m)
398 }
399 UnnamedItem::Block(Braced { value: block, .. }) => {
400 let items = match block {
401 Items::OrderedChoice(..) => panic!("choice not allowed here"),
403 Items::Sequence(items) => items,
404 };
405 let items = items
406 .iter()
407 .filter(|item| !matches!(item.unnamed(), UnnamedItem::Predicated(..)))
408 .collect_vec();
409 assert_eq!(items.len(), fields.len());
410 let mut dt = TokenStream::new();
411 for (name, item) in zip(fields, items) {
412 dt.extend(detokenize(parse_quote!(#name), item.unnamed(), ¶m));
413 }
414 dt
415 }
416 }
417 })
418 .collect_vec();
419
420 Ok(quote! {
421 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
426 pub enum #name {
427 #(#variant_names #variant_fields,)*
428 }
429
430 impl ::syn::parse::Parse for #name {
431 fn parse(#param: ::syn::parse::ParseStream) -> ::syn::parse::Result<Self> {
432 #(if #is_variant {
433 #(let mut #field_names;)*
434 #parse
435 Ok(#name_ :: #variant_names #field_pats)
436 } else)* {
437 unreachable!("pegcel ordered choice fallthrough case reached")
440 }
441 }
442 }
443
444 impl ::quote::ToTokens for #name {
445 fn to_tokens(&self, #param: &mut ::proc_macro2::TokenStream) {
446 use ::quote::{ToTokens, TokenStreamExt};
447 match self {
448 #to_tokens
449 }
450 }
451 }
452 })
453}
454
455fn make_struct_production_def(name: Ident, members: Vec<Item>) -> Result<TokenStream> {
456 let fields = make_fields(&members, parse_quote!(pub));
457 let param = new_uuidv4_ident();
458
459 let member_names: Vec<syn::Member> = match fields {
462 syn::Fields::Named(_) => fields
463 .iter()
464 .map(|field| syn::Member::Named(field.ident.as_ref().unwrap().clone()))
465 .collect(),
466 syn::Fields::Unnamed(_) => fields
467 .iter()
468 .enumerate()
469 .map(|(i, field)| {
470 syn::Member::Unnamed(syn::Index {
471 index: i as u32,
472 span: field.span(),
473 })
474 })
475 .collect(),
476 syn::Fields::Unit => unreachable!("Unexpected Unit type {:?}", name),
477 };
478 let member_names = &*member_names;
479
480 let mut to_tokens = quote! {
481 use ::quote::{ToTokens, TokenStreamExt};
482 };
483
484 for (name, item) in zip(member_names, &members) {
485 to_tokens.extend(tokenize(
486 parse_quote!((&self.#name)),
487 item.unnamed(),
488 ¶m,
489 ));
490 }
491
492 let field_names: Vec<Ident> = member_names
495 .iter()
496 .map(|member| match member {
497 syn::Member::Named(name) => name.clone(),
498 syn::Member::Unnamed(_) => new_uuidv4_ident(),
499 })
500 .collect();
501 let field_names = &*field_names;
502
503 let mut parse = TokenStream::new();
504
505 for (name, item) in zip(field_names, &members) {
506 parse.extend(detokenize(parse_quote!(#name), item.unnamed(), ¶m));
507 }
508
509 let make_struct = match fields {
510 syn::Fields::Named(_) => quote!(#name { #(#field_names),* }),
511 syn::Fields::Unnamed(_) => quote!(#name( #(#field_names),* )),
512 syn::Fields::Unit => unreachable!("Unexpected Unit type {:?}", name),
513 };
514
515 let fields = match fields {
517 syn::Fields::Unnamed(fields) => quote!(#fields;),
518 syn::Fields::Named(fields) => quote!(#fields),
519 syn::Fields::Unit => unreachable!("Unexpected Unit type {:?}", name),
520 };
521
522 Ok(quote! {
523 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
528 pub struct #name #fields
529
530 impl ::syn::parse::Parse for #name {
531 fn parse(#param: ::syn::parse::ParseStream) -> ::syn::parse::Result<Self> {
532 #(let mut #field_names;)*
533 #parse
534 Ok(#make_struct)
535 }
536 }
537
538 impl ::quote::ToTokens for #name {
539 fn to_tokens(&self, #param: &mut ::proc_macro2::TokenStream) {
540 #to_tokens
541 }
542 }
543 })
544}
545
546fn tokenize(place: syn::Expr, item: &UnnamedItem, param: &Ident) -> TokenStream {
547 match item {
548 UnnamedItem::Predicated(..) => TokenStream::new(), UnnamedItem::Symbol(_) => quote!(#place.to_tokens(#param);),
550 UnnamedItem::Block(Braced { value: block, .. }) => {
551 let items = match block {
552 Items::OrderedChoice(..) => unreachable!("errored earlier"),
553 Items::Sequence(items) => items
554 .iter()
555 .map(|item| match item {
556 Item::Named(_) => unreachable!("errored earlier"),
557 Item::Unnamed(item) => item,
558 })
559 .filter(|item| !matches!(item, UnnamedItem::Predicated(..)))
560 .collect_vec(),
561 };
562 let names = items.iter().map(|_| new_uuidv4_ident()).collect_vec();
563 let tokenization = zip(&names, &items)
564 .map(|(name, item)| tokenize(parse_quote!(#name), item, param))
565 .collect_vec();
566
567 quote! {
568 let (#(#names),*) = #place;
569 #(#tokenization)*
570 }
571 }
572 UnnamedItem::Repeated(item, repetition) => match repetition {
573 Repetition::ZeroOne(_) => quote!(#place.to_tokens(#param);),
574 Repetition::ZeroPlus(_, None) | Repetition::OnePlus(_, None) => {
575 let ident = new_uuidv4_ident();
576 let sub_tokenize = tokenize(parse_quote!(#ident), &item, param);
577 quote! {
578 for #ident in #place {
579 #sub_tokenize
580 }
581 }
582 }
583 Repetition::ZeroPlus(_, Some(_)) | Repetition::OnePlus(_, Some(_)) => {
584 let pair = new_uuidv4_ident();
585 let value = new_uuidv4_ident();
586 let punct = new_uuidv4_ident();
587 let sub_tokenize = tokenize(parse_quote!(#value), &item, param);
588 quote! {
589 for #pair in #place.pairs() {
590 let #value = #pair.value();
591 #sub_tokenize
592
593 if let Some(#punct) = #pair.punct() {
594 #punct.to_tokens(#param);
595 }
596 }
597 }
598 }
599 },
600 }
601}
602
603#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
604#[allow(clippy::enum_variant_names)] enum Peek {
606 Peek1,
607 Peek2,
608 Peek3,
609}
610
611impl Peek {
612 fn succ(self) -> Option<Peek> {
613 match self {
614 Peek::Peek1 => Some(Peek::Peek2),
615 Peek::Peek2 => Some(Peek::Peek3),
616 Peek::Peek3 => None,
617 }
618 }
619 fn succn(self, n: usize) -> Option<Peek> {
620 if n > 0 {
621 self.succ().and_then(|p| p.succn(n - 1))
622 } else {
623 Some(self)
624 }
625 }
626}
627
628fn la(parity: bool, peek: Peek, item: &UnnamedItem, param: &Ident) -> TokenStream {
629 let not = if !parity { quote!(!) } else { quote!() };
630 let f = match peek {
631 Peek::Peek1 => quote!(#not #param.peek),
632 Peek::Peek2 => quote!(#not #param.peek2),
633 Peek::Peek3 => quote!(#not #param.peek3),
634 };
635 match item {
636 UnnamedItem::Predicated(pred, item) => {
637 la(parity == pred.positive(), peek, item, param)
641 }
642 UnnamedItem::Repeated(..) => unreachable!("predicate cannot contain repetition"),
643 UnnamedItem::Symbol(symbol) => {
644 let ty = make_symbol_type(symbol);
645 quote!(#f(#ty))
646 }
647 UnnamedItem::Block(Braced { value: block, .. }) => match block {
648 Items::OrderedChoice(_, items) => {
649 let individual = items
650 .iter()
651 .map(|item| {
652 la(parity, peek, &item.item, param)
654 })
655 .collect_vec();
656 quote!((#(#individual)||*))
657 }
658 Items::Sequence(items) => {
659 let mut i = 0;
660 let i = &mut i;
661 let individual = items
662 .iter()
663 .map(|item| {
664 let expr = la(
666 parity,
667 peek.succn(*i).expect("peek distance"),
668 item.unnamed(),
669 param,
670 );
671 if !matches!(item.unnamed(), UnnamedItem::Predicated(..)) {
672 *i += 1;
673 }
674 expr
675 })
676 .collect_vec();
677 quote!((#(#individual &&)* true))
678 }
679 },
680 }
681}
682
683fn block_la(items: &[Item], param: &Ident) -> TokenStream {
684 assert!(!items.is_empty()); match items[0].unnamed() {
686 UnnamedItem::Block(..) | UnnamedItem::Repeated(..) => {
687 panic!("cannot start repetition with block or repetition")
690 }
691 UnnamedItem::Predicated(pred, item) => la(pred.positive(), Peek::Peek1, item, param),
692 UnnamedItem::Symbol(symbol) => {
693 let ty = make_symbol_type(symbol);
694 quote!(#param.peek(#ty))
695 }
696 }
697}
698
699fn detokenize(place: syn::Expr, item: &UnnamedItem, param: &Ident) -> TokenStream {
700 match item {
701 UnnamedItem::Predicated(pred, item) => {
702 let la = la(pred.positive(), Peek::Peek1, item, param);
703 quote!(assert!(#la);)
704 }
705 UnnamedItem::Symbol(_) => quote!(#place = #param.parse()?;),
706 UnnamedItem::Repeated(item, rep) => match rep {
707 Repetition::ZeroOne(_) => match &**item {
708 UnnamedItem::Predicated(..) | UnnamedItem::Repeated(..) => {
709 unreachable!("repetition cannot contain predicate or repetition")
710 }
711 UnnamedItem::Symbol(_) => quote!(#place = #param.parse()?;),
712 UnnamedItem::Block(Braced { value: block, .. }) => {
713 let items = match block {
714 Items::OrderedChoice(..) => panic!("choice not allowed here"),
716 Items::Sequence(items) => items,
717 };
718 let cond = block_la(items, param);
719 let val = new_uuidv4_ident();
720 let dt = detokenize(parse_quote!(#val), item, param);
721 quote! {
722 if #cond {
723 let #val;
724 #dt
725 #place = Some(#val);
726 } else {
727 #place = None;
728 }
729 }
730 }
731 },
732 Repetition::ZeroPlus(_, None) | Repetition::OnePlus(_, None) => {
733 let cond = match &**item {
734 UnnamedItem::Predicated(..) | UnnamedItem::Repeated(..) => {
735 unreachable!("repetition cannot contain predicate or repetition")
736 }
737 UnnamedItem::Symbol(symbol) => match symbol {
738 Symbol::Path(_) => quote!(!#param.is_empty()),
741 Symbol::Literal(_) => {
742 let ty = make_symbol_type(symbol);
743 quote!(#param.peek(#ty))
744 }
745 },
746 UnnamedItem::Block(Braced { value: block, .. }) => {
747 let items = match block {
748 Items::OrderedChoice(..) => panic!("choice not allowed here"),
750 Items::Sequence(items) => items,
751 };
752 block_la(items, param)
754 }
755 };
756 let val = new_uuidv4_ident();
757 let dt = detokenize(parse_quote!(#val), item, param);
758 let init = match rep {
759 Repetition::ZeroPlus(..) => quote!(),
760 Repetition::OnePlus(..) => quote!({ let #val; #dt #val }),
761 _ => unreachable!("matched above"),
762 };
763 quote! {
764 #place = vec![#init];
765 while #cond {
766 let #val;
767 #dt
768 #place.push(#val);
769 }
770 }
771 }
772 Repetition::ZeroPlus(_, Some(Interspersion::Separated(..))) => quote! {
773 #place = if #param.is_empty {
775 ::syn::punctuated::Punctuated::new();
776 } else {
777 #param.call(::syn::punctuated::Punctuated::parse_separated_nonempty)?;
778 }
779 },
780 Repetition::OnePlus(_, Some(Interspersion::Separated(..))) => quote! {
781 #place = #param.call(::syn::punctuated::Punctuated::parse_separated_nonempty)?;
783 },
784 Repetition::ZeroPlus(_, Some(Interspersion::Terminated(..))) => quote! {
785 #place = #param.call(::syn::punctuated::Punctuated::parse_terminated)?;
787 },
788 Repetition::OnePlus(_, Some(Interspersion::Terminated(..))) => {
789 let fork = new_uuidv4_ident();
791 let ty = make_type(item).unwrap();
792 quote! {
793 let #fork = #param.fork();
794 let _: #ty = #fork.parse()?;
795 #place = #param.call(::syn::punctuated::Punctuated::parse_terminated)?;
796 }
797 }
798 },
799 UnnamedItem::Block(Braced { value: block, .. }) => {
800 let items = match block {
801 Items::OrderedChoice(..) => panic!("choice not allowed in non-root"),
803 Items::Sequence(items) => items,
804 };
805 let mut make = TokenStream::new();
806 let mut ret = vec![];
807 for item in items {
808 let i = new_uuidv4_ident();
809 let p = detokenize(parse_quote!(#i), item.unnamed(), param);
810 if matches!(item.unnamed(), UnnamedItem::Predicated(..)) {
811 make.extend(p);
812 } else {
813 make.extend(quote!(let #i; #p));
814 ret.push(i);
815 }
816 }
817 quote!(#place = { #make (#(#ret),*) };)
818 }
819 }
820}
821
822fn make_fields(items: &[Item], vis: syn::Visibility) -> syn::Fields {
823 if items.iter().any(|item| matches!(item, Item::Named(_))) {
824 syn::Fields::Named(make_named_fields(items.iter(), vis))
825 } else {
826 syn::Fields::Unnamed(make_unnamed_fields(
827 items.iter().map(|item| match item {
828 Item::Unnamed(item) => item,
829 Item::Named(_) => unreachable!(),
830 }),
831 vis,
832 ))
833 }
834}
835
836fn make_named_fields<'a>(
837 items: impl Iterator<Item = &'a Item>,
838 vis: syn::Visibility,
839) -> syn::FieldsNamed {
840 syn::FieldsNamed {
841 brace_token: Default::default(),
842 named: items
843 .map(|item| match item {
844 Item::Named(item) => Some(syn::Field {
845 attrs: vec![],
846 vis: vis.clone(),
847 ident: Some(item.name.clone()),
848 colon_token: Some(Default::default()),
849 ty: make_type(&item.item)?,
850 }),
851 Item::Unnamed(item) => Some(syn::Field {
852 attrs: vec![],
853 vis: syn::Visibility::Inherited,
854 ident: Some(new_uuidv4_ident()),
855 colon_token: Some(Default::default()),
856 ty: make_type(item)?,
857 }),
858 })
859 .flatten()
860 .collect(),
861 }
862}
863
864fn make_unnamed_fields<'a>(
865 items: impl Iterator<Item = &'a UnnamedItem>,
866 vis: syn::Visibility,
867) -> syn::FieldsUnnamed {
868 syn::FieldsUnnamed {
869 paren_token: Default::default(),
870 unnamed: items
871 .map(|item| {
872 Some(syn::Field {
873 attrs: vec![],
874 vis: vis.clone(),
875 ident: None,
876 colon_token: None,
877 ty: make_type(item)?,
878 })
879 })
880 .flatten()
881 .collect(),
882 }
883}
884
885fn make_symbol_type(symbol: &Symbol) -> syn::Type {
886 match symbol {
887 Symbol::Path(path) => syn::Type::Path(syn::TypePath {
888 qself: None,
889 path: (*path).clone(),
890 }),
891 Symbol::Literal(lit) => {
892 let tok: TokenStream = lit
894 .parse()
895 .unwrap_or_else(|_| panic!("Failed to parse token literal"));
896 parse_quote!(Token![#tok])
897 }
898 }
899}
900
901fn make_type(item: &UnnamedItem) -> Option<syn::Type> {
902 match item {
903 UnnamedItem::Predicated(_, _) => None,
904 UnnamedItem::Repeated(item, repetition) => Some({
905 let inner_ty = make_type(item).unwrap_or_else(|| panic!("Non-advancing repetition"));
907 match repetition {
908 Repetition::ZeroOne(_) => parse_quote!(Option<#inner_ty>),
909 Repetition::ZeroPlus(_, None) | Repetition::OnePlus(_, None) => {
910 parse_quote!(Vec<#inner_ty>)
911 }
912 Repetition::ZeroPlus(_, Some(interspersion))
913 | Repetition::OnePlus(_, Some(interspersion)) => match interspersion {
914 Interspersion::Terminated(_, symbol) | Interspersion::Separated(_, symbol) => {
915 let symbol_ty = make_symbol_type(symbol);
916 parse_quote!(::syn::punctuated::Punctuated<#inner_ty, #symbol_ty>)
917 }
918 },
919 }
920 }),
921 UnnamedItem::Block(Braced { value: items, .. }) => Some({
922 match items {
923 Items::OrderedChoice(..) => {
924 panic!("Cannot have ordered choice blocks not at root level")
926 }
927 Items::Sequence(items) => {
928 syn::Type::Tuple(syn::TypeTuple {
929 paren_token: Default::default(),
930 elems: items
931 .iter()
932 .map(|item| match item {
933 Item::Named(_) => {
934 panic!("Cannot have named blocks not at root level")
936 }
937 Item::Unnamed(item) => make_type(item),
938 })
939 .flatten()
940 .collect(),
941 })
942 }
943 }
944 }),
945 UnnamedItem::Symbol(symbol) => Some(make_symbol_type(symbol)),
946 }
947}