1use proc_macro::TokenStream;
2use proc_macro2::{Span, TokenStream as TokenStream2};
3use quote::quote;
4use syn::{parse_quote, Data, DataEnum, DataStruct, DeriveInput, Fields, Generics, Ident};
5
6#[proc_macro_derive(Grammar, attributes(grammar))]
20pub fn derive_grammar(input: TokenStream) -> TokenStream {
21 let mut input = syn::parse_macro_input!(input as DeriveInput);
22 for param in input.generics.type_params_mut() {
23 param.bounds.push(parse_quote!(::tygr::Grammar));
24 }
25 match impl_grammar(&input) {
26 Ok(tokens) => tokens.into(),
27 Err(err) => err.to_compile_error().into(),
28 }
29}
30
31#[proc_macro_derive(GrammarFromStr, attributes(grammar))]
41pub fn derive_grammar_from_str(input: TokenStream) -> TokenStream {
42 derive_convert(input, Convert::FromStr)
43}
44
45#[proc_macro_derive(GrammarFromOther, attributes(grammar))]
54pub fn derive_grammar_from_source(input: TokenStream) -> TokenStream {
55 derive_convert(input, Convert::From)
56}
57
58#[proc_macro_derive(GrammarTryFromOther, attributes(grammar))]
68pub fn derive_grammar_try_from_source(input: TokenStream) -> TokenStream {
69 derive_convert(input, Convert::TryFrom)
70}
71
72#[derive(Clone, Copy)]
73enum Convert {
74 FromStr,
75 From,
76 TryFrom,
77}
78
79fn derive_convert(input: TokenStream, convert: Convert) -> TokenStream {
80 let mut input = syn::parse_macro_input!(input as DeriveInput);
81 for param in input.generics.type_params_mut() {
82 param.bounds.push(parse_quote!(::tygr::Grammar));
83 }
84 match impl_convert(&input, convert) {
85 Ok(tokens) => tokens.into(),
86 Err(err) => err.to_compile_error().into(),
87 }
88}
89
90#[proc_macro]
99#[allow(non_snake_case)]
100pub fn StringEq(input: TokenStream) -> TokenStream {
101 let lit = syn::parse_macro_input!(input as syn::LitStr);
102 let value = lit.value();
103 let chars: Vec<char> = value.chars().collect();
104
105 if chars.is_empty() {
106 return syn::Error::new(
107 lit.span(),
108 "StringEq!() requires a non-empty string literal",
109 )
110 .to_compile_error()
111 .into();
112 }
113
114 let chain = build_nested_chain(&chars, |ch, rest| quote! { ::tygr::CharThen<#ch, #rest> });
115 quote! { ::tygr::StringEq<#chain> }.into()
116}
117
118fn build_nested_chain<F>(items: &[char], mapper: F) -> TokenStream2
120where
121 F: Fn(&char, TokenStream2) -> TokenStream2,
122{
123 items
124 .iter()
125 .rev()
126 .fold(quote! { () }, |rest, ch| mapper(ch, rest))
127}
128
129#[proc_macro]
130#[allow(non_snake_case)]
131pub fn StringEqCI(input: TokenStream) -> TokenStream {
132 let lit = syn::parse_macro_input!(input as syn::LitStr);
133 let value = lit.value();
134 let chars: Vec<char> = value.chars().collect();
135
136 if chars.is_empty() {
137 return syn::Error::new(
138 lit.span(),
139 "StringEqCI!() requires a non-empty string literal",
140 )
141 .to_compile_error()
142 .into();
143 }
144
145 let chain = build_nested_chain(&chars, |ch, rest| quote! { ::tygr::CharCIThen<#ch, #rest> });
146 quote! { ::tygr::StringEqCI<#chain> }.into()
147}
148
149#[derive(Clone)]
150struct Tag {
151 name: TokenStream2,
152 case: Option<TokenStream2>,
153}
154
155impl Tag {
156 fn new(name: TokenStream2, case: Option<TokenStream2>) -> Self {
157 Self { name, case }
158 }
159
160 fn as_constructor(&self) -> TokenStream2 {
161 let name = &self.name;
162 let case = if let Some(case) = &self.case {
163 quote! { :: #case }
164 } else {
165 quote! {}
166 };
167 quote! { #name #case }
168 }
169}
170
171fn with_node(inline: bool, body: TokenStream2) -> TokenStream2 {
172 if inline {
173 body
174 } else {
175 quote! {
176 let mut state = state.node(Self::NAME, pos);
177 #body
178 }
179 }
180}
181
182fn default_name(ident: &Ident) -> String {
184 let ident = ident.to_string();
185 #[cfg(all(feature = "lower_bnf_name", not(feature = "upper_bnf_name")))]
186 let ident = ident.to_ascii_lowercase();
187 #[cfg(all(feature = "upper_bnf_name", not(feature = "lower_bnf_name")))]
188 let ident = ident.to_ascii_uppercase();
189 ident
190}
191
192fn impl_grammar(input: &DeriveInput) -> syn::Result<TokenStream2> {
193 let ident = &input.ident;
194 let generics = &input.generics;
195 let GrammarAttr {
196 name,
197 hidden,
198 inline,
199 validated,
200 } = grammar_attr(input)?;
201 let name = name.unwrap_or_else(|| default_name(ident));
202 match &input.data {
203 Data::Struct(data) => impl_struct(ident, generics, name, hidden, inline, validated, data),
204 Data::Enum(data) => impl_enum(ident, generics, name, hidden, inline, validated, data),
205 Data::Union(_) => Err(syn::Error::new_spanned(
206 ident,
207 "Grammar cannot be derived for unions",
208 )),
209 }
210}
211
212fn grammar_attr(input: &DeriveInput) -> syn::Result<GrammarAttr> {
213 for attr in &input.attrs {
214 if attr.path().is_ident("grammar") {
215 return attr.parse_args::<GrammarAttr>();
216 }
217 }
218 Ok(GrammarAttr::default())
219}
220
221#[derive(Default)]
222struct GrammarAttr {
223 name: Option<String>,
224 hidden: bool,
225 inline: bool,
226 validated: bool,
227}
228
229impl syn::parse::Parse for GrammarAttr {
230 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
231 let mut attr = GrammarAttr::default();
232
233 while !input.is_empty() {
234 let ident: syn::Ident = input.parse()?;
235 if ident == "name" {
236 let _: syn::Token![=] = input.parse()?;
237 let lit: syn::LitStr = input.parse()?;
238 attr.name = Some(lit.value());
239 } else if ident == "hidden" {
240 attr.hidden = true;
241 attr.inline = true;
244 } else if ident == "inline" {
245 attr.inline = true;
246 } else if ident == "validated" {
247 attr.validated = true;
248 } else {
249 return Err(syn::Error::new(
250 ident.span(),
251 "expected `name`, `hidden`, `inline`, or `validated`",
252 ));
253 }
254 if input.is_empty() {
255 break;
256 }
257 let _: syn::Token![,] = input.parse()?;
258 }
259
260 Ok(attr)
261 }
262}
263
264type ProcessedFields<'a> = Vec<(String, Ident, &'a syn::Type)>;
265
266fn components_and_xts(tag: TokenStream2, fields: &Fields) -> (TokenStream2, ProcessedFields<'_>) {
267 match fields {
268 Fields::Named(fields) => {
269 let fields: Vec<_> = fields
270 .named
271 .iter()
272 .map(|field| {
273 let x = field.ident.as_ref().unwrap().clone();
274 let t = &field.ty;
275 (x.to_string(), x, t)
276 })
277 .collect();
278 let xs = fields.iter().map(|(_, x, _)| x);
279 (quote! { #tag { #(#xs),* } }, fields)
280 }
281 Fields::Unnamed(fields) => {
282 let fields: Vec<_> = fields
283 .unnamed
284 .iter()
285 .enumerate()
286 .map(|(i, field)| {
287 let x = Ident::new(&format!("_f{i}"), Span::call_site());
288 let t = &field.ty;
289 (i.to_string(), x, t)
290 })
291 .collect();
292 let xs = fields.iter().map(|(_, x, _)| x);
293 (quote! { #tag ( #(#xs),* ) }, fields)
294 }
295 Fields::Unit => (quote! { #tag }, vec![]),
296 }
297}
298
299fn parse_at(validated: bool, fields: &ProcessedFields, constructor: &TokenStream2) -> TokenStream2 {
300 let steps: Vec<_> = fields
301 .iter()
302 .map(|(_, x, t)| {
303 quote! {
304 let (#x, pos) = <#t as ::tygr::Grammar>::parse_at(input, pos, state.reborrow())?;
305 }
306 })
307 .collect();
308 let (start_pos, validate) = if validated {
309 let trace = if cfg!(feature = "trace") {
310 quote! {
311 state.expect(pos, ::tygr::Expectation::Valid {
312 node: Self::NAME,
313 text: input[start_pos..pos].to_string(),
314 be_valid,
315 });
316 }
317 } else if cfg!(feature = "trace_pos") {
318 quote! {
319 state.expect(pos);
320 }
321 } else {
322 quote! {}
323 };
324 (
325 quote! { let start_pos = pos; },
326 quote! {
327 if let Some(be_valid) = ::tygr::Validation::be_valid(::tygr::Validate::validate(&value)) {
328 #trace
329 return None
330 }
331 },
332 )
333 } else {
334 (quote! {}, quote! {})
335 };
336 quote! {
337 #start_pos
338 #(#steps)*
339 let value = #constructor;
340 #validate
341 Some((value, pos))
342 }
343}
344
345fn scan_at(validated: bool, fields: &ProcessedFields, constructor: &TokenStream2) -> TokenStream2 {
346 if validated {
347 let parse_at = parse_at(true, fields, constructor);
348 quote! { ({#parse_at}).map(|(_, pos)| pos) }
349 } else {
350 let steps: Vec<_> = fields
351 .iter()
352 .map(|(_, _, t)| {
353 quote! {
354 let pos = <#t as ::tygr::Grammar>::scan_at(input, pos, state.reborrow())?;
355 }
356 })
357 .collect();
358 quote! {
359 #(#steps)*
360 Some(pos)
361 }
362 }
363}
364
365fn print_steps(fields: &ProcessedFields) -> Vec<TokenStream2> {
366 fields
367 .iter()
368 .map(|(_, x, _)| {
369 quote! {
370 ::tygr::Grammar::print_to(#x, buf);
371 }
372 })
373 .collect()
374}
375
376fn to_bnf(fields: &ProcessedFields) -> TokenStream2 {
377 let ts = fields.iter().map(|(_, _, t)| quote! { #t });
378 quote! {
379 ::tygr::bnf::Expr::sequence(vec![
380 #(<#ts as ::tygr::Grammar>::to_bnf()),*
381 ])
382 }
383}
384
385fn fail_at(fields: &ProcessedFields) -> TokenStream2 {
389 let calls = fields.iter().map(|(_, _, t)| {
390 quote! { <#t as ::tygr::Grammar>::fail_at(pos, state.reborrow()) }
391 });
392 quote! {
393 #(#calls ||)* false
394 }
395}
396
397fn bnf_ref(grammar_name: &str, hidden: bool, to_bnf: TokenStream2, inline: bool) -> TokenStream2 {
398 if hidden {
399 quote! { ::tygr::bnf::Expr::empty() }
400 } else if inline {
401 to_bnf
402 } else {
403 quote! { ::tygr::bnf::Expr::RuleRef(#grammar_name.to_string()) }
404 }
405}
406
407struct FieldsInfo {
408 constructor: TokenStream2,
409 parse_at: TokenStream2,
410 scan_at: TokenStream2,
411 print_to: TokenStream2,
412 to_bnf: TokenStream2,
413 fail_at: TokenStream2,
414 first: TokenStream2,
415}
416
417impl FieldsInfo {
418 fn from(validated: bool, tag: Tag, fields: &Fields) -> Self {
419 let (constructor, fields) = components_and_xts(tag.as_constructor(), fields);
420 let print_steps = print_steps(&fields);
421 let parse_at = parse_at(validated, &fields, &constructor);
422 let scan_at = scan_at(validated, &fields, &constructor);
423 let mut first = quote! { ::tygr::OptionalFirst<::tygr::EmptyByteSet> };
424 for (_, _, t) in &fields {
425 first = quote! {
426 <#first as ::tygr::First>::Concat<#t>
427 }
428 }
429 Self {
430 parse_at: quote! { #parse_at },
431 scan_at: quote! { #scan_at },
432 print_to: quote! {#(#print_steps)*},
433 to_bnf: to_bnf(&fields),
434 fail_at: fail_at(&fields),
435 constructor,
436 first,
437 }
438 }
439}
440
441fn impl_convert(input: &DeriveInput, convert: Convert) -> syn::Result<TokenStream2> {
442 let ident = &input.ident;
443 let generics = &input.generics;
444 let GrammarAttr {
445 name,
446 hidden,
447 inline,
448 validated,
449 } = grammar_attr(input)?;
450 if validated {
451 return Err(syn::Error::new_spanned(
452 ident,
453 "GrammarFromStr/GrammarFromOther/GrammarTryFromOther don't support `#[grammar(validated)]` — reject the value from FromStr/TryFrom's own `Err` instead",
454 ));
455 }
456 let name = name.unwrap_or_else(|| default_name(ident));
457 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
458 let self_ty = quote! { #ident #ty_generics };
459 let source = quote! { <#self_ty as ::tygr::GrammarFrom>::Source };
460 let trace = if cfg!(feature = "trace") {
462 quote! {
463 state.expect(
464 end,
465 ::tygr::Expectation::GrammarFrom {
466 from: input[pos..end].to_string(),
467 into: Self::NAME,
468 fail: ::std::string::ToString::to_string(&err),
469 },
470 );
471 }
472 } else if cfg!(feature = "trace_pos") {
473 quote! {
474 state.expect(end);
475 }
476 } else {
477 quote! {}
478 };
479 let parse_at = match convert {
480 Convert::FromStr => quote! {
481 let end = <#source as ::tygr::Grammar>::scan_at(input, pos, state.reborrow())?;
482 match <#self_ty as ::core::str::FromStr>::from_str(&input[pos..end]) {
483 Ok(value) => Some((value, end)),
484 Err(err) => {
485 #trace
486 let _ = &err;
487 None
488 }
489 }
490 },
491 Convert::From => quote! {
492 let (source, end) = <#source as ::tygr::Grammar>::parse_at(input, pos, state.reborrow())?;
493 Some((<#self_ty as ::core::convert::From<#source>>::from(source), end))
494 },
495 Convert::TryFrom => quote! {
496 let (source, end) = <#source as ::tygr::Grammar>::parse_at(input, pos, state.reborrow())?;
497 match <#self_ty as ::core::convert::TryFrom<#source>>::try_from(source) {
498 Ok(value) => Some((value, end)),
499 Err(err) => {
500 #trace
501 let _ = &err;
502 None
503 }
504 }
505 },
506 };
507 let scan_at = match convert {
509 Convert::From => quote! {
510 <#source as ::tygr::Grammar>::scan_at(input, pos, state)
511 },
512 Convert::FromStr | Convert::TryFrom => quote! {
513 Self::parse_at(input, pos, state).map(|(_, end)| end)
514 },
515 };
516 let to_bnf_def = quote! { <#source as ::tygr::Grammar>::to_bnf() };
517 let bnf_ref = bnf_ref(&name, hidden, to_bnf_def.clone(), inline);
518 Ok(quote! {
519 impl #impl_generics ::tygr::Grammar for #self_ty #where_clause {
520 type First = <#source as ::tygr::Grammar>::First;
521
522 #[inline]
523 fn parse_at(input: &str, pos: usize, #[allow(unused_mut)] mut state: ::tygr::State) -> Option<(Self, usize)> {
524 #parse_at
525 }
526
527 #[inline]
528 fn scan_at(input: &str, pos: usize, #[allow(unused_mut)] mut state: ::tygr::State) -> Option<usize> {
529 #scan_at
530 }
531
532 fn print_to(&self, buf: &mut ::std::string::String) {
533 <#self_ty as ::tygr::GrammarFrom>::print_to(self, buf);
534 }
535
536 fn to_bnf() -> ::tygr::bnf::Expr {
537 #bnf_ref
538 }
539
540 fn fail_at(pos: usize, state: ::tygr::State) -> bool {
541 <#source as ::tygr::Grammar>::fail_at(pos, state)
542 }
543 }
544
545 impl #impl_generics ::tygr::GrammarRule for #self_ty #where_clause {
546 const NAME: &'static str = #name;
547
548 fn to_bnf_def() -> ::tygr::bnf::Expr {
549 #to_bnf_def
550 }
551 }
552 })
553}
554
555fn impl_struct(
556 ident: &Ident,
557 generics: &Generics,
558 name: String,
559 hidden: bool,
560 inline: bool,
561 validated: bool,
562 data: &DataStruct,
563) -> syn::Result<TokenStream2> {
564 let tag = Tag::new(quote! { #ident }, None);
565 let fields = &data.fields;
566 let FieldsInfo {
567 constructor,
568 parse_at,
569 scan_at,
570 print_to,
571 to_bnf,
572 fail_at,
573 first,
574 } = FieldsInfo::from(validated, tag, fields);
575 let parse_at = with_node(inline, parse_at);
576 let scan_at = with_node(inline, scan_at);
577 let fail_at = with_node(inline, fail_at);
578 let bnf_ref = bnf_ref(&name, hidden, to_bnf.clone(), inline);
579 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
580 Ok(quote! {
581 impl #impl_generics ::tygr::Grammar for #ident #ty_generics #where_clause {
582 type First = #first;
583
584 #[inline]
585 fn parse_at(input: &str, pos: usize, #[allow(unused_mut)] mut state: ::tygr::State) -> Option<(Self, usize)> {
586 #parse_at
587 }
588
589 #[inline]
590 fn scan_at(input: &str, pos: usize, #[allow(unused_mut)] mut state: ::tygr::State) -> Option<usize> {
591 #scan_at
592 }
593
594 fn print_to(&self, buf: &mut ::std::string::String) {
595 let #constructor = &self;
596 #print_to
597 }
598
599 fn to_bnf() -> ::tygr::bnf::Expr {
600 #bnf_ref
601 }
602
603 fn fail_at(#[allow(unused_variables)] pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> bool {
604 #fail_at
605 }
606 }
607
608 impl #impl_generics ::tygr::GrammarRule for #ident #ty_generics #where_clause {
609 const NAME: &'static str = #name;
610
611 fn to_bnf_def() -> ::tygr::bnf::Expr {
612 #to_bnf
613 }
614 }
615 })
616}
617
618fn impl_enum(
621 ident: &Ident,
622 generics: &Generics,
623 name: String,
624 hidden: bool,
625 inline: bool,
626 validated: bool,
627 data: &DataEnum,
628) -> syn::Result<TokenStream2> {
629 let mut each_constructor = vec![];
630 let mut each_parse_at = vec![];
631 let mut each_scan_at = vec![];
632 let mut each_print_to = vec![];
633 let mut each_to_bnf = vec![];
634 let mut each_fail_at = vec![];
635 let mut each_first = vec![];
636 for variant in &data.variants {
637 let variant_ident = &variant.ident;
638 let tag = Tag::new(quote! { #ident }, Some(quote! {#variant_ident}));
639 let FieldsInfo {
640 constructor,
641 parse_at,
642 scan_at,
643 print_to,
644 to_bnf,
645 fail_at,
646 first,
647 } = FieldsInfo::from(validated, tag, &variant.fields);
648 each_constructor.push(constructor);
649 each_parse_at.push(parse_at);
650 each_scan_at.push(scan_at);
651 each_print_to.push(print_to);
652 each_to_bnf.push(to_bnf);
653 each_fail_at.push(fail_at);
654 each_first.push(first);
655 }
656 let fail_at_variants_body = {
660 let mut variants = each_fail_at.iter();
661 let first = variants.next().cloned().unwrap_or_else(|| quote! { false });
662 variants.fold(first, |acc, next| quote! { (#acc) & (#next) })
663 };
664 let to_bnf = quote! { ::tygr::bnf::Expr::alternation(vec![ #(#each_to_bnf),* ]) };
665 let bnf_ref = bnf_ref(&name, hidden, to_bnf.clone(), inline);
666 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
667 let n = each_first.len();
668 let self_ty = quote! { #ident #ty_generics };
669 let parse_fn_ty = quote! {
670 fn(&str, usize, ::tygr::State<'_>) -> Option<(#self_ty, usize)>
671 };
672 let scan_fn_ty = quote! {
673 fn(&str, usize, ::tygr::State<'_>) -> Option<usize>
674 };
675 let case_fns: Vec<Ident> = (0..n)
676 .map(|k| Ident::new(&format!("parse_case_{k}"), Span::call_site()))
677 .collect();
678 let scan_fns: Vec<Ident> = (0..n)
679 .map(|k| Ident::new(&format!("scan_case_{k}"), Span::call_site()))
680 .collect();
681 let case_defs = case_fns.iter().zip(&each_parse_at).enumerate().map(|(k, (name, arm))| {
682 let next = if k + 1 < n {
683 let nx = &case_fns[k + 1];
684 quote! { Self::#nx(input, pos, state) }
685 } else {
686 quote! { None }
687 };
688 quote! {
689 #[inline]
690 fn #name(input: &str, pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> Option<(Self, usize)> {
691 if let Some(result) = (|| { #arm })() { return Some(result); }
692 #next
693 }
694 }
695 });
696 let scan_case_defs = scan_fns
697 .iter()
698 .zip(&each_scan_at)
699 .enumerate()
700 .map(|(k, (name, arm))| {
701 let next = if k + 1 < n {
702 let nx = &scan_fns[k + 1];
703 quote! { Self::#nx(input, pos, state) }
704 } else {
705 quote! { None }
706 };
707 quote! {
708 #[inline]
709 fn #name(input: &str, pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> Option<usize> {
710 if let Some(result) = (|| { #arm })() { return Some(result); }
711 #next
712 }
713 }
714 });
715 let build_table = |fn_ty: &TokenStream2, fns: &[Ident], miss: &TokenStream2| {
718 quote! {{
719 let parsers: [#fn_ty; #n] = [ #(<#self_ty>::#fns),* ];
720 let mut table: [#fn_ty; 257] = [#miss; 257];
724 let mut first = 0usize;
725 while first < 257 {
726 let mut case = 0usize;
727 while case < #n {
728 if CONTAINS_NIL[case] || (first <= 255 && CONTAINS_BYTE[case][first]) {
729 table[first] = parsers[case];
730 break;
731 }
732 case += 1;
733 }
734 first += 1;
735 }
736 table
737 }}
738 };
739 let parse_table = build_table(
740 &parse_fn_ty,
741 &case_fns,
742 "e! { <#self_ty>::parse_case_miss },
743 );
744 let scan_table = build_table(
745 &scan_fn_ty,
746 &scan_fns,
747 "e! { <#self_ty>::scan_case_miss },
748 );
749 const DISPATCH_THRESHOLD: usize = 4;
750 let fail_at_on_miss = if cfg!(feature = "trace_pos") {
754 quote! { Self::fail_at_variants(pos, state); }
755 } else {
756 quote! {}
757 };
758 let (dispatch_body, scan_dispatch_body, case_impls) = if n >= DISPATCH_THRESHOLD {
759 (
760 quote! {
761 const CONTAINS_NIL: [bool; #n] = [ #(<#each_first as ::tygr::First>::CONTAINS_NIL),* ];
762 const CONTAINS_BYTE: [[bool; 256]; #n] = [ #(<#each_first as ::tygr::First>::CONTAINS_BYTE),* ];
763 const DISPATCH: [#parse_fn_ty; 257] = #parse_table;
764 let first = input.as_bytes().get(pos).map(|&first| first as usize).unwrap_or(256);
765 DISPATCH[first](input, pos, state)
766 },
767 quote! {
768 const CONTAINS_NIL: [bool; #n] = [ #(<#each_first as ::tygr::First>::CONTAINS_NIL),* ];
769 const CONTAINS_BYTE: [[bool; 256]; #n] = [ #(<#each_first as ::tygr::First>::CONTAINS_BYTE),* ];
770 const DISPATCH: [#scan_fn_ty; 257] = #scan_table;
771 let first = input.as_bytes().get(pos).map(|&first| first as usize).unwrap_or(256);
772 DISPATCH[first](input, pos, state)
773 },
774 quote! {
775 #(#case_defs)*
776 #(#scan_case_defs)*
777
778 #[inline]
779 fn parse_case_miss(_input: &str, #[allow(unused_variables)] pos: usize, #[allow(unused_variables)] state: ::tygr::State) -> Option<(Self, usize)> {
780 #fail_at_on_miss
781 None
782 }
783
784 #[inline]
785 fn scan_case_miss(_input: &str, #[allow(unused_variables)] pos: usize, #[allow(unused_variables)] state: ::tygr::State) -> Option<usize> {
786 #fail_at_on_miss
787 None
788 }
789 },
790 )
791 } else {
792 (
793 quote! {
794 #( if let Some(result) = (|| { #each_parse_at })() { return Some(result); } )*
795 None
796 },
797 quote! {
798 #( if let Some(result) = (|| { #each_scan_at })() { return Some(result); } )*
799 None
800 },
801 quote! {},
802 )
803 };
804 let parse_body = with_node(inline, dispatch_body);
805 let scan_body = with_node(inline, scan_dispatch_body);
806 let fail_at = with_node(inline, quote! { Self::fail_at_variants(pos, state) });
807 let first = {
808 let mut the_first = quote! { ::tygr::EmptyByteSet };
809 for first in each_first {
810 the_first = quote! { <#the_first as ::tygr::First>::Union<#first> };
811 }
812 the_first
813 };
814 Ok(quote! {
815 impl #impl_generics #ident #ty_generics #where_clause {
816 #case_impls
817
818 #[inline]
819 fn parse_case_none(_input: &str, _pos: usize, _state: ::tygr::State) -> Option<(Self, usize)> {
820 None
821 }
822
823 #[inline]
824 fn fail_at_variants(#[allow(unused_variables)] pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> bool {
825 #fail_at_variants_body
826 }
827 }
828
829 impl #impl_generics ::tygr::Grammar for #ident #ty_generics #where_clause {
830 type First = #first;
831
832 #[inline]
833 fn parse_at(input: &str, pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> Option<(Self, usize)> {
834 #parse_body
835 }
836
837 #[inline]
838 fn scan_at(input: &str, pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> Option<usize> {
839 #scan_body
840 }
841
842 fn print_to(&self, buf: &mut ::std::string::String) {
843 match self {
844 #(#each_constructor => { #each_print_to }),*
845 }
846 }
847
848 fn to_bnf() -> ::tygr::bnf::Expr {
849 #bnf_ref
850 }
851
852 fn fail_at(pos: usize, #[allow(unused_variables, unused_mut)] mut state: ::tygr::State) -> bool {
853 #fail_at
854 }
855 }
856
857 impl #impl_generics ::tygr::GrammarRule for #ident #ty_generics #where_clause {
858 const NAME: &'static str = #name;
859
860 fn to_bnf_def() -> ::tygr::bnf::Expr {
861 #to_bnf
862 }
863 }
864 })
865}