]> rethought.computer Git - sorel-lang.git/commitdiff
implement import in hylo compiler keep/8927db4f8a319c21688cde162791c5d5195ce886
authorBryan English <bryan@rethought.computer>
Sat, 3 Jan 2026 04:16:24 +0000 (23:16 -0500)
committerBryan English <bryan@rethought.computer>
Tue, 10 Feb 2026 04:08:54 +0000 (04:08 +0000)
hylo-lang/README.md
hylo-lang/hylo-ir/src/lib.rs
hylo-lang/hyloc/src/ir.rs
hylo-lang/hyloc/src/main.rs
hylo-lang/hyloc/src/parser.rs

index f9715089cd74b03ddf5d97c063b42fd1a0a60880..0f13d52652477b0a70db128f6a0ef5d87e46a26c 100644 (file)
@@ -1,3 +1,11 @@
 # hylo-lang
 
 The name means "it's high-level and low-level at the same time".
+
+
+## TODO
+
+* [x] Imports
+* [ ] Syscalls
+* [ ] Structs
+* [ ] many, many more things
index be8608a203202caac78e6ad7dab0dbdca51f9339..9d3e4dbc1cdec36b99f55a75357d3fa978941a4c 100644 (file)
@@ -10,6 +10,9 @@ pub enum IR {
     StackPushString(usize),
     StringDef(String),
 
+    Import, // Not actually used at runtime. Should be elided.
+    ImportString, // Not actually used at runtime. Should be elided.
+
     // These next ones should always be inlined, so they're in IR.
     Load, // @ ( addr -- x ) -- Fetch memory contents at addr
     Store, // ! ( x addr -- ) -- Store x at addr
index fa1a8951a1b75f52cee58327262d9f61d14fff77..e3d23e7c645369935516dd6618d899cac772c55d 100644 (file)
@@ -1,19 +1,79 @@
 use crate::parser::Module;
-use crate::tokenizer::Token;
+use crate::tokenizer::{Token, tokenize};
 use hylo_ir::*;
 
+use std::collections::HashSet;
+use std::path::PathBuf;
+
 macro_rules! push_num {
     ($num:ident) => { IR::StackPush(*$num as u64) }
 }
 
-pub fn generate(module: &Module) -> IRModule {
+fn import(specifier: &str, imported: &mut HashSet<PathBuf>) -> Option<ModuleWithImports> {
+    // TODO paths relative to the files, not just the invocation
+    let path = PathBuf::from(specifier).canonicalize().unwrap();    
+    if imported.contains(&path) {
+        return None;
+    }
+
+    let contents = std::fs::read_to_string(&path).unwrap();
+
+    Some(generate_internal(&Module::parse(tokenize(&contents)), imported))
+}
+
+fn collapse_module(mut module_w: ModuleWithImports) -> IRModule {
+    let mut module = module_w.module.take().unwrap();
+    let mut data = std::mem::take(&mut module.data);
+    let mut prev_data_len = data.len();
+    let mut text = std::mem::take(&mut module.text);
+
+    module_w.imports.take().unwrap().into_iter().for_each(|imported| {
+        let mut ir_mod = collapse_module(imported);
+        let mut mod_data = std::mem::take(&mut ir_mod.data);
+        let mod_data_len = mod_data.len();
+        data.append(&mut mod_data);
+
+        let mut mod_text = std::mem::take(&mut ir_mod.text).into_iter().map(|ir| {
+            if let IR::StackPushString(num) = ir {
+                IR::StackPushString(num + prev_data_len)
+            } else {
+                ir
+            }
+        }).collect::<Vec<_>>();
+        text.append(&mut mod_text);
+
+        prev_data_len += mod_data_len;
+    });
+
+    IRModule {
+        data,
+        text,
+    }
+}
+
+pub fn compile(path: &str) -> IRModule {
+    let mut imported = HashSet::new();
+    let module = import(path, &mut imported).unwrap();
+    collapse_module(module) // TODO remove unused words 
+}
+
+struct ModuleWithImports {
+    module: Option<IRModule>,
+    imports: Option<Vec<ModuleWithImports>>
+}
+
+fn generate_internal(module: &Module, imported: &mut HashSet<PathBuf>) -> ModuleWithImports {
     // Eventually these will end up being sections in assembly
     let mut text = vec![];
     let mut data = vec![];
 
+    let mut imports = vec![];
+    
+    let mut last_was_import = false;
+
     text.push(module.words.iter().map(|def| {
         let mut body = def.instructions.iter().map(|inst| {
-            match inst {
+            let mapped_ir = match inst {
                 Token::Word(word) => {
                     match *word {
                         "@" => IR::Load,
@@ -32,13 +92,21 @@ pub fn generate(module: &Module) -> IRModule {
                         "-" => IR::SubtractU64,
                         "*" => IR::MultiplyU64,
                         "/" => IR::DivideU64,
+                        "import" => IR::Import,
                         // TODO num type specfic math like `+:i32`, etc.
                         _ =>  IR::Call(String::from(*word))
                     }
                 },
                 Token::String(text) => {
-                    data.push(IR::StringDef(String::from(*text)));
-                    IR::StackPushString(data.len() - 1)
+                    if last_was_import {
+                        if let Some(module) = import(text, imported) {
+                            imports.push(module);
+                        }
+                        IR::ImportString // This will be elided later
+                    } else {
+                        data.push(IR::StringDef(String::from(*text)));
+                        IR::StackPushString(data.len() - 1)
+                    }
                 },
                 Token::NumU8(num) => push_num!(num),
                 Token::NumI8(num) => push_num!(num),
@@ -50,7 +118,12 @@ pub fn generate(module: &Module) -> IRModule {
                 Token::NumI64(num) => push_num!(num),
                 Token::NumF32(num) => push_num!(num),
                 Token::NumF64(num) => push_num!(num),
-            }
+            };
+            last_was_import = match mapped_ir {
+                IR::Import => true,
+                _ => false,
+            };
+            mapped_ir
         }).collect::<Vec<_>>();
 
         let mut result = vec![IR::Label(def.name.to_string())];
@@ -60,8 +133,11 @@ pub fn generate(module: &Module) -> IRModule {
     }).flatten().collect::<Vec<_>>());
 
     
-    IRModule {
-        text: text.into_iter().flatten().collect::<Vec<_>>(),
-        data
+    ModuleWithImports {
+        module: Some(IRModule {
+            text: text.into_iter().flatten().collect::<Vec<_>>(),
+            data,
+        }),
+        imports: Some(Vec::new()) // TODO
     }
 }
index 518e198e82f4079e1da2f9602ad01cf70397b64a..aebd1970ef1960223b2ed915f014ce7b171c9d3f 100644 (file)
@@ -2,17 +2,11 @@ mod tokenizer;
 mod parser;
 mod ir;
 
-use hylo_ir::IRModule;
 use hylo_interpret::Interpreter;
 
-fn compile(source: &str) -> IRModule {
-    ir::generate(&parser::Module::parse(tokenizer::tokenize(source)))
-}
-
 fn main() {
     let filename = std::env::args().nth(1).expect("must provide a file to compile");
-    let contents = std::fs::read_to_string(&filename).unwrap();
-    let module = compile(&contents);
+    let module = ir::compile(&filename);
     let mut interp = Interpreter::new(&module);
     interp.run();
 }
index 43d2ca1c8764938c617e1496c648ab61b471060f..e678e1462370b727d7e6473931295492270482f2 100644 (file)
@@ -63,6 +63,7 @@ impl<'a> Module<'a> {
         Module { words: result }
     }
 
+    #[cfg(test)]
     pub fn debug_print(&self) {
         for word in &self.words {
             println!("{}", word.name);