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