From f2f02817ea599265b8fb9d5b6dc92ccc4a63cb46 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 3 Dec 2019 17:46:12 -0500 Subject: [PATCH 1/3] Load builtins --- builtins/Defaults.roc | 3 +++ builtins/Map.roc | 5 ++++ builtins/Set.roc | 7 ++++++ src/load/mod.rs | 53 +++++++++++++++++++++++++++---------------- 4 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 builtins/Defaults.roc create mode 100644 builtins/Map.roc create mode 100644 builtins/Set.roc diff --git a/builtins/Defaults.roc b/builtins/Defaults.roc new file mode 100644 index 0000000000..a05c8f74ee --- /dev/null +++ b/builtins/Defaults.roc @@ -0,0 +1,3 @@ +interface Defaults + exposes [] + imports [ Map.{ Map }, Set.{ Set } ] diff --git a/builtins/Map.roc b/builtins/Map.roc new file mode 100644 index 0000000000..fa8e3afe2e --- /dev/null +++ b/builtins/Map.roc @@ -0,0 +1,5 @@ +interface Map + exposes [ isEmpty ] + imports [] + +isEmpty = 0 diff --git a/builtins/Set.roc b/builtins/Set.roc new file mode 100644 index 0000000000..3422d82ae2 --- /dev/null +++ b/builtins/Set.roc @@ -0,0 +1,7 @@ +interface Set + exposes [ isEmpty ] + imports [] + +## Check + +# isEmpty : List * -> Bool diff --git a/src/load/mod.rs b/src/load/mod.rs index d842173d3a..dac5d45a82 100644 --- a/src/load/mod.rs +++ b/src/load/mod.rs @@ -23,7 +23,6 @@ use tokio::sync::mpsc::{self, Receiver, Sender}; pub struct Loaded { pub requested_module: LoadedModule, pub vars_created: usize, - pub deps: Deps, } #[derive(Debug, Clone)] @@ -36,13 +35,23 @@ pub enum BuildProblem<'a> { FileNotFound(&'a Path), } -type Deps = SendSet>; +type LoadedDeps = Vec; +type DepNames = SendSet>; -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum LoadedModule { Valid(Module), - FileProblem(io::ErrorKind), - ParsingFailed(Fail), + FileProblem { filename: PathBuf, error: io::ErrorKind }, + ParsingFailed { filename: PathBuf, fail: Fail }, +} + +impl LoadedModule { + pub fn into_module(self) -> Option { + match self { + LoadedModule::Valid(module) => Some(module), + _ => None + } + } } /// The loading process works like this, starting from the given filename (e.g. "main.roc"): @@ -54,21 +63,26 @@ pub enum LoadedModule { /// 4. Add everything we were able to import unqualified to the module's default scope. /// 5. Parse the module's defs. /// 6. Canonicalize the module. -pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded { +/// +/// The loaded_modules argument specifies which modules have already been loaded. +/// It typically contains the standard modules, but is empty when loading the +/// standard modules themselves. +pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf, loaded_deps: &mut LoadedDeps) -> Loaded { let env = Env { src_dir: src_dir.clone(), }; - let (tx, mut rx): (Sender, Receiver) = mpsc::channel(1024); + let (tx, mut rx): (Sender, Receiver) = mpsc::channel(1024); let arc_var_store = Arc::new(VarStore::new()); let main_tx = tx.clone(); let var_store = Arc::clone(&arc_var_store); let handle = - tokio::spawn(async move { load_filename(&env, &filename, main_tx, &var_store).await }); + tokio::spawn(async move { + load_filename(&env, filename, main_tx, &var_store).await + }); - let requested_module = handle.await.expect("Unable to load requested module."); - let mut other_modules = Vec::new(); - let mut all_deps = SendSet::default(); + let requested_module = handle.await.unwrap_or_else(|err| panic!("Unable to load requested module: {:?}", err)); + let mut all_deps: SendSet> = SendSet::default(); // Get a fresh env, since the previous one has been consumed let env = Env { src_dir }; @@ -95,7 +109,7 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded { .await; for module in loaded_modules { - other_modules.push(module.expect("Unable to load dependent module")); + loaded_deps.push(module.expect("Unable to load dependent module")); } // Once we've run out of pending modules to process, we're done! @@ -110,7 +124,6 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded { Loaded { requested_module, - deps: all_deps, vars_created, } } @@ -118,7 +131,7 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded { async fn load_module( env: &Env, module_name: Box, - tx: Sender, + tx: Sender, var_store: &VarStore, ) -> LoadedModule { let mut filename = PathBuf::new(); @@ -133,16 +146,16 @@ async fn load_module( // End with .roc filename.set_extension("roc"); - load_filename(env, &filename, tx, var_store).await + load_filename(env, filename, tx, var_store).await } async fn load_filename( env: &Env, - filename: &Path, - tx: Sender, + filename: PathBuf, + tx: Sender, var_store: &VarStore, ) -> LoadedModule { - match read_to_string(filename).await { + match read_to_string(&filename).await { Ok(src) => { let arena = Bump::new(); // TODO instead of env.arena.alloc(src), we should create a new buffer @@ -231,12 +244,12 @@ async fn load_filename( LoadedModule::Valid(module) } - Err((fail, _)) => LoadedModule::ParsingFailed(fail), + Err((fail, _)) => LoadedModule::ParsingFailed{ filename, fail }, }; answer } - Err(err) => LoadedModule::FileProblem(err.kind()), + Err(err) => LoadedModule::FileProblem { filename, error: err.kind()}, } } From 2387862d87c417c577e080e0f395e1830387d60c Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 3 Dec 2019 17:46:33 -0500 Subject: [PATCH 2/3] Test loading with builtins --- tests/helpers/mod.rs | 5 +++ tests/test_load.rs | 102 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index bacc722977..a58a82e42b 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -191,3 +191,8 @@ where pub fn fixtures_dir<'a>() -> PathBuf { Path::new("tests").join("fixtures").join("build") } + +#[allow(dead_code)] +pub fn builtins_dir<'a>() -> PathBuf { + PathBuf::new().join("builtins") +} diff --git a/tests/test_load.rs b/tests/test_load.rs index 0014aeb0ef..b18ae9733d 100644 --- a/tests/test_load.rs +++ b/tests/test_load.rs @@ -11,8 +11,9 @@ mod helpers; #[cfg(test)] mod test_load { - use crate::helpers::{fixtures_dir, send_set_from}; - use roc::load::{load, LoadedModule}; + use crate::helpers::{fixtures_dir, builtins_dir}; + use roc::load::{load, Loaded, LoadedModule}; + use roc::can::module::Module; fn test_async(future: F) -> F::Output { use tokio::runtime::Runtime; @@ -24,33 +25,96 @@ mod test_load { rt.block_on(future) } + fn expect_module(loaded: Loaded) -> Module { + match loaded.requested_module { + LoadedModule::Valid(module) => module, + LoadedModule::FileProblem{ filename, error } => panic!( + "{:?} failed to load with FileProblem: {:?}", + filename, error + ), + LoadedModule::ParsingFailed{ filename, fail } => panic!( + "{:?} failed to load with ParsingFailed: {:?}", + filename, fail + ), + } + } + + async fn load_builtins(deps: &mut Vec) { + let src_dir = builtins_dir(); + let filename = src_dir.join("Defaults.roc"); + + load(src_dir, filename, deps).await; + } + #[test] fn interface_with_deps() { + let mut deps = Vec::new(); let src_dir = fixtures_dir().join("interface_with_deps"); let filename = src_dir.join("Primary.roc"); test_async(async { - let loaded = load(src_dir, filename).await; - - let module = match loaded.requested_module { - LoadedModule::Valid(module) => module, - LoadedModule::FileProblem(err) => panic!( - "requested_module failed to load with FileProblem: {:?}", - err - ), - LoadedModule::ParsingFailed(fail) => panic!( - "requested_module failed to load with ParsingFailed: {:?}", - fail - ), - }; + let module = expect_module(load(src_dir, filename, &mut deps).await); assert_eq!(module.name, Some("Primary".into())); assert_eq!(module.defs.len(), 6); - assert_eq!( - loaded.deps, - send_set_from(vec!["Dep1".into(), "Dep2".into(), "Dep3.Blah".into()]) - ); + let module_names: Vec>> = + deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + + assert_eq!(module_names, vec![ + Some("Dep1".into()), + Some("Dep3.Blah".into()), + Some("Dep2".into()) + ]); + }); + } + + #[test] + fn builtins() { + let mut deps = Vec::new(); + let src_dir = builtins_dir(); + let filename = src_dir.join("Defaults.roc"); + + test_async(async { + let module = expect_module(load(src_dir, filename, &mut deps).await); + + assert_eq!(module.name, Some("Defaults".into())); + assert_eq!(module.defs.len(), 0); + + let module_names: Vec>> = + deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + + assert_eq!(module_names, vec![ + Some("Map".into()), + Some("Set".into()), + ]); + }); + } + + #[test] + fn interface_with_builtins() { + let mut deps = Vec::new(); + + test_async(async { + load_builtins(&mut deps).await; + + let src_dir = fixtures_dir().join("interface_with_deps"); + let filename = src_dir.join("Primary.roc"); + let module = expect_module(load(src_dir, filename, &mut deps).await); + + assert_eq!(module.name, Some("Primary".into())); + assert_eq!(module.defs.len(), 6); + + let module_names: Vec>> = + deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + + assert_eq!(module_names, vec![ + Some("Map".into()), + Some("Set".into()), + Some("Dep1".into()), + Some("Dep3.Blah".into()), + Some("Dep2".into()) + ]); }); } } From b5a10eee20d0f5baac3767938f6d0f4e52ae9483 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 3 Dec 2019 19:55:46 -0500 Subject: [PATCH 3/3] cargo fmt --- src/load/mod.rs | 27 +++++++++++++------- tests/test_load.rs | 61 ++++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/load/mod.rs b/src/load/mod.rs index dac5d45a82..df1f02ae22 100644 --- a/src/load/mod.rs +++ b/src/load/mod.rs @@ -41,15 +41,21 @@ type DepNames = SendSet>; #[derive(Clone, Debug, PartialEq)] pub enum LoadedModule { Valid(Module), - FileProblem { filename: PathBuf, error: io::ErrorKind }, - ParsingFailed { filename: PathBuf, fail: Fail }, + FileProblem { + filename: PathBuf, + error: io::ErrorKind, + }, + ParsingFailed { + filename: PathBuf, + fail: Fail, + }, } impl LoadedModule { pub fn into_module(self) -> Option { match self { LoadedModule::Valid(module) => Some(module), - _ => None + _ => None, } } } @@ -77,11 +83,11 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf, loaded_deps: &mut Loa let main_tx = tx.clone(); let var_store = Arc::clone(&arc_var_store); let handle = - tokio::spawn(async move { - load_filename(&env, filename, main_tx, &var_store).await - }); + tokio::spawn(async move { load_filename(&env, filename, main_tx, &var_store).await }); - let requested_module = handle.await.unwrap_or_else(|err| panic!("Unable to load requested module: {:?}", err)); + let requested_module = handle + .await + .unwrap_or_else(|err| panic!("Unable to load requested module: {:?}", err)); let mut all_deps: SendSet> = SendSet::default(); // Get a fresh env, since the previous one has been consumed @@ -244,12 +250,15 @@ async fn load_filename( LoadedModule::Valid(module) } - Err((fail, _)) => LoadedModule::ParsingFailed{ filename, fail }, + Err((fail, _)) => LoadedModule::ParsingFailed { filename, fail }, }; answer } - Err(err) => LoadedModule::FileProblem { filename, error: err.kind()}, + Err(err) => LoadedModule::FileProblem { + filename, + error: err.kind(), + }, } } diff --git a/tests/test_load.rs b/tests/test_load.rs index b18ae9733d..f3a514387b 100644 --- a/tests/test_load.rs +++ b/tests/test_load.rs @@ -11,9 +11,9 @@ mod helpers; #[cfg(test)] mod test_load { - use crate::helpers::{fixtures_dir, builtins_dir}; - use roc::load::{load, Loaded, LoadedModule}; + use crate::helpers::{builtins_dir, fixtures_dir}; use roc::can::module::Module; + use roc::load::{load, Loaded, LoadedModule}; fn test_async(future: F) -> F::Output { use tokio::runtime::Runtime; @@ -28,11 +28,11 @@ mod test_load { fn expect_module(loaded: Loaded) -> Module { match loaded.requested_module { LoadedModule::Valid(module) => module, - LoadedModule::FileProblem{ filename, error } => panic!( + LoadedModule::FileProblem { filename, error } => panic!( "{:?} failed to load with FileProblem: {:?}", filename, error ), - LoadedModule::ParsingFailed{ filename, fail } => panic!( + LoadedModule::ParsingFailed { filename, fail } => panic!( "{:?} failed to load with ParsingFailed: {:?}", filename, fail ), @@ -58,14 +58,19 @@ mod test_load { assert_eq!(module.name, Some("Primary".into())); assert_eq!(module.defs.len(), 6); - let module_names: Vec>> = - deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + let module_names: Vec>> = deps + .into_iter() + .map(|dep| dep.into_module().unwrap().name) + .collect(); - assert_eq!(module_names, vec![ - Some("Dep1".into()), - Some("Dep3.Blah".into()), - Some("Dep2".into()) - ]); + assert_eq!( + module_names, + vec![ + Some("Dep1".into()), + Some("Dep3.Blah".into()), + Some("Dep2".into()) + ] + ); }); } @@ -81,13 +86,12 @@ mod test_load { assert_eq!(module.name, Some("Defaults".into())); assert_eq!(module.defs.len(), 0); - let module_names: Vec>> = - deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + let module_names: Vec>> = deps + .into_iter() + .map(|dep| dep.into_module().unwrap().name) + .collect(); - assert_eq!(module_names, vec![ - Some("Map".into()), - Some("Set".into()), - ]); + assert_eq!(module_names, vec![Some("Map".into()), Some("Set".into()),]); }); } @@ -105,16 +109,21 @@ mod test_load { assert_eq!(module.name, Some("Primary".into())); assert_eq!(module.defs.len(), 6); - let module_names: Vec>> = - deps.into_iter().map(|dep| dep.into_module().unwrap().name).collect(); + let module_names: Vec>> = deps + .into_iter() + .map(|dep| dep.into_module().unwrap().name) + .collect(); - assert_eq!(module_names, vec![ - Some("Map".into()), - Some("Set".into()), - Some("Dep1".into()), - Some("Dep3.Blah".into()), - Some("Dep2".into()) - ]); + assert_eq!( + module_names, + vec![ + Some("Map".into()), + Some("Set".into()), + Some("Dep1".into()), + Some("Dep3.Blah".into()), + Some("Dep2".into()) + ] + ); }); } }