diff --git a/src/builder/mod.rs b/src/builder/mod.rs index 53f75d5..1bbe577 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -37,16 +37,23 @@ impl Builder { } } + fn get_base_path(&self) -> Result { + Ok(self + .in_file + .parent() + .expect("Directory has no root") + .to_path_buf()) + } + pub fn build(&mut self) -> Result<(), String> { let in_file = self.in_file.clone(); // Resolve path deltas between working directory and entrypoint - if let Some(base_directory) = self.in_file.clone().parent() { - if let Ok(resolved_delta) = in_file.strip_prefix(base_directory) { - // TODO: This error could probably be handled better - let _ = env::set_current_dir(base_directory); - self.in_file = resolved_delta.to_path_buf(); - } - }; + let base_directory = self.get_base_path()?; + if let Ok(resolved_delta) = in_file.strip_prefix(&base_directory) { + // TODO: This error could probably be handled better + let _ = env::set_current_dir(base_directory); + self.in_file = resolved_delta.to_path_buf(); + } self.build_module(self.in_file.clone())?; // Append standard library @@ -55,16 +62,33 @@ impl Builder { } fn build_module(&mut self, file_path: PathBuf) -> Result { - let mut file = File::open(&file_path) - .map_err(|_| format!("Could not open file: {}", file_path.display()))?; + // TODO: This method can probably cleaned up quite a bit + + // In case the module is a directory, we have to append the filename of the entrypoint + let resolved_file_path = if file_path.is_dir() { + file_path.join("module.sb") + } else { + file_path + }; + let mut file = File::open(&resolved_file_path) + .map_err(|_| format!("Could not open file: {}", resolved_file_path.display()))?; let mut contents = String::new(); file.read_to_string(&mut contents) .expect("Could not read file"); let tokens = lexer::tokenize(&contents); - let module = parser::parse(tokens, Some(contents), file_path.display().to_string())?; + let module = parser::parse( + tokens, + Some(contents), + resolved_file_path.display().to_string(), + )?; for import in &module.imports { - self.build_module(PathBuf::from(import))?; + // Build module relative to the current file + let import_path = resolved_file_path + .parent() + .unwrap() + .join(PathBuf::from(import)); + self.build_module(import_path)?; } self.modules.push(module.clone()); Ok(module) diff --git a/src/tests/test_examples.rs b/src/tests/test_examples.rs index ee33056..c4ebdba 100644 --- a/src/tests/test_examples.rs +++ b/src/tests/test_examples.rs @@ -36,6 +36,11 @@ fn test_directory(dir_in: &str) -> Result<(), Error> { for ex in examples { let example = ex?; let in_file = dir.join(dir_in).join(example.file_name()); + + // We don't want to build submodules, since they don't run without a main function + if in_file.is_dir() { + continue; + } let out_file = dir.join(&dir_out).join( example .file_name() diff --git a/tests/importable_module/foo/bar.sb b/tests/importable_module/foo/bar.sb new file mode 100644 index 0000000..8dc7af5 --- /dev/null +++ b/tests/importable_module/foo/bar.sb @@ -0,0 +1,4 @@ + +fn nested_module() { + println("A deeply nested function was called!") +} \ No newline at end of file diff --git a/tests/importable_module/module.sb b/tests/importable_module/module.sb new file mode 100644 index 0000000..5ab00a6 --- /dev/null +++ b/tests/importable_module/module.sb @@ -0,0 +1,6 @@ +import "foo/bar" + +fn external_function() { + println("I was called!!") + nested_module() +} \ No newline at end of file diff --git a/tests/imports.sb b/tests/imports.sb new file mode 100644 index 0000000..b9a8fd0 --- /dev/null +++ b/tests/imports.sb @@ -0,0 +1,5 @@ +import "importable_module/module" + +fn main() { + external_function() +} \ No newline at end of file