derive_finite_automaton_derive/
macro.rs

1mod trie;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::{format_ident, quote};
6use syn::{parse_macro_input, Arm, DeriveInput, Expr, Ident};
7use trie::Trie;
8
9pub(crate) const NO_STATE_NAME: &str = "None";
10
11#[proc_macro_derive(
12    FiniteAutomataConstructor,
13    attributes(automaton_mappings, automaton_item_type)
14)]
15pub fn stateful_trie_constructor(input: TokenStream) -> TokenStream {
16    let input = parse_macro_input!(input as DeriveInput);
17    let name = input.ident;
18
19    let mut mappings = None::<trie::Mappings>;
20
21    let automaton_mappings = input
22        .attrs
23        .iter()
24        .filter(|attr| attr.path().is_ident("automaton_mappings"));
25
26    for mapping in automaton_mappings {
27        let m = mapping.parse_args::<trie::Mappings>().unwrap();
28        if let Some(em) = mappings.as_mut() {
29            em.extend(m);
30        } else {
31            mappings = Some(m);
32        }
33    }
34
35    // TODO unwrap here
36    let item_type: Ident = input
37        .attrs
38        .iter()
39        .find(|attr| attr.path().is_ident("automaton_item_type"))
40        .map(|attr| attr.parse_args().unwrap())
41        .unwrap_or_else(|| Ident::new("char", Span::call_site()));
42
43    let trie: Trie<crate::trie::Item, Expr> = mappings.unwrap().into();
44
45    let (mut states, mut arms): (Vec<Ident>, Vec<Arm>) = Default::default();
46
47    let no_state_ident = Ident::new(NO_STATE_NAME, Span::call_site());
48
49    let states_ident = format_ident!("{}States", name.to_string().to_uppercase());
50
51    trie::expand_trie(
52        &trie,
53        &mut arms,
54        &mut states,
55        &no_state_ident,
56        &states_ident,
57    );
58
59    let output = quote! {
60        const _: () = {
61            #[derive(PartialEq, Eq, Clone, Debug)]
62            pub enum #states_ident {
63                #no_state_ident,
64                #( #states ),*
65            }
66
67            impl ::derive_finite_automaton::FiniteAutomataConstructor for #name {
68                type FiniteAutomata = #states_ident;
69
70                fn new_automaton() -> #states_ident {
71                    #states_ident::#no_state_ident
72                }
73            }
74
75            impl ::derive_finite_automaton::FiniteAutomata<#name> for #states_ident {
76                type State = #states_ident;
77                type Item = #item_type;
78
79                fn get_next(self, item: Self::Item) -> ::derive_finite_automaton::GetNextResult<#name, #states_ident> {
80                    match (&self, item) {
81                        #( #arms )*
82                    }
83                }
84            }
85        };
86    };
87
88    output.into()
89}