diff --git a/bin/build_main.rs b/bin/build_main.rs index 8dc135b..5d046ff 100644 --- a/bin/build_main.rs +++ b/bin/build_main.rs @@ -14,8 +14,11 @@ fn generate_rust_module() -> String { // We only include files that are not test files. if path.is_file() && !path.ends_with("_test.ucg") { let path_str = path.to_string_lossy(); - let include = format!("\tstdlib.insert(\n\t\t\"{}\".to_string(),\n\t\tinclude_str!(\"../../{}\"));\n", path_str, path_str); - rust_lib.push_str(&include); + let include = format!( + "\tstdlib.insert(\n\t\t\"{}\".to_string(),\n\t\tinclude_str!(\"../../{}\"));\n", + path_str, path_str + ); + rust_lib.push_str(&include); } } rust_lib.push_str("\tstdlib\n"); @@ -27,4 +30,4 @@ fn generate_rust_module() -> String { fn main() { let contents = generate_rust_module(); std::fs::write("src/build/stdlib.rs", contents.as_bytes()).unwrap(); -} \ No newline at end of file +} diff --git a/src/build/mod.rs b/src/build/mod.rs index dc3e181..e572ba9 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -104,6 +104,7 @@ pub struct AssertCollector { /// Builder handles building ucg code for a single file. pub struct FileBuilder<'a> { file: PathBuf, + std: Rc>, import_path: &'a Vec, validate_mode: bool, pub assert_collector: AssertCollector, @@ -165,9 +166,11 @@ impl<'a> FileBuilder<'a> { scope: Scope, ) -> Self { let file = file.into(); + let std = Rc::new(stdlib::get_libs()); FileBuilder { // Our import stack is initialized with ourself. file: file, + std: std, import_path: import_paths, validate_mode: false, assert_collector: AssertCollector { @@ -189,6 +192,7 @@ impl<'a> FileBuilder<'a> { pub fn clone_builder>(&self, file: P) -> Self { FileBuilder { file: file.into(), + std: self.std.clone(), import_path: self.import_path, validate_mode: false, assert_collector: AssertCollector { @@ -378,6 +382,35 @@ impl<'a> FileBuilder<'a> { } fn eval_import(&self, def: &ImportDef) -> Result, Box> { + // Look for a std file first. + if def.path.fragment.starts_with("std/") { + eprintln!("Processing std lib path: {}", def.path.fragment); + if self.std.contains_key(&def.path.fragment) { + // Okay then this is a stdlib and it's special. + // Introduce a scope so the above borrow is dropped before we modify + // the cache below. + // Only parse the file once on import. + let path = PathBuf::from(&def.path.fragment); + let maybe_asset = self.assets.borrow().get(&path)?; + let result = match maybe_asset { + Some(v) => v.clone(), + None => { + let mut b = self.clone_builder(&def.path.fragment); + b.eval_string(self.std.get(&def.path.fragment).unwrap())?; + b.get_outputs_as_val() + } + }; + let mut mut_assets_cache = self.assets.borrow_mut(); + mut_assets_cache.stash(path, result.clone())?; + return Ok(result); + } else { + return Err(Box::new(error::BuildError::new( + format!("No such import {} in the std library.", def.path.fragment), + error::ErrorType::Unsupported, + def.pos.clone(), + ))); + } + } // Try a relative path first. let normalized = self.find_file(&def.path.fragment, true)?; if self.detect_import_cycle(normalized.to_string_lossy().as_ref()) { diff --git a/std/tests/lists_test.ucg b/std/tests/lists_test.ucg index 382f3cb..1d227a7 100644 --- a/std/tests/lists_test.ucg +++ b/std/tests/lists_test.ucg @@ -1,5 +1,5 @@ -let list = import "../lists.ucg"; -let t = import "../testing.ucg"; +let list = import "std/lists.ucg"; +let t = import "std/testing.ucg"; let list_to_join = [1, 2, 3]; diff --git a/std/tests/testing_test.ucg b/std/tests/testing_test.ucg index 73f78ea..fd02fd1 100644 --- a/std/tests/testing_test.ucg +++ b/std/tests/testing_test.ucg @@ -1,4 +1,4 @@ -let t = import "../testing.ucg"; +let t = import "std/testing.ucg"; let asserts = t.asserts{}; diff --git a/std/tests/tuples_test.ucg b/std/tests/tuples_test.ucg index df45a30..db7b3f3 100644 --- a/std/tests/tuples_test.ucg +++ b/std/tests/tuples_test.ucg @@ -1,5 +1,5 @@ -let tpl = import "../tuples.ucg"; -let t = (import "../testing.ucg").asserts{}; +let tpl = import "std/tuples.ucg"; +let t = (import "std/testing.ucg").asserts{}; assert t.equal{ left = tpl.fields{tpl={foo=1, bar=2}}.result,