metrale_grammar/grammar/functor/
hash_walk.rs1use std::collections::{BTreeMap, BTreeSet, VecDeque};
11
12use crate::grammar::data::GrammarData;
13use crate::support::hash::hash_combine_binary;
14
15pub mod flag {
17 pub const NOT_END: u64 = (-0x100_i64) as u64;
19 pub const END: u64 = (-0x200_i64) as u64;
21 pub const SELF_RECURSION: u64 = (-0x300_i64) as u64;
23 pub const SIMPLE_CYCLE: u64 = (-0x400_i64) as u64;
25 pub const UNKNOWN: u64 = (-0x500_i64) as u64;
27}
28
29fn mix(seed: u64, values: &[u64]) -> u64 {
31 let mut s = seed;
32 for &v in values {
33 hash_combine_binary(&mut s, v);
34 }
35 s
36}
37
38fn sorted_edges(grammar: &GrammarData, s: usize) -> Vec<crate::fsm::FsmEdge> {
40 let mut e: Vec<_> = grammar.complete_fsm.edges(s).to_vec();
41 e.sort_unstable();
42 e
43}
44
45pub fn hash_fsm(grammar: &GrammarData, fsm_index: i32) -> (u64, Vec<(i32, i32)>) {
48 let fsm = grammar.per_rule_fsms[fsm_index as usize]
49 .as_ref()
50 .expect("fsm present");
51 let mut old_to_new: BTreeMap<i32, i32> = BTreeMap::new();
52 old_to_new.insert(fsm.start() as i32, 0);
53 let mut queue: VecDeque<i32> = VecDeque::new();
54 queue.push_back(fsm.start() as i32);
55 let mut hash = 0u64;
56
57 while let Some(old) = queue.pop_front() {
58 let new_id = old_to_new[&old];
59 hash = if fsm.is_end_state(old as usize) {
60 mix(hash, &[new_id as u64, flag::END, flag::END, new_id as u64])
61 } else {
62 mix(
63 hash,
64 &[new_id as u64, flag::NOT_END, flag::NOT_END, new_id as u64],
65 )
66 };
67
68 let edges = sorted_edges(grammar, old as usize);
69 let mut hash_and_target: BTreeSet<(i64, i32)> = BTreeSet::new();
71 for edge in &edges {
72 if edge.is_rule_ref() {
73 let rid = edge.ref_rule_id();
74 let h = ref_hash(grammar, fsm_index, rid);
75 hash_and_target.insert((h as i64, edge.target));
76 } else if edge.is_repeat_ref() {
77 let info = grammar.complete_fsm.repeat_edge_info(edge.aux_index());
78 let rid = info.rule_id as i32;
79 let base = ref_hash(grammar, fsm_index, rid);
80 let rh = mix(base, &[info.lower as i64 as u64, info.upper as i64 as u64]);
81 hash_and_target.insert((rh as i64, edge.target));
82 }
83 }
84 for (h, target) in hash_and_target {
85 assign(&mut old_to_new, &mut queue, target);
86 let tnew = old_to_new[&target];
87 hash = mix(hash, &[new_id as u64, h as u64, tnew as u64]);
88 }
89 for edge in &edges {
91 assign(&mut old_to_new, &mut queue, edge.target);
92 let tnew = old_to_new[&edge.target];
93 if edge.is_rule_ref() || edge.is_repeat_ref() {
94 continue;
95 }
96 hash = mix(
97 hash,
98 &[
99 new_id as u64,
100 edge.min as i64 as u64,
101 edge.max as i64 as u64,
102 tnew as u64,
103 ],
104 );
105 }
106 }
107 (hash, old_to_new.into_iter().collect())
108}
109
110fn ref_hash(grammar: &GrammarData, fsm_index: i32, ref_rule_id: i32) -> u64 {
112 if ref_rule_id == fsm_index {
113 flag::SELF_RECURSION
114 } else {
115 grammar.per_rule_fsm_hashes[ref_rule_id as usize]
116 .expect("referenced rule must already be hashed")
117 }
118}
119
120fn assign(map: &mut BTreeMap<i32, i32>, queue: &mut VecDeque<i32>, target: i32) {
122 if !map.contains_key(&target) {
123 let new_id = map.len() as i32;
124 map.insert(target, new_id);
125 queue.push_back(target);
126 }
127}
128
129pub fn partial_hash_fsm(grammar: &GrammarData, fsm_index: i32) -> Option<(u64, Vec<(i32, i32)>)> {
132 let fsm = grammar.per_rule_fsms[fsm_index as usize].as_ref()?;
133 let start = fsm.start() as i32;
134 let mut old_to_new: BTreeMap<i32, i32> = BTreeMap::new();
135 old_to_new.insert(start, 0);
136 let mut queue: VecDeque<i32> = VecDeque::new();
137 queue.push_back(start);
138 let mut hash = 0u64;
139
140 while let Some(old) = queue.pop_front() {
141 let is_start = old == start;
142 let new_id = old_to_new[&old];
143 hash = if fsm.is_end_state(old as usize) {
144 mix(hash, &[new_id as u64, flag::END, flag::END, new_id as u64])
145 } else {
146 mix(
147 hash,
148 &[new_id as u64, flag::NOT_END, flag::NOT_END, new_id as u64],
149 )
150 };
151
152 let edges = sorted_edges(grammar, old as usize);
153 let mut hash_and_target: BTreeSet<(i64, i32)> = BTreeSet::new();
154 let mut unhashed = 0;
155 for edge in &edges {
156 let rid = if edge.is_rule_ref() {
157 edge.ref_rule_id()
158 } else if edge.is_repeat_ref() {
159 grammar
160 .complete_fsm
161 .repeat_edge_info(edge.aux_index())
162 .rule_id as i32
163 } else {
164 continue;
165 };
166 if rid == fsm_index {
167 hash_and_target.insert((flag::SELF_RECURSION as i64, edge.target));
168 continue;
169 }
170 match grammar.per_rule_fsm_hashes[rid as usize] {
171 Some(h) => {
172 hash_and_target.insert((h as i64, edge.target));
173 }
174 None => {
175 if !is_start {
176 return None;
177 }
178 unhashed += 1;
179 if unhashed > 1 {
180 return None;
181 }
182 hash_and_target.insert((flag::UNKNOWN as i64, edge.target));
183 }
184 }
185 }
186 for (h, target) in hash_and_target {
187 assign(&mut old_to_new, &mut queue, target);
188 let tnew = old_to_new[&target];
189 hash = mix(hash, &[new_id as u64, h as u64, tnew as u64]);
190 }
191 for edge in &edges {
192 assign(&mut old_to_new, &mut queue, edge.target);
193 let tnew = old_to_new[&edge.target];
194 if edge.is_rule_ref() || edge.is_repeat_ref() {
195 continue;
196 }
197 hash = mix(
198 hash,
199 &[
200 new_id as u64,
201 edge.min as i64 as u64,
202 edge.max as i64 as u64,
203 tnew as u64,
204 ],
205 );
206 }
207 }
208 Some((hash, old_to_new.into_iter().collect()))
209}