use std::collections::HashMap;
use uni_cypher::locy_ast::{LocyProgram, UseDecl};
use super::errors::LocyCompileError;
#[derive(Debug, Clone, Default)]
pub struct ModuleContext {
pub module_name: Option<String>,
pub imports: HashMap<String, String>,
}
pub fn resolve_modules(
program: &LocyProgram,
available_modules: &HashMap<String, Vec<String>>,
) -> Result<ModuleContext, LocyCompileError> {
let mut ctx = ModuleContext::default();
if let Some(module_decl) = &program.module {
ctx.module_name = Some(module_decl.name.to_string());
}
for use_decl in &program.uses {
resolve_use(&mut ctx, use_decl, available_modules)?;
}
Ok(ctx)
}
fn resolve_use(
ctx: &mut ModuleContext,
use_decl: &UseDecl,
available_modules: &HashMap<String, Vec<String>>,
) -> Result<(), LocyCompileError> {
let module_name = use_decl.name.to_string();
if let Some(rules) = available_modules.get(&module_name) {
match &use_decl.imports {
None => {
for rule in rules {
ctx.imports
.insert(rule.clone(), format!("{}.{}", module_name, rule));
}
}
Some(selected) => {
for name in selected {
if rules.contains(name) {
ctx.imports
.insert(name.clone(), format!("{}.{}", module_name, name));
} else {
return Err(LocyCompileError::ImportNotFound {
module: module_name,
rule: name.clone(),
});
}
}
}
}
Ok(())
} else {
Err(LocyCompileError::ModuleNotFound { name: module_name })
}
}
pub fn resolve_rule_name(ctx: &ModuleContext, name: &str) -> String {
if let Some(qualified) = ctx.imports.get(name) {
qualified.clone()
} else if let Some(module) = &ctx.module_name {
if !name.contains('.') {
format!("{}.{}", module, name)
} else {
name.to_string()
}
} else {
name.to_string()
}
}