scopegraphs_regular_expressions/
emit.rs

1use crate::compile::MatchState;
2use crate::Automaton;
3use proc_macro2::{Ident, TokenStream};
4use quote::{quote, TokenStreamExt};
5use syn::Type;
6
7impl Automaton {
8    /// Convert this compiled regex into rust code that accepts this regular expression.
9    /// `name` is the name of the type that is emitted, and `alphabet` is the type of symbols
10    /// that the machine should accept.
11    pub fn emit(&self, name: &Ident, alphabet: &Type, errors: Vec<syn::Error>) -> TokenStream {
12        let Self {
13            states, initial, ..
14        } = self;
15
16        let ids: Vec<_> = (0..states.len()).collect();
17        let arms: Vec<_> = states
18            .iter()
19            .map(|s| {
20                let options: Vec<_> = s.transition_table.keys().collect();
21                let default_transition = s.default_transition;
22                let new_states: Vec<_> = options
23                    .iter()
24                    .flat_map(|x| s.transition_table.get(*x))
25                    .copied()
26                    .collect();
27                let matchers: Vec<_> = options.into_iter().map(|i| i.name.clone()).collect();
28
29                quote!(
30                    match token {
31                        #(
32                            #alphabet::#matchers => {self.state = #new_states;}
33                        ),*
34                        _ => {self.state = #default_transition;}
35                    }
36
37                )
38            })
39            .collect();
40
41        let finals: Vec<_> = states.iter().map(|i| i.is_final).collect();
42        let accepting: Vec<_> = states.iter().map(MatchState::is_accepting).collect();
43        let compile_errors: TokenStream = errors
44            .iter()
45            .flat_map(syn::Error::to_compile_error)
46            .collect();
47
48        let mut result = quote!(
49            #[derive(Clone)]
50            struct #name {
51                state: usize,
52            }
53
54            impl #name {
55                fn new() -> Self { Self {state: #initial} }
56            }
57
58            impl scopegraphs::RegexMatcher<#alphabet> for #name {
59                fn step(&mut self, token: #alphabet) {
60                    match self.state {
61                        #(
62                            #ids => #arms
63                        ),*
64                        _ => unreachable!(),
65                    }
66                }
67
68                fn is_final(&self) -> bool {
69                    match self.state {
70                        #(
71                            #ids => {return #finals;}
72                        ),*
73                        _ => unreachable!(),
74                    }
75                }
76
77                fn is_accepting(&self) -> bool {
78                    match self.state {
79                        #(
80                            #ids => {return #accepting;}
81                        ),*
82                        _ => unreachable!(),
83                    }
84                }
85            }
86
87            impl scopegraphs::RegexMatcher<&#alphabet> for #name {
88                fn step(&mut self, token: &#alphabet) {
89                    match self.state {
90                        #(
91                            #ids => #arms
92                        ),*
93                        _ => unreachable!(),
94                    }
95                }
96
97                fn is_final(&self) -> bool {
98                    match self.state {
99                        #(
100                            #ids => {return #finals;}
101                        ),*
102                        _ => unreachable!(),
103                    }
104                }
105
106                fn is_accepting(&self) -> bool {
107                    match self.state {
108                        #(
109                            #ids => {return #accepting;}
110                        ),*
111                        _ => unreachable!(),
112                    }
113                }
114            }
115        );
116        result.append_all(compile_errors);
117        result
118    }
119}