mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Merge branch 'trunk' into ct/typos-0
This commit is contained in:
commit
988a5401f9
6 changed files with 152 additions and 37 deletions
3
builtins/Defaults.roc
Normal file
3
builtins/Defaults.roc
Normal file
|
@ -0,0 +1,3 @@
|
|||
interface Defaults
|
||||
exposes []
|
||||
imports [ Map.{ Map }, Set.{ Set } ]
|
5
builtins/Map.roc
Normal file
5
builtins/Map.roc
Normal file
|
@ -0,0 +1,5 @@
|
|||
interface Map
|
||||
exposes [ isEmpty ]
|
||||
imports []
|
||||
|
||||
isEmpty = 0
|
7
builtins/Set.roc
Normal file
7
builtins/Set.roc
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface Set
|
||||
exposes [ isEmpty ]
|
||||
imports []
|
||||
|
||||
## Check
|
||||
|
||||
# isEmpty : List * -> Bool
|
|
@ -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,29 @@ pub enum BuildProblem<'a> {
|
|||
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 {
|
||||
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<Module> {
|
||||
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 +69,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<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 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<Box<str>> = SendSet::default();
|
||||
|
||||
// Get a fresh env, since the previous one has been consumed
|
||||
let env = Env { src_dir };
|
||||
|
@ -95,7 +115,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 +130,6 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded {
|
|||
|
||||
Loaded {
|
||||
requested_module,
|
||||
deps: all_deps,
|
||||
vars_created,
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +137,7 @@ pub async fn load<'a>(src_dir: PathBuf, filename: PathBuf) -> Loaded {
|
|||
async fn load_module(
|
||||
env: &Env,
|
||||
module_name: Box<str>,
|
||||
tx: Sender<Deps>,
|
||||
tx: Sender<DepNames>,
|
||||
var_store: &VarStore,
|
||||
) -> LoadedModule {
|
||||
let mut filename = PathBuf::new();
|
||||
|
@ -133,16 +152,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<Deps>,
|
||||
filename: PathBuf,
|
||||
tx: Sender<DepNames>,
|
||||
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 +250,15 @@ 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(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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::{builtins_dir, fixtures_dir};
|
||||
use roc::can::module::Module;
|
||||
use roc::load::{load, Loaded, LoadedModule};
|
||||
|
||||
fn test_async<F: std::future::Future>(future: F) -> F::Output {
|
||||
use tokio::runtime::Runtime;
|
||||
|
@ -24,32 +25,104 @@ 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<LoadedModule>) {
|
||||
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);
|
||||
|
||||
let module_names: Vec<Option<Box<str>>> = deps
|
||||
.into_iter()
|
||||
.map(|dep| dep.into_module().unwrap().name)
|
||||
.collect();
|
||||
|
||||
assert_eq!(
|
||||
loaded.deps,
|
||||
send_set_from(vec!["Dep1".into(), "Dep2".into(), "Dep3.Blah".into()])
|
||||
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<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())
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue