bend/fun/transform/
definition_merge.rs1use crate::{
2 fun::{Book, Definition, Name, Rule, Term},
3 maybe_grow,
4};
5use indexmap::{IndexMap, IndexSet};
6use itertools::Itertools;
7use std::collections::BTreeMap;
8
9pub const MERGE_SEPARATOR: &str = "__M_";
10
11impl Book {
12 pub fn merge_definitions(&mut self) {
18 let defs: Vec<_> = self.defs.keys().cloned().collect();
19 self.merge(defs.into_iter());
20 }
21
22 fn merge(&mut self, defs: impl Iterator<Item = Name>) {
25 let name = self.entrypoint.clone();
26 let equal_terms =
28 self.collect_terms(defs.filter(|def_name| !name.as_ref().is_some_and(|m| m == def_name)));
29
30 let mut name_map = BTreeMap::new();
32
33 for (term, equal_defs) in equal_terms {
34 let new_name = Name::new(equal_defs.iter().join(MERGE_SEPARATOR));
36
37 if equal_defs.len() > 1 {
38 let any_def_name = equal_defs.iter().next().unwrap(); let source = self.defs[any_def_name].source.clone();
48 let rules = vec![Rule { pats: vec![], body: term }];
49 let new_def = Definition::new_gen(new_name.clone(), rules, source, false);
51 self.defs.insert(new_name.clone(), new_def);
52 for name in equal_defs {
54 self.defs.swap_remove(&name);
55 name_map.insert(name, new_name.clone());
56 }
57 } else {
58 let def_name = equal_defs.into_iter().next().unwrap();
60 let def = self.defs.get_mut(&def_name).unwrap();
61 def.rule_mut().body = term;
62 }
63 }
64 self.update_refs(&name_map);
65 }
66
67 fn collect_terms(&mut self, def_entries: impl Iterator<Item = Name>) -> IndexMap<Term, IndexSet<Name>> {
68 let mut equal_terms: IndexMap<Term, IndexSet<Name>> = IndexMap::new();
69
70 for def_name in def_entries {
71 let def = self.defs.get_mut(&def_name).unwrap();
72 let term = std::mem::take(&mut def.rule_mut().body);
73 equal_terms.entry(term).or_default().insert(def_name);
74 }
75
76 equal_terms
77 }
78
79 fn update_refs(&mut self, name_map: &BTreeMap<Name, Name>) {
80 let mut updated_defs = Vec::new();
81
82 for def in self.defs.values_mut() {
83 if Term::subst_ref_to_ref(&mut def.rule_mut().body, name_map) {
84 updated_defs.push(def.name.clone());
85 }
86 }
87
88 if !updated_defs.is_empty() {
89 self.merge(updated_defs.into_iter());
90 }
91 }
92}
93
94impl Term {
95 pub fn subst_ref_to_ref(term: &mut Term, ref_map: &BTreeMap<Name, Name>) -> bool {
98 maybe_grow(|| match term {
99 Term::Ref { nam: def_name } => {
100 if let Some(target_name) = ref_map.get(def_name) {
101 *def_name = target_name.clone();
102 true
103 } else {
104 false
105 }
106 }
107
108 _ => {
109 let mut subst = false;
110 for child in term.children_mut() {
111 subst |= Term::subst_ref_to_ref(child, ref_map);
112 }
113 subst
114 }
115 })
116 }
117}