ModuleResolver – Resolución de Módulos y Paquetes

Archivo: src/module.rs507 líneas

¿Por qué existe?

Gestiona la carga, composición y recarga de módulos de código Forja, permitiendo que los archivos .fa se importen entre sí (importar ruta) y que dependencias externas provengan de paquetes publicados o módulos embebidos en el binario del compilador. Es el sistema de resolución de dependencias del lenguaje.

Estructuras principales

ModuleInfo

Almacena la información completa de un módulo cargado.

CampoTipoDescripción
source_pathStringRuta absoluta al archivo fuente del módulo
source_hashu64Hash del contenido fuente para detectar cambios
funcionesVec<(String, SymId)>Lista de funciones exportadas (nombre, SymId)
variables_globalesVec<(String, SymId)>Lista de variables globales exportadas
importsVec<ModuleId>IDs de los módulos que este módulo importa
dependentsVec<ModuleId>IDs de los módulos que dependen de este (para recarga en cascada)
bytecodeOption<ModuleBytecode>Bytecode compilado del módulo (opcional, se genera bajo demanda)
versionu64Contador de versiones para detectar cambios

ModuleCache

Cache de módulos con índices por ruta y por ID, más grafos de importación y dependencias.

CampoTipoDescripción
por_rutaHashMap<String, ModuleId>Índice de módulos por ruta de archivo
por_idHashMap<ModuleId, ModuleInfo>Índice de módulos por ID (SymId)
grafo_importacionesHashMap<ModuleId, Vec<ModuleId>>Grafo dirigido de importaciones
grafo_dependientesHashMap<ModuleId, Vec<ModuleId>>Grafo inverso de dependientes (para recarga en cascada)

ModuleResolver

CampoTipoDescripción
root_dirPathBufDirectorio raíz del proyecto (donde se resuelven rutas relativas)
cacheHashMap<String, Programa>Cache de ASTs resueltos por ruta
package_resolverOption<PackageResolver>Resolvedor de paquetes externos (opcional)
module_cacheModuleCacheCache estructurada de módulos con metadatos

Métodos públicos

Constructor y configuración

FirmaDescripción
pub fn new(root_dir: &str) -> Self Crea un nuevo ModuleResolver con el directorio raíz especificado y caches vacíos

Resolución de módulos

FirmaDescripción
pub fn resolver(&mut self, ruta: &str) -> Result<Programa, Vec<ErrorForja>> Resuelve un módulo por ruta. Normaliza la ruta, verifica seguridad (path traversal), lee el archivo, tokeniza, parsea, resuelve recursivamente imports y cachea el AST.
pub fn resolver_con_id(&mut self, ruta: &str) -> Result<(Programa, ModuleId), Vec<ErrorForja>> Similar a resolver() pero además retorna el ModuleId asignado al módulo. Es el método principal de resolución (~188 líneas).
fn resolver_con_id_embebido(&mut self, ruta_embedded: &str) -> Result<(Programa, ModuleId), Vec<ErrorForja>> Resuelve módulos embebidos (prefijo embedded://). Busca el módulo en la lista de stdlib embebida (stdlib_embedded.rs), lo parsea y lo registra en el cache.

Recarga de módulos

FirmaDescripción
pub fn recargar(&mut self, module_id: ModuleId) -> Result<Programa, Vec<ErrorForja>> Recarga un módulo por su ID. Vuelve a leer el archivo fuente, re-parsea, re-compila y actualiza el cache. Si el módulo ya no existe, lo elimina del cache y propaga la invalidación a sus dependientes.
pub fn modulo_cambio(&mut self, ruta: &str) -> bool Verifica si un módulo ha cambiado comparando el hash actual del archivo con el hash almacenado. Retorna cierto si el archivo fue modificado.
pub fn modulos_cambiados(&self) -> Vec<(ModuleId, String)> Retorna una lista de todos los módulos cuyo archivo fuente ha cambiado desde la última recarga. Iteración sobre todos los módulos en cache comparando hashes.

Registro y consulta de módulos

FirmaDescripción
pub fn registrar_modulo(&mut self, module_id: ModuleId, info: ModuleInfo) Registra un módulo en el cache. Actualiza los índices por ruta y por ID, y mantiene el grafo de importaciones/dependencias.
pub fn dependientes_de(&self, module_id: ModuleId) -> Option<&[ModuleId]> Retorna los IDs de módulos que dependen del módulo especificado
pub fn importaciones_de(&self, module_id: ModuleId) -> Option<&[ModuleId]> Retorna los IDs de módulos que el módulo especificado importa

Utilidades

FirmaDescripción
pub fn hash_fuente(ruta: &str) -> u64 Calcula un hash CRC32 del contenido de un archivo fuente. Usado para detectar cambios en módulos. Si el archivo no existe, retorna 0.

Funciones auxiliares

dedup_declaraciones()

FirmaDescripción
pub fn dedup_declaraciones(decls: Vec<Declaracion>) -> Vec<Declaracion> Elimina declaraciones duplicadas basándose en una clave única que identifica cada declaración: fn:nombre:tipos para funciones (incluye tipos de parámetros para soportar sobrecarga), cls:nombre para clases, var:nombre para variables globales. Si hay conflicto, la última declaración prevalece.

formato_tipo_para_key()

FirmaDescripción
fn formato_tipo_para_key(t: &Tipo) -> String Convierte un Tipo a su representación textual para usar como parte de la clave de deduplicación. Permite diferenciar sobrecargas de funciones con tipos distintos en los parámetros.

Pipeline de resolución de módulos

┌─────────────┐
│ importar    │
│ "ruta/foo"  │
└──────┬──────┘
       ▼
┌──────────────────────────────┐
│ 1. Normalizar ruta           │
│    - Unir con root_dir       │
│    - Prevenir path traversal │
│    - Rechazar rutas absolutas│
└──────┬───────────────────────┘
       ▼
┌──────────────────────────────┐
│ 2. ¿Módulo embebido?         │──▶ embedded:// → resolver_con_id_embebido
└──────┬───────────────────────┘
       ▼ (no)
┌──────────────────────────────┐
│ 3. ¿En cache?                │──▶ Sí → retornar Programa cacheado
└──────┬───────────────────────┘
       ▼ (no)
┌──────────────────────────────┐
│ 4. Leer archivo fuente       │
│    - Límite de tamaño        │
│    - Hash CRC32              │
└──────┬───────────────────────┘
       ▼
┌──────────────────────────────┐
│ 5. Tokenizar (lexer)         │
│ 6. Parsear (parser) → AST    │
│ 7. Resolver imports recurs.  │
└──────┬───────────────────────┘
       ▼
┌──────────────────────────────┐
│ 8. Deduplicar declaraciones  │
│ 9. Cachear Programa          │
│ 10. Registrar en ModuleCache │
│ 11. Retornar Programa        │
└──────────────────────────────┘

Seguridad

Relación con el resto del compilador