metrale_grammar/grammar/functor/
fsm_hasher.rs1use crate::grammar::data::GrammarData;
11use crate::grammar::expr::GrammarExprType;
12use crate::support::hash::hash_combine_binary;
13
14use super::analyzer::RuleRefGraphFinder;
15use super::hash_walk::{flag, hash_fsm};
16
17pub struct GrammarFsmHasher {
19 visited: Vec<bool>,
20 referrer_to_referee: Vec<Vec<i32>>,
22 referee_to_referrer: Vec<Vec<i32>>,
24}
25
26impl GrammarFsmHasher {
27 pub fn apply(grammar: &mut GrammarData) {
29 let num_rules = grammar.num_rules() as usize;
30 grammar.per_rule_fsm_hashes = vec![None; num_rules];
31 grammar.per_rule_fsm_new_state_ids = vec![Vec::new(); num_rules];
32
33 let referee_to_referrer = RuleRefGraphFinder::apply(grammar);
34 let mut referrer_to_referee: Vec<Vec<i32>> = vec![Vec::new(); num_rules];
35 for (referee, referrers) in referee_to_referrer.iter().enumerate() {
36 for &referrer in referrers {
37 referrer_to_referee[referrer as usize].push(referee as i32);
38 }
39 }
40
41 let mut visited = vec![false; num_rules];
42 for (i, fsm) in grammar.per_rule_fsms.iter().enumerate() {
43 if fsm.is_none() {
44 visited[i] = true;
45 }
46 }
47
48 let mut hasher = Self {
49 visited,
50 referrer_to_referee,
51 referee_to_referrer,
52 };
53
54 loop {
56 let idx = hasher.find_terminal();
57 if idx != -1 {
58 hasher.visited[idx as usize] = true;
59 let (h, mapping) = hash_fsm(grammar, idx);
60 grammar.per_rule_fsm_hashes[idx as usize] = Some(h);
61 grammar.per_rule_fsm_new_state_ids[idx as usize] = mapping;
62 hasher.detach(idx);
63 continue;
64 }
65 if !hasher.break_one_cycle(grammar) {
66 break;
67 }
68 }
69
70 let mut partial: Vec<(i32, u64)> = Vec::new();
73 for i in 0..num_rules as i32 {
74 if grammar.per_rule_fsm_hashes[i as usize].is_some() {
75 continue;
76 }
77 let Some(fsm) = &grammar.per_rule_fsms[i as usize] else {
78 continue;
79 };
80 if has_inward_edge(grammar, fsm.start()) {
81 continue;
82 }
83 if let Some((h, mapping)) = super::hash_walk::partial_hash_fsm(grammar, i) {
84 grammar.per_rule_fsm_new_state_ids[i as usize] = mapping;
85 partial.push((i, h));
86 }
87 }
88 for (rule_id, h) in partial {
89 grammar.per_rule_fsm_hashes[rule_id as usize] = Some(h);
90 }
91 }
92
93 fn find_terminal(&self) -> i32 {
96 for i in 0..self.referrer_to_referee.len() {
97 if self.visited[i] {
98 continue;
99 }
100 if self.referrer_to_referee[i].is_empty() {
101 return i as i32;
102 }
103 if self.referrer_to_referee[i].len() == 1 && self.referrer_to_referee[i][0] == i as i32
104 {
105 return i as i32;
106 }
107 }
108 -1
109 }
110
111 fn detach(&mut self, idx: i32) {
113 for referer in self.referee_to_referrer[idx as usize].clone() {
114 self.referrer_to_referee[referer as usize].retain(|&r| r != idx);
115 }
116 }
117
118 fn break_one_cycle(&mut self, grammar: &mut GrammarData) -> bool {
121 let n = self.referee_to_referrer.len();
122 let mut not_simple = self.visited.clone();
123 for i in 0..n {
124 if not_simple[i] {
125 continue;
126 }
127 let mut dfs_stack: Vec<i32> = vec![i as i32];
128 let mut in_stack = vec![false; n];
129 in_stack[i] = true;
130 let mut cur = i as i32;
131 let mut cycle: Vec<i32> = Vec::new();
132 while self.referrer_to_referee[cur as usize].len() == 1 && !not_simple[cur as usize] {
133 assert_ne!(
134 cur, self.referrer_to_referee[cur as usize][0],
135 "self-recursion cycle not allowed"
136 );
137 not_simple[cur as usize] = true;
138 cur = self.referrer_to_referee[cur as usize][0];
139 if in_stack[cur as usize] {
140 cycle.push(cur);
141 while *dfs_stack.last().unwrap() != cur {
142 cycle.push(dfs_stack.pop().unwrap());
143 }
144 break;
145 }
146 dfs_stack.push(cur);
147 in_stack[cur as usize] = true;
148 }
149 if !cycle.is_empty() {
150 self.hash_cycle(grammar, &cycle);
151 return true;
152 }
153 }
154 false
155 }
156
157 fn hash_cycle(&mut self, grammar: &mut GrammarData, cycle: &[i32]) {
159 for &id in cycle {
160 self.visited[id as usize] = true;
161 grammar.per_rule_fsm_hashes[id as usize] = Some(flag::SIMPLE_CYCLE);
162 }
163 let mut local: Vec<u64> = Vec::with_capacity(cycle.len());
164 for &id in cycle {
165 let (h, mapping) = hash_fsm(grammar, id);
166 grammar.per_rule_fsm_new_state_ids[id as usize] = mapping;
167 local.push(h);
168 }
169 let len = local.len();
170 for (i, &id) in cycle.iter().enumerate() {
171 let mut seed = 0u64;
172 for j in 0..len {
173 hash_combine_binary(&mut seed, local[(i + j) % len]);
174 }
175 grammar.per_rule_fsm_hashes[id as usize] = Some(seed);
176 }
177 for &id in cycle {
178 self.detach(id);
179 }
180 }
181}
182
183fn has_inward_edge(grammar: &GrammarData, state: usize) -> bool {
185 let fsm = &grammar.complete_fsm;
186 for s in 0..fsm.num_states() {
187 for edge in fsm.edges(s) {
188 if edge.target as usize == state {
189 return true;
190 }
191 }
192 }
193 false
194}
195
196pub fn hash_sequence(grammar: &GrammarData, sequence_id: i32) -> Option<u64> {
199 if sequence_id == -1 {
200 return None;
201 }
202 let seq = grammar.expr(sequence_id);
203 debug_assert_eq!(seq.kind, GrammarExprType::Sequence);
204 let mut seed = 0u64;
205 for &eid in seq.data {
206 let e = grammar.expr(eid);
207 hash_combine_binary(&mut seed, e.kind as i32 as u64);
208 match e.kind {
209 GrammarExprType::ByteString
210 | GrammarExprType::CharacterClass
211 | GrammarExprType::CharacterClassStar
212 | GrammarExprType::EmptyStr => {
213 for &x in e.data {
214 hash_combine_binary(&mut seed, x as i64 as u64);
215 }
216 }
217 GrammarExprType::RuleRef => {
218 let h = grammar.per_rule_fsm_hashes[e.data[0] as usize]?;
219 hash_combine_binary(&mut seed, h);
220 }
221 GrammarExprType::Repeat => {
222 let h = grammar.per_rule_fsm_hashes[e.data[0] as usize]?;
223 hash_combine_binary(&mut seed, h);
224 hash_combine_binary(&mut seed, e.data[1] as i64 as u64);
225 hash_combine_binary(&mut seed, e.data[2] as i64 as u64);
226 }
227 GrammarExprType::Sequence | GrammarExprType::Choices => return None,
228 GrammarExprType::TagDispatch => return None,
229 }
230 }
231 Some(seed)
232}
233
234#[cfg(test)]
235#[path = "fsm_hasher_tests.rs"]
236mod tests;