From: Bryan English Date: Sat, 14 Feb 2026 05:52:29 +0000 (-0500) Subject: some cleanup of ir.rs X-Git-Url: https://rethought.computer/gitweb//gitweb//git?a=commitdiff_plain;h=48389b39ef79c61b4106429c1e3b84a84a8a32c7;p=sorel-lang.git some cleanup of ir.rs --- diff --git a/sorelc/src/ir.rs b/sorelc/src/ir.rs index 7b931c4..88c2f47 100644 --- a/sorelc/src/ir.rs +++ b/sorelc/src/ir.rs @@ -1,29 +1,53 @@ use crate::parser::Module; use crate::tokenizer::{Token, tokenize}; + use sorel_ir::*; use std::collections::{HashSet, HashMap}; use std::path::PathBuf; use std::rc::Rc; +use std::cell::RefCell; use std::include_str; -use anyhow::{Result, bail}; +use anyhow::{Result, bail, anyhow}; macro_rules! push_num { ($num:ident) => { IR::StackPush(*$num as u64) }; ($num:ident, $num_typ:ty) => { IR::StackPush(*$num as $num_typ as u64) }; } +type WrappedIRModule = Rc>; + +#[derive(Debug, PartialEq, Clone)] +enum ModuleID { + SourceFile(PathBuf), + StdSpecifier(String) +} + +impl Default for ModuleID { + fn default() -> Self { + ModuleID::StdSpecifier(String::from("")) + } +} + +impl ToString for ModuleID { + fn to_string(&self) -> String { + match self { + ModuleID::SourceFile(f) => f.to_string_lossy().to_string(), + ModuleID::StdSpecifier(s) => s.clone() + } + } +} + #[derive(Debug, Default)] struct IRModule { data: Vec, text: Vec, - imports: Vec>, + imports: Vec, exports: Vec, externs: Vec, // TODO these next two should form an enum, not two options - source_file: Option, - std_specifier: Option, + module_id: ModuleID, number: usize, } @@ -34,6 +58,7 @@ impl IRModule { } let mut found: Option = None; for imported in &self.imports { + let imported = imported.borrow(); if imported.exports.contains(name) { found = Some(imported.number); // Don't break here, since the last one should win. @@ -53,12 +78,12 @@ impl IRModule { } #[derive(Default)] -struct ImportTree { +pub(crate) struct ImportTree { data: Vec, text: Vec, - all_modules: HashMap>, + all_modules: HashMap, all_exports: HashSet, - entrypoint: Rc, + entrypoint: WrappedIRModule, module_count: usize, collapse_seen: HashSet, } @@ -74,18 +99,14 @@ fn std_import(specifier: &str) -> Result<&str> { } impl ImportTree { - fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result> { - Ok(if specifier.starts_with("std:") { + fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result { + let (contents, module_id) = if specifier.starts_with("std:") { if self.all_modules.contains_key(specifier) { let module = self.all_modules.get(specifier).unwrap().clone(); return Ok(module); } let contents = std_import(specifier)?; - let parsed = &Module::parse(tokenize(&contents)?, is_entrypoint)?; - let module = self.generate_internal(None, Some(specifier.to_string()), parsed); - let module = Rc::new(module); - self.all_modules.insert(specifier.to_string(), module.clone()); - module + (contents.to_string(), ModuleID::StdSpecifier(specifier.to_string())) } else { let mut path = PathBuf::from(specifier); if path.is_relative() { @@ -99,56 +120,41 @@ impl ImportTree { return Ok(module); } - let contents = &std::fs::read_to_string(&path)?; - let tokens = tokenize(&contents)?; - let parsed = &Module::parse(tokens, is_entrypoint)?; - - let module = self.generate_internal(Some(path), None, parsed); - let module = Rc::new(module); - self.all_modules.insert(path_key, module.clone()); - if is_entrypoint { - self.entrypoint = module.clone(); - } - module - }) - + let contents = std::fs::read_to_string(&path)?; + (contents, ModuleID::SourceFile(path)) + }; + let tokens = tokenize(&contents)?; + let parsed = &Module::parse(tokens, is_entrypoint)?; + let module = self.generate_internal(module_id.clone(), parsed)?; + let module = Rc::new(RefCell::new(module)); + self.all_modules.insert(module_id.to_string(), module.clone()); + if is_entrypoint { + self.entrypoint = module.clone(); + } + Ok(module) } - fn generate_internal(&mut self, path: Option, std_specifier: Option, module: &Module) -> IRModule { + fn generate_internal(&mut self, module_id: ModuleID, module: &Module) -> Result { // Eventually these will end up being sections in assembly let mut text = vec![]; let mut data = vec![]; let mut imports = vec![]; - if let Some(ref path) = path { - module.imports.iter().for_each(|imported| { - if let Some(parent_path) = path.parent() { - match self.import(&parent_path.to_path_buf(), imported, false) { - Ok(module) => { - imports.push(module); - }, - Err(msg) => { - eprintln!("{}", msg); - } - } - } else { - } - }); - } else { - // We're in a stdlib module, which can only import other stdlib - // modules. - module.imports.iter().for_each(|imported| { - match self.import(&PathBuf::new(), imported, false) { - Ok(module) => { - imports.push(module); - }, - Err(msg) => { - eprintln!("{}", msg); - } - } - }); - } - + + let parent_path = match module_id { + ModuleID::SourceFile(ref path) => { + path.parent().ok_or(anyhow!("no parent for path: {:?}", path))?.to_path_buf() + }, + // A stdlib module can only import other stdlib + // modules, so no need for parent path. + ModuleID::StdSpecifier(_) => PathBuf::new(), + }; + module.imports.iter().try_for_each(|imported| -> Result<()> { + let new_module = self.import(&parent_path, imported, false)?; + imports.push(new_module); + Ok(()) + })?; + let exports: Vec<_> = module.exports.iter().map(|s| { self.all_exports.insert(s.to_string()); s.to_string() @@ -237,34 +243,28 @@ impl ImportTree { let number = self.module_count; self.module_count += 1; - IRModule { + Ok(IRModule { text: text.into_iter().flatten().collect::>(), data, imports, exports, externs, - source_file: path, - std_specifier, + module_id, number, - } + }) } - fn collapse(&mut self, module: Rc) -> Result<()> { - let seen_key = if let Some(source_file) = &module.source_file { - source_file.to_string_lossy().to_string() - } else { - module.std_specifier.clone().unwrap() - }; + fn collapse(&mut self, module: WrappedIRModule, is_entrypoint: bool) -> Result<()> { + let module = module.borrow_mut(); + let seen_key = module.module_id.to_string(); if self.collapse_seen.contains(&seen_key) { return Ok(()) } for imported in module.imports.clone() { - self.collapse(imported)?; + self.collapse(imported, false)?; } - let is_entrypoint = module.source_file == self.entrypoint.source_file; - let module_number = module.number; for string in &module.data { @@ -310,7 +310,7 @@ pub fn compile(path: &str) -> Result { let dir = std::env::current_dir()?; let mut tree: ImportTree = Default::default(); let module = tree.import(&dir, path, true)?; - tree.collapse(module)?; + tree.collapse(module, true)?; // TODO remove unused words Ok(IRObject { data: tree.data,