Merge branch 'trunk' into ct/typos-0

This commit is contained in:
Chadtech 2019-12-03 22:03:13 -05:00 committed by GitHub
commit 988a5401f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 152 additions and 37 deletions

3
builtins/Defaults.roc Normal file
View file

@ -0,0 +1,3 @@
interface Defaults
exposes []
imports [ Map.{ Map }, Set.{ Set } ]

5
builtins/Map.roc Normal file
View file

@ -0,0 +1,5 @@
interface Map
exposes [ isEmpty ]
imports []
isEmpty = 0

7
builtins/Set.roc Normal file
View file

@ -0,0 +1,7 @@
interface Set
exposes [ isEmpty ]
imports []
## Check
# isEmpty : List * -> Bool

View file

@ -23,7 +23,6 @@ use tokio::sync::mpsc::{self, Receiver, Sender};
pub struct Loaded { pub struct Loaded {
pub requested_module: LoadedModule, pub requested_module: LoadedModule,
pub vars_created: usize, pub vars_created: usize,
pub deps: Deps,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -36,13 +35,29 @@ pub enum BuildProblem<'a> {
FileNotFound(&'a Path), FileNotFound(&'a Path),
} }
type Deps = SendSet<Box<str>>; type LoadedDeps = Vec<LoadedModule>;
type DepNames = SendSet<Box<str>>;
#[derive(Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum LoadedModule { pub enum LoadedModule {
Valid(Module), Valid(Module),
FileProblem(io::ErrorKind), FileProblem {
ParsingFailed(Fail), filename: PathBuf,
error: io::ErrorKind,
},
ParsingFailed {
filename: PathBuf,
fail: Fail,
},
}
impl LoadedModule {
pub fn into_module(self) -> Option<Module> {
match self {
LoadedModule::Valid(module) => Some(module),
_ => None,
}
}
} }
/// The loading process works like this, starting from the given filename (e.g. "main.roc"): /// The loading process works like this, starting from the given filename (e.g. "main.roc"):
@ -54,21 +69,26 @@ pub enum LoadedModule {
/// 4. Add everything we were able to import unqualified to the module's default scope. /// 4. Add everything we were able to import unqualified to the module's default scope.
/// 5. Parse the module's defs. /// 5. Parse the module's defs.
/// 6. Canonicalize the module. /// 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 { let env = Env {
src_dir: src_dir.clone(), src_dir: src_dir.clone(),
}; };
let (tx, mut rx): (Sender<Deps>, Receiver<Deps>) = mpsc::channel(1024); let (tx, mut rx): (Sender<DepNames>, Receiver<DepNames>) = mpsc::channel(1024);
let arc_var_store = Arc::new(VarStore::new()); let arc_var_store = Arc::new(VarStore::new());
let main_tx = tx.clone(); let main_tx = tx.clone();
let var_store = Arc::clone(&arc_var_store); let var_store = Arc::clone(&arc_var_store);
let handle = 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 requested_module = handle
let mut other_modules = Vec::new(); .await
let mut all_deps = SendSet::default(); .unwrap_or_else(|err| panic!("Unable to load requested module: {:?}", err));
let mut all_deps: SendSet<Box<str>> = SendSet::default();
// Get a fresh env, since the previous one has been consumed // Get a fresh env, since the previous one has been consumed
let env = Env { src_dir }; let env = Env { src_dir };
@ -95,7 +115,7 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded {
.await; .await;
for module in loaded_modules { 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! // Once we've run out of pending modules to process, we're done!
@ -110,7 +130,6 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded {
Loaded { Loaded {
requested_module, requested_module,
deps: all_deps,
vars_created, vars_created,
} }
} }
@ -118,7 +137,7 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded {
async fn load_module( async fn load_module(
env: &Env, env: &Env,
module_name: Box<str>, module_name: Box<str>,
tx: Sender<Deps>, tx: Sender<DepNames>,
var_store: &VarStore, var_store: &VarStore,
) -> LoadedModule { ) -> LoadedModule {
let mut filename = PathBuf::new(); let mut filename = PathBuf::new();
@ -133,16 +152,16 @@ async fn load_module(
// End with .roc // End with .roc
filename.set_extension("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( async fn load_filename(
env: &Env, env: &Env,
filename: &Path, filename: PathBuf,
tx: Sender<Deps>, tx: Sender<DepNames>,
var_store: &VarStore, var_store: &VarStore,
) -> LoadedModule { ) -> LoadedModule {
match read_to_string(filename).await { match read_to_string(&filename).await {
Ok(src) => { Ok(src) => {
let arena = Bump::new(); let arena = Bump::new();
// TODO instead of env.arena.alloc(src), we should create a new buffer // TODO instead of env.arena.alloc(src), we should create a new buffer
@ -231,12 +250,15 @@ async fn load_filename(
LoadedModule::Valid(module) LoadedModule::Valid(module)
} }
Err((fail, _)) => LoadedModule::ParsingFailed(fail), Err((fail, _)) => LoadedModule::ParsingFailed { filename, fail },
}; };
answer answer
} }
Err(err) => LoadedModule::FileProblem(err.kind()), Err(err) => LoadedModule::FileProblem {
filename,
error: err.kind(),
},
} }
} }

View file

@ -191,3 +191,8 @@ where
pub fn fixtures_dir<'a>() -> PathBuf { pub fn fixtures_dir<'a>() -> PathBuf {
Path::new("tests").join("fixtures").join("build") Path::new("tests").join("fixtures").join("build")
} }
#[allow(dead_code)]
pub fn builtins_dir<'a>() -> PathBuf {
PathBuf::new().join("builtins")
}

View file

@ -11,8 +11,9 @@ mod helpers;
#[cfg(test)] #[cfg(test)]
mod test_load { mod test_load {
use crate::helpers::{fixtures_dir, send_set_from}; use crate::helpers::{builtins_dir, fixtures_dir};
use roc::load::{load, LoadedModule}; use roc::can::module::Module;
use roc::load::{load, Loaded, LoadedModule};
fn test_async<F: std::future::Future>(future: F) -> F::Output { fn test_async<F: std::future::Future>(future: F) -> F::Output {
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
@ -24,32 +25,104 @@ mod test_load {
rt.block_on(future) 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<LoadedModule>) {
let src_dir = builtins_dir();
let filename = src_dir.join("Defaults.roc");
load(src_dir, filename, deps).await;
}
#[test] #[test]
fn interface_with_deps() { fn interface_with_deps() {
let mut deps = Vec::new();
let src_dir = fixtures_dir().join("interface_with_deps"); let src_dir = fixtures_dir().join("interface_with_deps");
let filename = src_dir.join("Primary.roc"); let filename = src_dir.join("Primary.roc");
test_async(async { test_async(async {
let loaded = load(src_dir, filename).await; let module = expect_module(load(src_dir, filename, &mut deps).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
),
};
assert_eq!(module.name, Some("Primary".into())); assert_eq!(module.name, Some("Primary".into()));
assert_eq!(module.defs.len(), 6); assert_eq!(module.defs.len(), 6);
let module_names: Vec<Option<Box<str>>> = deps
.into_iter()
.map(|dep| dep.into_module().unwrap().name)
.collect();
assert_eq!( assert_eq!(
loaded.deps, module_names,
send_set_from(vec!["Dep1".into(), "Dep2".into(), "Dep3.Blah".into()]) 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<Option<Box<str>>> = 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<Option<Box<str>>> = 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())
]
); );
}); });
} }