FEATURE: Special case the std/ import prefix.

It's a reserved import path for our std library.

closes #27
This commit is contained in:
Jeremy Wall 2019-01-13 20:33:38 -06:00
parent 50a3d33208
commit 547c271aa1
5 changed files with 44 additions and 8 deletions

View File

@ -14,8 +14,11 @@ fn generate_rust_module() -> String {
// We only include files that are not test files. // We only include files that are not test files.
if path.is_file() && !path.ends_with("_test.ucg") { if path.is_file() && !path.ends_with("_test.ucg") {
let path_str = path.to_string_lossy(); 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); let include = format!(
rust_lib.push_str(&include); "\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"); rust_lib.push_str("\tstdlib\n");
@ -27,4 +30,4 @@ fn generate_rust_module() -> String {
fn main() { fn main() {
let contents = generate_rust_module(); let contents = generate_rust_module();
std::fs::write("src/build/stdlib.rs", contents.as_bytes()).unwrap(); std::fs::write("src/build/stdlib.rs", contents.as_bytes()).unwrap();
} }

View File

@ -104,6 +104,7 @@ pub struct AssertCollector {
/// Builder handles building ucg code for a single file. /// Builder handles building ucg code for a single file.
pub struct FileBuilder<'a> { pub struct FileBuilder<'a> {
file: PathBuf, file: PathBuf,
std: Rc<HashMap<String, &'static str>>,
import_path: &'a Vec<PathBuf>, import_path: &'a Vec<PathBuf>,
validate_mode: bool, validate_mode: bool,
pub assert_collector: AssertCollector, pub assert_collector: AssertCollector,
@ -165,9 +166,11 @@ impl<'a> FileBuilder<'a> {
scope: Scope, scope: Scope,
) -> Self { ) -> Self {
let file = file.into(); let file = file.into();
let std = Rc::new(stdlib::get_libs());
FileBuilder { FileBuilder {
// Our import stack is initialized with ourself. // Our import stack is initialized with ourself.
file: file, file: file,
std: std,
import_path: import_paths, import_path: import_paths,
validate_mode: false, validate_mode: false,
assert_collector: AssertCollector { assert_collector: AssertCollector {
@ -189,6 +192,7 @@ impl<'a> FileBuilder<'a> {
pub fn clone_builder<P: Into<PathBuf>>(&self, file: P) -> Self { pub fn clone_builder<P: Into<PathBuf>>(&self, file: P) -> Self {
FileBuilder { FileBuilder {
file: file.into(), file: file.into(),
std: self.std.clone(),
import_path: self.import_path, import_path: self.import_path,
validate_mode: false, validate_mode: false,
assert_collector: AssertCollector { assert_collector: AssertCollector {
@ -378,6 +382,35 @@ impl<'a> FileBuilder<'a> {
} }
fn eval_import(&self, def: &ImportDef) -> Result<Rc<Val>, Box<dyn Error>> { fn eval_import(&self, def: &ImportDef) -> Result<Rc<Val>, Box<dyn Error>> {
// 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. // Try a relative path first.
let normalized = self.find_file(&def.path.fragment, true)?; let normalized = self.find_file(&def.path.fragment, true)?;
if self.detect_import_cycle(normalized.to_string_lossy().as_ref()) { if self.detect_import_cycle(normalized.to_string_lossy().as_ref()) {

View File

@ -1,5 +1,5 @@
let list = import "../lists.ucg"; let list = import "std/lists.ucg";
let t = import "../testing.ucg"; let t = import "std/testing.ucg";
let list_to_join = [1, 2, 3]; let list_to_join = [1, 2, 3];

View File

@ -1,4 +1,4 @@
let t = import "../testing.ucg"; let t = import "std/testing.ucg";
let asserts = t.asserts{}; let asserts = t.asserts{};

View File

@ -1,5 +1,5 @@
let tpl = import "../tuples.ucg"; let tpl = import "std/tuples.ucg";
let t = (import "../testing.ucg").asserts{}; let t = (import "std/testing.ucg").asserts{};
assert t.equal{ assert t.equal{
left = tpl.fields{tpl={foo=1, bar=2}}.result, left = tpl.fields{tpl={foo=1, bar=2}}.result,