runmat-hir 0.4.4

High-level IR for RunMat with type inference and lowering utilities
Documentation
use crate::{HirProgram, HirStmt, SemanticError};

pub fn collect_imports(prog: &HirProgram) -> Vec<(Vec<String>, bool)> {
    let mut imports = Vec::new();
    for stmt in &prog.body {
        if let HirStmt::Import { path, wildcard, .. } = stmt {
            imports.push((path.clone(), *wildcard));
        }
    }
    imports
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NormalizedImport {
    pub path: String,
    pub wildcard: bool,
    pub unqualified: Option<String>,
}

pub fn normalize_imports(prog: &HirProgram) -> Vec<NormalizedImport> {
    let mut out = Vec::new();
    for stmt in &prog.body {
        if let HirStmt::Import { path, wildcard, .. } = stmt {
            let path_str = path.join(".");
            let last = if *wildcard {
                None
            } else {
                path.last().cloned()
            };
            out.push(NormalizedImport {
                path: path_str,
                wildcard: *wildcard,
                unqualified: last,
            });
        }
    }
    out
}

pub fn validate_imports(prog: &HirProgram) -> Result<(), SemanticError> {
    use std::collections::{HashMap, HashSet};

    let norms = normalize_imports(prog);
    let mut seen_exact: HashSet<(String, bool)> = HashSet::new();
    for n in &norms {
        if !seen_exact.insert((n.path.clone(), n.wildcard)) {
            return Err(SemanticError::new(format!(
                "duplicate import '{}{}'",
                n.path,
                if n.wildcard { ".*" } else { "" }
            )));
        }
    }

    let mut by_name: HashMap<String, Vec<String>> = HashMap::new();
    for n in &norms {
        if !n.wildcard {
            if let Some(uq) = &n.unqualified {
                by_name.entry(uq.clone()).or_default().push(n.path.clone());
            }
        }
    }
    for (uq, sources) in by_name {
        if sources.len() > 1 {
            return Err(SemanticError::new(format!(
                "ambiguous import for '{}': {}",
                uq,
                sources.join(", ")
            )));
        }
    }
    Ok(())
}