erg_compiler/module/
index.rs

1use std::collections::hash_map::{Iter, Keys, Values};
2use std::fmt;
3
4use erg_common::dict::Dict;
5use erg_common::pathutil::NormalizedPathBuf;
6use erg_common::set;
7use erg_common::set::Set;
8use erg_common::shared::{MappedRwLockReadGuard, RwLockReadGuard, Shared};
9use erg_common::Str;
10
11use crate::varinfo::{AbsLocation, VarInfo};
12
13pub struct Members<'a>(MappedRwLockReadGuard<'a, Dict<AbsLocation, ModuleIndexValue>>);
14
15impl Members<'_> {
16    pub fn iter(&self) -> Iter<'_, AbsLocation, ModuleIndexValue> {
17        self.0.iter()
18    }
19
20    pub fn keys(&self) -> Keys<'_, AbsLocation, ModuleIndexValue> {
21        self.0.keys()
22    }
23
24    pub fn values(&self) -> Values<'_, AbsLocation, ModuleIndexValue> {
25        self.0.values()
26    }
27}
28
29#[derive(Debug, Clone)]
30pub struct ModuleIndexValue {
31    pub name: Str,
32    pub vi: VarInfo,
33    pub referrers: Set<AbsLocation>,
34}
35
36impl fmt::Display for ModuleIndexValue {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(
39            f,
40            "{{ name: {}, vi: {}, referrers: {} }}",
41            self.name, self.vi, self.referrers
42        )
43    }
44}
45
46impl ModuleIndexValue {
47    pub const fn new(name: Str, vi: VarInfo, referrers: Set<AbsLocation>) -> Self {
48        Self {
49            name,
50            vi,
51            referrers,
52        }
53    }
54
55    pub fn push_ref(&mut self, referrer: AbsLocation) {
56        self.referrers.insert(referrer);
57    }
58}
59
60#[derive(Debug, Clone, Default)]
61pub struct ModuleIndex {
62    members: Dict<AbsLocation, ModuleIndexValue>,
63}
64
65impl fmt::Display for ModuleIndex {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        self.members.fmt(f)
68    }
69}
70
71impl ModuleIndex {
72    pub fn new() -> Self {
73        Self {
74            members: Dict::new(),
75        }
76    }
77
78    pub fn inc_ref(&mut self, name: &Str, vi: &VarInfo, referrer: AbsLocation) {
79        let referee = vi.def_loc.clone();
80        if let Some(referrers) = self.members.get_mut(&referee) {
81            referrers.push_ref(referrer);
82        } else {
83            let value = ModuleIndexValue::new(name.clone(), vi.clone(), set! {referrer});
84            self.members.insert(referee, value);
85        }
86    }
87
88    pub fn register(&mut self, name: Str, vi: &VarInfo) {
89        if self.members.contains_key(&vi.def_loc) {
90            return;
91        }
92        let referee = vi.def_loc.clone();
93        let value = ModuleIndexValue::new(name, vi.clone(), set! {});
94        self.members.insert(referee, value);
95    }
96
97    pub fn get_refs(&self, referee: &AbsLocation) -> Option<&ModuleIndexValue> {
98        self.members.get(referee)
99    }
100
101    pub fn initialize(&mut self) {
102        self.members.clear();
103    }
104
105    pub fn remove_path(&mut self, path: &NormalizedPathBuf) {
106        self.members.retain(|loc, value| {
107            value
108                .referrers
109                .retain(|ref_loc| ref_loc.module.as_deref() != Some(path));
110            loc.module.as_deref() != Some(path)
111        });
112    }
113
114    pub fn rename_path(&mut self, old: &NormalizedPathBuf, new: NormalizedPathBuf) {
115        let mut new_members = Dict::new();
116        for (loc, mut value) in std::mem::take(&mut self.members) {
117            if value.vi.def_loc.module.as_deref() == Some(old) {
118                value.vi.def_loc.module = Some(new.clone());
119            }
120            let mut new_referrers = set! {};
121            for referee in value.referrers.into_iter() {
122                if referee.module.as_deref() == Some(old) {
123                    new_referrers.insert(AbsLocation {
124                        module: Some(new.clone()),
125                        ..referee
126                    });
127                } else {
128                    new_referrers.insert(referee);
129                }
130            }
131            value.referrers = new_referrers;
132            if loc.module.as_deref() != Some(old) {
133                new_members.insert(loc.clone(), value.clone());
134            } else {
135                new_members.insert(
136                    AbsLocation {
137                        module: Some(new.clone()),
138                        ..loc
139                    },
140                    value,
141                );
142            }
143        }
144        self.members = new_members;
145    }
146}
147
148#[derive(Debug, Clone, Default)]
149pub struct SharedModuleIndex(Shared<ModuleIndex>);
150
151impl fmt::Display for SharedModuleIndex {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        self.0.borrow().fmt(f)
154    }
155}
156
157impl SharedModuleIndex {
158    pub fn new() -> Self {
159        Self(Shared::new(ModuleIndex::new()))
160    }
161
162    pub fn inc_ref(&self, name: &Str, vi: &VarInfo, referrer: AbsLocation) {
163        self.0.borrow_mut().inc_ref(name, vi, referrer);
164    }
165
166    pub fn register(&self, name: Str, vi: &VarInfo) {
167        self.0.borrow_mut().register(name, vi);
168    }
169
170    pub fn get_refs(
171        &self,
172        referee: &AbsLocation,
173    ) -> Option<MappedRwLockReadGuard<'_, ModuleIndexValue>> {
174        RwLockReadGuard::try_map(self.0.borrow(), |index| index.get_refs(referee)).ok()
175    }
176
177    pub fn members(&self) -> Members<'_> {
178        Members(RwLockReadGuard::map(self.0.borrow(), |mi| &mi.members))
179    }
180
181    pub fn initialize(&self) {
182        self.0.borrow_mut().initialize();
183    }
184
185    pub fn remove_path(&self, path: &NormalizedPathBuf) {
186        self.0.borrow_mut().remove_path(path);
187    }
188
189    pub fn rename_path(&self, old: &NormalizedPathBuf, new: NormalizedPathBuf) {
190        self.0.borrow_mut().rename_path(old, new);
191    }
192}