scopegraphs_regular_expressions/
emit.rs1use crate::compile::MatchState;
2use crate::Automaton;
3use proc_macro2::{Ident, TokenStream};
4use quote::{quote, TokenStreamExt};
5use syn::Type;
6
7impl Automaton {
8 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}