Browse Source

feat: resolve nested modules

modules
Garrit Franke 3 years ago
parent
commit
ee598e06de
  1. 46
      src/builder/mod.rs
  2. 5
      src/tests/test_examples.rs
  3. 4
      tests/importable_module/foo/bar.sb
  4. 6
      tests/importable_module/module.sb
  5. 5
      tests/imports.sb

46
src/builder/mod.rs

@ -37,16 +37,23 @@ impl Builder {
}
}
fn get_base_path(&self) -> Result<PathBuf, String> {
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<Module, String> {
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)

5
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()

4
tests/importable_module/foo/bar.sb

@ -0,0 +1,4 @@
fn nested_module() {
println("A deeply nested function was called!")
}

6
tests/importable_module/module.sb

@ -0,0 +1,6 @@
import "foo/bar"
fn external_function() {
println("I was called!!")
nested_module()
}

5
tests/imports.sb

@ -0,0 +1,5 @@
import "importable_module/module"
fn main() {
external_function()
}
Loading…
Cancel
Save