microcad_lang/resolve/
sources.rs1use crate::{parse::*, rc::*, resolve::*, src_ref::*, syntax::*};
7use std::collections::HashMap;
8
9#[derive(Default)]
17pub struct Sources {
18 externals: Externals,
20
21 by_hash: HashMap<u64, usize>,
22 by_path: HashMap<std::path::PathBuf, usize>,
23 by_name: HashMap<QualifiedName, usize>,
24
25 source_files: Vec<Rc<SourceFile>>,
27
28 search_paths: Vec<std::path::PathBuf>,
30}
31
32impl Sources {
33 pub fn load(root: Rc<SourceFile>, search_paths: &[std::path::PathBuf]) -> ParseResult<Self> {
37 let mut source_files = Vec::new();
38 let mut by_name = HashMap::new();
39 let mut by_hash = HashMap::new();
40 let mut by_path = HashMap::new();
41
42 by_hash.insert(root.hash, 0);
43 by_path.insert(root.filename(), 0);
44 by_name.insert(root.name.clone(), 0);
45 source_files.push(root);
46
47 let externals = Externals::new(search_paths);
49
50 log::trace!("Externals:\n{externals}");
51
52 externals
54 .iter()
55 .try_for_each(|(name, path)| -> Result<(), ParseError> {
56 let source_file = SourceFile::load_with_name(path.clone(), name.clone())?;
57 let index = source_files.len();
58 by_hash.insert(source_file.hash, index);
59 by_path.insert(source_file.filename(), index);
60 by_name.insert(name.clone(), index);
61 source_files.push(source_file);
62 Ok(())
63 })?;
64
65 Ok(Self {
66 externals,
67 source_files,
68 by_hash,
69 by_path,
70 by_name,
71 search_paths: search_paths.to_vec(),
72 })
73 }
74
75 pub fn root(&self) -> Rc<SourceFile> {
77 self.source_files
78 .first()
79 .expect("empty source cache has not root")
80 .clone()
81 }
82
83 fn create_modules(externals: &Externals) -> SymbolMap {
85 let mut map = SymbolMap::new();
86 externals.iter().for_each(|(basename, _)| {
87 let (id, name) = basename.split_first();
88 let module = match map.get(&id) {
89 Some(symbol) => symbol.clone(),
90 _ => Symbol::new(
91 SymbolDefinition::Module(ModuleDefinition::new(Visibility::Public, id.clone())),
92 None,
93 ),
94 };
95 Self::recursive_create_modules(&module, &name);
96 map.insert(id.clone(), module);
97 });
98 map
99 }
100
101 fn recursive_create_modules(parent: &Symbol, name: &QualifiedName) -> Option<Symbol> {
102 if name.is_empty() {
103 return None;
104 }
105
106 let node_id = name.first().expect("Non-empty qualified name");
107 if let Some(child) = parent.get(node_id) {
108 return Some(child.clone());
109 }
110
111 let child = Symbol::new(
112 SymbolDefinition::Module(ModuleDefinition::new(Visibility::Public, node_id.clone())),
113 None,
114 );
115 Symbol::add_child(parent, child.clone());
116
117 Self::recursive_create_modules(&child, &name.remove_first());
118 Some(child)
119 }
120
121 pub fn resolve(&self) -> ResolveResult<SymbolMap> {
123 let mut symbols = Self::create_modules(&self.externals);
124 symbols.insert(
125 self.root().id(),
126 Symbol::new(SymbolDefinition::SourceFile(self.root()), None),
127 );
128
129 self.source_files
130 .iter()
131 .try_for_each(|source_file| -> Result<(), ResolveError> {
132 let name = &source_file.name;
133 log::trace!(
134 "{resolve} file {path:?} [{name}]",
135 resolve = crate::mark!(RESOLVE),
136 path = source_file.filename(),
137 );
138 let symbol = source_file.resolve()?;
139
140 let target = symbols.search(name)?;
142 target.move_children(&symbol);
143
144 Ok(())
145 })?;
146
147 Ok(symbols)
148 }
149
150 pub fn name_by_path(&self, filename: &std::path::Path) -> ResolveResult<QualifiedName> {
152 Ok(self.externals.get_name(filename)?.clone())
153 }
154
155 pub fn get_by_src_ref(&self, referrer: &impl SrcReferrer) -> ResolveResult<Rc<SourceFile>> {
157 self.get_by_hash(referrer.src_ref().source_hash())
158 }
159
160 pub fn ref_str(&self, referrer: &impl SrcReferrer) -> String {
162 format!(
163 "{}:{}",
164 self.get_by_src_ref(referrer)
165 .expect("Source file not found")
166 .filename_as_str(),
167 referrer.src_ref(),
168 )
169 }
170
171 pub fn get_by_path(&self, path: &std::path::Path) -> ResolveResult<Rc<SourceFile>> {
173 let path = path.to_path_buf();
174 if let Some(index) = self.by_path.get(&path) {
175 Ok(self.source_files[*index].clone())
176 } else {
177 Err(ResolveError::FileNotFound(path))
178 }
179 }
180
181 pub fn get_name_by_hash(&self, hash: u64) -> ResolveResult<&QualifiedName> {
183 match self.get_by_hash(hash) {
184 Ok(file) => self.externals.get_name(&file.filename()),
185 Err(err) => Err(err),
186 }
187 }
188
189 pub fn get_by_name(&self, name: &QualifiedName) -> ResolveResult<Rc<SourceFile>> {
191 if let Some(index) = self.by_name.get(name) {
192 Ok(self.source_files[*index].clone())
193 } else {
194 match self.externals.fetch_external(name) {
196 Ok((name, path)) => {
197 if self.get_by_path(&path).is_err() {
198 return Err(ResolveError::SymbolMustBeLoaded(name, path));
199 }
200 }
201 Err(ResolveError::ExternalSymbolNotFound(_)) => (),
202 Err(err) => return Err(err),
203 }
204 Err(ResolveError::SymbolNotFound(name.clone()))
205 }
206 }
207
208 fn name_from_index(&self, index: usize) -> Option<QualifiedName> {
209 self.by_name
210 .iter()
211 .find(|(_, i)| **i == index)
212 .map(|(name, _)| name.clone())
213 }
214
215 pub fn search_paths(&self) -> &Vec<std::path::PathBuf> {
217 &self.search_paths
218 }
219}
220
221pub trait GetSourceByHash {
223 fn get_by_hash(&self, hash: u64) -> ResolveResult<Rc<SourceFile>>;
225}
226
227impl GetSourceByHash for Sources {
228 fn get_by_hash(&self, hash: u64) -> ResolveResult<Rc<SourceFile>> {
230 if let Some(index) = self.by_hash.get(&hash) {
231 Ok(self.source_files[*index].clone())
232 } else if hash == 0 {
233 Err(ResolveError::NulHash)
234 } else {
235 Err(ResolveError::UnknownHash(hash))
236 }
237 }
238}
239
240impl std::fmt::Display for Sources {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 for (index, source_file) in self.source_files.iter().enumerate() {
243 let filename = source_file.filename_as_str();
244 let name = self
245 .name_from_index(index)
246 .unwrap_or(QualifiedName::no_ref(vec![]));
247 let hash = source_file.hash;
248 writeln!(f, "[{index}] {name:?} {hash:#x} {filename}")?;
249 }
250 Ok(())
251 }
252}