From: Bryan English Date: Sat, 3 Jan 2026 04:16:24 +0000 (-0500) Subject: implement import in hylo compiler X-Git-Url: https://rethought.computer/gitweb//gitweb//git?a=commitdiff_plain;h=8927db4f8a319c21688cde162791c5d5195ce886;p=sorel-lang.git implement import in hylo compiler --- diff --git a/hylo-lang/README.md b/hylo-lang/README.md index f971508..0f13d52 100644 --- a/hylo-lang/README.md +++ b/hylo-lang/README.md @@ -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 diff --git a/hylo-lang/hylo-ir/src/lib.rs b/hylo-lang/hylo-ir/src/lib.rs index be8608a..9d3e4db 100644 --- a/hylo-lang/hylo-ir/src/lib.rs +++ b/hylo-lang/hylo-ir/src/lib.rs @@ -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 diff --git a/hylo-lang/hyloc/src/ir.rs b/hylo-lang/hyloc/src/ir.rs index fa1a895..e3d23e7 100644 --- a/hylo-lang/hyloc/src/ir.rs +++ b/hylo-lang/hyloc/src/ir.rs @@ -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) -> Option { + // 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::>(); + 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, + imports: Option> +} + +fn generate_internal(module: &Module, imported: &mut HashSet) -> 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::>(); let mut result = vec![IR::Label(def.name.to_string())]; @@ -60,8 +133,11 @@ pub fn generate(module: &Module) -> IRModule { }).flatten().collect::>()); - IRModule { - text: text.into_iter().flatten().collect::>(), - data + ModuleWithImports { + module: Some(IRModule { + text: text.into_iter().flatten().collect::>(), + data, + }), + imports: Some(Vec::new()) // TODO } } diff --git a/hylo-lang/hyloc/src/main.rs b/hylo-lang/hyloc/src/main.rs index 518e198..aebd197 100644 --- a/hylo-lang/hyloc/src/main.rs +++ b/hylo-lang/hyloc/src/main.rs @@ -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(); } diff --git a/hylo-lang/hyloc/src/parser.rs b/hylo-lang/hyloc/src/parser.rs index 43d2ca1..e678e14 100644 --- a/hylo-lang/hyloc/src/parser.rs +++ b/hylo-lang/hyloc/src/parser.rs @@ -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);