use std::path::Path;
use crate::loader::Loader;
use crate::{Interner, Lexer, mwe};
use super::{TypeRegistry, TypeDef, DiscoveryPass, scan_dependencies};
pub fn discover_with_imports(
file_path: &Path,
source: &str,
loader: &mut Loader,
interner: &mut Interner,
) -> Result<TypeRegistry, String> {
let mut registry = TypeRegistry::with_primitives(interner);
let deps = scan_dependencies(source);
for dep in deps {
let module_source = loader.resolve(file_path, &dep.uri)?;
let dep_content = module_source.content.clone();
let dep_path = module_source.path.clone();
let dep_registry = discover_with_imports(
&dep_path,
&dep_content,
loader,
interner
)?;
merge_registry(&mut registry, &dep.alias, dep_registry, interner);
}
let mut lexer = Lexer::new(source, interner);
let tokens = lexer.tokenize();
let mwe_trie = mwe::build_mwe_trie();
let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, interner);
let mut discovery = DiscoveryPass::new(&tokens, interner);
let local_registry = discovery.run();
for (sym, def) in local_registry.iter_types() {
let name = interner.resolve(*sym);
if !["Int", "Nat", "Text", "Bool", "Real", "Unit"].contains(&name) {
registry.register(*sym, def.clone());
}
}
Ok(registry)
}
fn merge_registry(
main: &mut TypeRegistry,
namespace: &str,
dep: TypeRegistry,
interner: &mut Interner,
) {
for (sym, def) in dep.iter_types() {
let orig_name = interner.resolve(*sym);
if ["Int", "Nat", "Text", "Bool", "Real", "Unit"].contains(&orig_name) {
continue;
}
let namespaced = format!("{}::{}", namespace, orig_name);
let namespaced_sym = interner.intern(&namespaced);
let namespaced_def = match def {
TypeDef::Struct { fields, generics, is_portable, is_shared } => TypeDef::Struct {
fields: fields.clone(),
generics: generics.clone(),
is_portable: *is_portable,
is_shared: *is_shared,
},
TypeDef::Enum { variants, generics, is_portable, is_shared } => TypeDef::Enum {
variants: variants.clone(),
generics: generics.clone(),
is_portable: *is_portable,
is_shared: *is_shared,
},
TypeDef::Alias { target } => TypeDef::Alias {
target: target.clone(),
},
TypeDef::Generic { param_count } => TypeDef::Generic {
param_count: *param_count,
},
TypeDef::Primitive => TypeDef::Primitive,
};
main.register(namespaced_sym, namespaced_def);
}
}