]> rethought.computer Git - sorel-lang.git/commitdiff
some cleanup of ir.rs
authorBryan English <bryan@rethought.computer>
Sat, 14 Feb 2026 05:52:29 +0000 (00:52 -0500)
committerBryan English <bryan@rethought.computer>
Sat, 14 Feb 2026 05:52:48 +0000 (00:52 -0500)
sorelc/src/ir.rs

index 7b931c460c4898a7aef0d7c768be380fdb2e7839..88c2f47785418426a8fa727c89036824490b8a37 100644 (file)
@@ -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<RefCell<IRModule>>;
+
+#[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<IR>,
     text: Vec<IR>,
-    imports: Vec<Rc<IRModule>>,
+    imports: Vec<WrappedIRModule>,
     exports: Vec<String>,
     externs: Vec<String>,
     // TODO these next two should form an enum, not two options
-    source_file: Option<PathBuf>,
-    std_specifier: Option<String>,
+    module_id: ModuleID,
     number: usize,
 }
 
@@ -34,6 +58,7 @@ impl IRModule {
         }
         let mut found: Option<usize> = 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<IR>,
     text: Vec<IR>,
-    all_modules: HashMap<String, Rc<IRModule>>,
+    all_modules: HashMap<String, WrappedIRModule>,
     all_exports: HashSet<String>,
-    entrypoint: Rc<IRModule>,
+    entrypoint: WrappedIRModule,
     module_count: usize,
     collapse_seen: HashSet<String>,
 }
@@ -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<Rc<IRModule>> {
-        Ok(if specifier.starts_with("std:") {
+    fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result<WrappedIRModule> {
+        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<PathBuf>, std_specifier: Option<String>, module: &Module) -> IRModule {
+    fn generate_internal(&mut self, module_id: ModuleID, module: &Module) -> Result<IRModule> {
         // 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::<Vec<_>>(),
             data,
             imports,
             exports,
             externs,
-            source_file: path,
-            std_specifier, 
+            module_id,
             number,
-        }
+        })
     }
 
-    fn collapse(&mut self, module: Rc<IRModule>) -> 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<IRObject> {
     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,