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
120
121
122
123
124
125
126
use quote::format_ident;
use super::*;
impl SimpleRegex {
pub fn generate_parser(&self, fn_name: Ident) -> TokenStream {
let mut state_fns = vec![];
let mut state_matches = vec![];
for (state, transitions) in &self.dfa.transitions {
let state_fn = format_ident!("state_{}", state);
let mut transition_matches = vec![];
for (transition, target) in transitions {
let match_expr = match transition {
nfa::TransitionEvent::Epsilon => unreachable!(),
nfa::TransitionEvent::End => quote! { _ => ::compiler_tools::MatchResult::MatchedEmpty(#target), },
nfa::TransitionEvent::Char(c) => quote! { Some(#c) => ::compiler_tools::MatchResult::Matched(#target), },
nfa::TransitionEvent::Chars(inverted, group) => {
let mut matching = vec![];
for entry in group {
match entry {
GroupEntry::Char(c) => {
if !matching.is_empty() {
matching.push(quote! { | })
}
matching.push(quote! { #c });
}
GroupEntry::Range(start, end) => {
if !matching.is_empty() {
matching.push(quote! { | })
}
matching.push(quote! { #start ..= #end });
}
}
}
let matching_empty = matching.is_empty();
let matching = flatten(matching);
if *inverted {
if matching_empty {
quote! {
_ => ::compiler_tools::MatchResult::Matched(#target),
}
} else {
quote! {
Some(c) if !matches!(c, #matching) => ::compiler_tools::MatchResult::Matched(#target),
}
}
} else {
quote! {
Some(c) if matches!(c, #matching) => ::compiler_tools::MatchResult::Matched(#target),
}
}
}
};
transition_matches.push(match_expr);
}
let transition_matches = flatten(transition_matches);
state_fns.push(quote! {
#[inline]
fn #state_fn(target: Option<char>) -> ::compiler_tools::MatchResult {
match target {
#transition_matches
_ => ::compiler_tools::MatchResult::NoMatch,
}
}
});
state_matches.push(quote! {
#state => #state_fn(c),
});
}
/*
let mut state = 0u32;
let mut chars = from.chars();
while let Some(char) = chars.next() {
for (transition, target) in self.dfa.transitions.get(&state).unwrap() {
if transition.matches(char) {
state = *target;
if state == self.dfa.final_state {
return true;
}
}
}
}
false
*/
let state_fns = flatten(state_fns);
let state_matches = flatten(state_matches);
let final_state = self.dfa.final_state;
quote! {
fn #fn_name(from: &str) -> Option<(&str, &str)> {
#state_fns
let mut counter = 0usize;
let mut state = 0u32;
let mut chars = from.chars();
loop {
let c = chars.next();
let next_state = match state {
#state_matches
_ => ::compiler_tools::MatchResult::NoMatch,
};
match next_state {
::compiler_tools::MatchResult::Matched(next_state) => {
state = next_state;
if let Some(c) = c {
counter += c.len_utf8();
}
if next_state == #final_state {
return Some((&from[..counter], &from[counter..]));
}
},
::compiler_tools::MatchResult::MatchedEmpty(next_state) => {
state = next_state;
//TODO: backtrack iterator (but this only occurs at End sequence right now)
if next_state == #final_state {
return Some((&from[..counter], &from[counter..]));
}
},
::compiler_tools::MatchResult::NoMatch => return None,
}
}
None
}
}
}
}