use std::iter; use itertools::Itertools; use super::walk_with_links::walk_with_links; use crate::ast::{Expr, Rule}; use crate::representations::project::{ ItemKind, ProjectExt, ProjectItem, ProjectMod, }; use crate::tree::{ModEntry, ModMember, Module}; use crate::utils::pure_push::pushed; use crate::{Interner, ProjectTree, Tok, VName}; fn resolve_aliases_rec( root: &ProjectMod, module: &ProjectMod, updated: &impl Fn(&[Tok]) -> bool, is_root: bool, ) -> ProjectMod { if !is_root && !updated(&module.extra.path) { return module.clone(); } let process_expr = |expr: &Expr| { expr .map_names(&|n| { let full_name = (module.extra.path.iter()).chain(n.iter()).cloned(); match walk_with_links(root, full_name, false) { Ok(rep) => Some(rep.abs_path), // Ok(_) => None, Err(e) => { let leftovers = e.tail.collect::>(); if !leftovers.is_empty() { let full_name = (module.extra.path.iter()) .chain(n.iter()) .cloned() .collect::>(); let _ = walk_with_links(root, full_name.iter().cloned(), true); panic!( "Invalid path {} while resolving {} should have been noticed \ earlier", (e.abs_path.into_iter()) .chain(iter::once(e.name)) .chain(leftovers.into_iter()) .join("::"), Interner::extern_all(&full_name).join("::"), ); } Some(pushed(e.abs_path, e.name)) }, } }) .unwrap_or_else(|| expr.clone()) }; Module { extra: ProjectExt { path: module.extra.path.clone(), file: module.extra.file.clone(), imports_from: module.extra.imports_from.clone(), rules: (module.extra.rules.iter()) .map(|Rule { pattern, prio, template }| Rule { pattern: pattern.iter().map(process_expr).collect(), template: template.iter().map(process_expr).collect(), prio: *prio, }) .collect(), }, entries: module .entries .iter() .map(|(k, v)| { (k.clone(), ModEntry { exported: v.exported, member: match &v.member { ModMember::Sub(module) => ModMember::Sub(resolve_aliases_rec(root, module, updated, false)), ModMember::Item(item) => ModMember::Item(ProjectItem { is_op: item.is_op, kind: match &item.kind { ItemKind::Const(value) => ItemKind::Const(process_expr(value)), other => other.clone(), }, }), }, }) }) .collect(), } } pub fn resolve_aliases( project: ProjectTree, updated: &impl Fn(&[Tok]) -> bool, ) -> ProjectTree { ProjectTree(resolve_aliases_rec(&project.0, &project.0, updated, true)) }