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