forester_rs/tree/project/
imports.rs1use crate::tree::parser::ast::{ImportName, Tree};
2use crate::tree::project::{AliasName, File, FileName, Project, TreeName};
3use crate::tree::{cerr, TreeError};
4use std::collections::{HashMap, HashSet};
5
6#[derive(Default)]
8pub struct ImportMap {
9 pub aliases: HashMap<AliasName, TreeName>,
10 pub trees: HashMap<TreeName, FileName>,
11 pub files: HashSet<FileName>,
12}
13
14impl ImportMap {
15 pub fn build(file: &File) -> Result<Self, TreeError> {
20 let mut map = ImportMap::default();
21 for (file, items) in &file.imports {
22 for item in items {
23 match item {
24 ImportName::Id(v) => {
25 if map.trees.get(v).filter(|f| f != &file).is_some() {
26 return Err(cerr(format!("the import call {v} is presented twice from several different files")));
27 }
28 if map.aliases.get(v).is_some() {
29 return Err(cerr(format!("the import call {v} is presented as alias")));
30 }
31 map.trees.insert(v.to_string(), file.to_string());
32 }
33 ImportName::Alias(id, alias) => {
34 if map.aliases.get(alias).filter(|idt| *idt != id).is_some() {
35 return Err(cerr(format!(
36 "the import alias {alias} is already defined for another call "
37 )));
38 }
39 map.aliases.insert(alias.to_string(), id.to_string());
40 map.trees.insert(id.to_string(), file.to_string());
41 }
42 ImportName::WholeFile => {
43 map.files.insert(file.to_string());
44 }
45 }
46 }
47 }
48
49 Ok(map)
50 }
51
52 pub fn find<'a>(
54 &'a self,
55 key: &TreeName,
56 project: &'a Project,
57 ) -> Result<(&'a Tree, &'a FileName), TreeError> {
58 if let Some(file) = self.trees.get(key) {
60 project
61 .find_tree(file, key)
62 .map(|t| (t, file))
63 .ok_or(cerr(format!(
64 "the call {key} can not be found in the file {file} "
65 )))
66 } else if let Some(id) = self.aliases.get(key) {
68 let file = self
69 .trees
70 .get(id)
71 .ok_or(cerr(format!("the call {id} is not presented")))?;
72 project
73 .find_tree(file, id)
74 .map(|t| (t, file))
75 .ok_or(cerr(format!(
76 "the call {key} can not be found in the file {file} "
77 )))
78 } else {
79 self.files
81 .iter()
82 .flat_map(|f| project.files.get(f))
83 .find(|f| f.definitions.contains_key(key))
84 .and_then(|f| f.definitions.get(key).map(|t| (t, &f.name)))
85 .ok_or(cerr(format!(
86 "the call {key} can not be found among the file in the project"
87 )))
88 }
89 }
90}