use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use genotype_parser::{
tree::{GTIdentifier, GTImportName, GTImportReference, GTPath},
GTDefinitionId, GTReferenceId,
};
use miette::Result;
use crate::error::GTProjectError;
use super::{GTProjectModuleParse, GTProjectModulePath};
#[derive(Debug, PartialEq, Clone)]
pub struct GTProjectModuleResolve {
pub deps: HashMap<GTPath, Arc<GTProjectModulePath>>,
pub references_identifiers: HashMap<GTIdentifier, GTProjectModuleReference>,
pub references: HashMap<GTDefinitionId, HashSet<GTReferenceId>>,
}
impl GTProjectModuleResolve {
pub fn try_new(
modules: &Vec<GTProjectModuleParse>,
parse: >ProjectModuleParse,
) -> Result<Self> {
let mut deps = HashMap::new();
for local_path in parse.1.resolve.deps.iter() {
if deps.contains_key(local_path) {
continue;
}
let path = Arc::new(
parse
.0
.resolve(local_path)
.map_err(|_| GTProjectError::CannotResolve(local_path.as_str().to_owned()))?,
);
deps.insert(local_path.clone(), path);
}
let mut references_identifiers = HashMap::new();
for reference in parse.1.resolve.references.iter() {
if references_identifiers.contains_key(reference) {
continue;
};
if parse
.1
.resolve
.exports
.iter()
.any(|export| export.1 == reference.1)
{
references_identifiers.insert(reference.clone(), GTProjectModuleReference::Local);
continue;
}
let (local_path, _) = deps
.iter()
.find(|(local_path, path)| {
let import = parse.1.module.imports.iter().find(|import| {
if import.path != **local_path {
return false;
}
match &import.reference {
GTImportReference::Glob(_) => {
let module =
modules.iter().find(|module| module.0 == ***path).unwrap();
module
.1
.resolve
.exports
.iter()
.any(|export| export.1 == reference.1)
}
GTImportReference::Name(_, name) => name.1 == reference.1,
GTImportReference::Names(_, names) => {
names.iter().any(|name| match name {
GTImportName::Name(_, name) => name.1 == reference.1,
GTImportName::Alias(_, _, alias) => alias.1 == reference.1,
})
}
}
});
!import.is_none()
})
.ok_or_else(|| GTProjectError::UndefinedType {
span: reference.as_span(),
identifier: reference.as_string(),
})?;
references_identifiers.insert(
reference.clone(),
GTProjectModuleReference::External(local_path.clone()),
);
}
Ok(GTProjectModuleResolve {
deps,
references_identifiers,
references: Default::default(),
})
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum GTProjectModuleReference {
Local,
External(GTPath),
}