mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +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 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(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue