1#![warn(missing_docs)]
2
3use chomsky_uir::{Analysis, EGraph, IKun, Id, Language};
4use std::collections::HashMap;
5
6pub struct IKunLinker<A: Analysis<IKun>> {
8 pub global_graph: EGraph<IKun, A>,
10 exports: HashMap<(String, String), Id>,
12}
13
14impl<A: Analysis<IKun> + Default> IKunLinker<A> {
15 pub fn new() -> Self {
16 Self {
17 global_graph: EGraph::new(),
18 exports: HashMap::new(),
19 }
20 }
21
22 pub fn add_module(&mut self, module_name: &str, graph: &EGraph<IKun, A>) {
25 for entry in graph.classes.iter() {
27 let class = entry.value();
28 for node in &class.nodes {
29 if let IKun::Export(_name, _body_id) = node {
30 }
32 }
33 }
34
35 self.merge_graph(module_name, graph);
36 }
37
38 fn merge_graph(&mut self, module_name: &str, source: &EGraph<IKun, A>) {
39 let mut id_map = HashMap::new();
40
41 for entry in source.classes.iter() {
43 let class = entry.value();
44 for node in &class.nodes {
45 let new_id = self.add_node_recursive(node, source, &mut id_map);
46 id_map.insert(class.id, new_id);
47
48 if let IKun::Export(name, _) = node {
50 self.exports
51 .insert((module_name.to_string(), name.clone()), new_id);
52 }
53 }
54 }
55 }
56
57 fn add_node_recursive(
58 &mut self,
59 node: &IKun,
60 source: &EGraph<IKun, A>,
61 id_map: &mut HashMap<Id, Id>,
62 ) -> Id {
63 let remapped = node.map_children(|child_id| {
64 if let Some(&new_id) = id_map.get(&child_id) {
65 new_id
66 } else {
67 let child_class = source.get_class(child_id);
69 let child_node = &child_class.nodes[0];
71 let new_id = self.add_node_recursive(child_node, source, id_map);
72 id_map.insert(child_id, new_id);
73 new_id
74 }
75 });
76 self.global_graph.add(remapped)
77 }
78
79 pub fn link(&mut self) {
81 let mut links_to_make = Vec::new();
82
83 for entry in self.global_graph.classes.iter() {
84 let id = *entry.key();
85 let class = entry.value();
86 for node in &class.nodes {
87 if let IKun::Import(mod_name, sym_name) = node {
88 if let Some(&export_id) =
89 self.exports.get(&(mod_name.clone(), sym_name.clone()))
90 {
91 links_to_make.push((id, export_id));
92 }
93 }
94 }
95 }
96
97 for (import_id, export_id) in links_to_make {
99 self.global_graph.union(import_id, export_id);
100 }
101
102 self.global_graph.rebuild();
103 }
104}