Revert "First pass at async stuff"

This reverts commit 43440629ea81978f379c79576d8d9cada1be85fa.
This commit is contained in:
Richard Feldman 2019-11-30 08:48:07 -05:00
parent 29acb7a2b4
commit 700fd6d2f2

View file

@ -8,21 +8,22 @@ use crate::parse::parser::{Fail, Parser, State};
use crate::region::{Located, Region}; use crate::region::{Located, Region};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use std::future::Future; use std::fs::read_to_string;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin;
use tokio::fs::read_to_string;
pub struct Loaded<'a> { pub struct Loaded<'a> {
pub requested_header: LoadedHeader<'a>, pub requested_header: LoadedHeader<'a>,
pub dependent_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>, pub dependent_headers: MutMap<ModuleName<'a>, LoadedHeader<'a>>,
pub defs: MutMap<ModuleName<'a>, Result<Vec<'a, Located<Def<'a>>>, Fail>>, pub defs: MutMap<ModuleName<'a>, Result<Vec<'a, Located<Def<'a>>>, Fail>>,
pub problems: Vec<'a, BuildProblem<'a>>,
} }
struct Env<'a> { struct Env<'a, 'p> {
pub arena: &'a Bump, pub arena: &'a Bump,
pub src_dir: &'a Path, pub src_dir: &'p Path,
pub problems: Vec<'a, BuildProblem<'a>>,
pub loaded_headers: MutMap<ModuleName<'a>, LoadedHeader<'a>>,
pub queue: Queue<'a>, pub queue: Queue<'a>,
} }
@ -33,7 +34,7 @@ pub enum BuildProblem<'a> {
FileNotFound(&'a Path), FileNotFound(&'a Path),
} }
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq)]
pub enum LoadedHeader<'a> { pub enum LoadedHeader<'a> {
Valid { Valid {
scope: ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>, scope: ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>,
@ -42,38 +43,32 @@ pub enum LoadedHeader<'a> {
ParsingFailed(Fail), ParsingFailed(Fail),
} }
pub async fn load<'a>(arena: &'a Bump, src_dir: &'a Path, filename: &Path) -> Loaded<'a> { pub fn load<'a>(arena: &'a Bump, src_dir: &Path, filename: &Path) -> Loaded<'a> {
let env = Env { let mut env = Env {
arena, arena,
src_dir, src_dir,
problems: Vec::new_in(&arena),
loaded_headers: MutMap::default(),
queue: MutMap::default(), queue: MutMap::default(),
}; };
let requested_header = load_filename(&mut env, filename);
/// TODO proof of concept:
///
/// set up a job queue, and load *all* modules using that.
/// after each one loads, maintain a cache of "we've already started loading this"
/// so subsequent ones don't need to enqueue redundantly -
/// but also check again before running a fresh load!
/// Also, use a similar (maybe even the same?) queue for parsing defs in parallel
let (requested_header, dependent_headers) = load_filename(&env, filename).await;
let mut defs = MutMap::default(); let mut defs = MutMap::default();
// for (module_name, state) in env.queue { for (module_name, state) in env.queue {
// let loaded_defs = match module::module_defs().parse(arena, state) { let loaded_defs = match module::module_defs().parse(arena, state) {
// Ok((defs, _)) => Ok(defs), Ok((defs, _)) => Ok(defs),
// Err((fail, _)) => Err(fail), Err((fail, _)) => Err(fail),
// }; };
// defs.insert(module_name, loaded_defs); defs.insert(module_name, loaded_defs);
// } }
Loaded { Loaded {
requested_header, requested_header,
dependent_headers, dependent_headers: env.loaded_headers,
defs, defs,
problems: env.problems,
} }
} }
@ -122,9 +117,7 @@ pub async fn load<'a>(arena: &'a Bump, src_dir: &'a Path, filename: &Path) -> Lo
/// module's canonicalization. /// module's canonicalization.
/// ///
/// If a given import has not been loaded yet, load it too. /// If a given import has not been loaded yet, load it too.
async fn load_module<'a>(env: &'a Env<'a>, fn load_module<'a, 'p>(env: &mut Env<'a, 'p>, module_name: &ModuleName<'a>) -> LoadedHeader<'a> {
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>,
module_name: &ModuleName<'a>) -> (LoadedHeader<'a>, ImMap<ModuleName<'a>, LoadedHeader<'a>>) {
// 1. Convert module_name to filename, using src_dir. // 1. Convert module_name to filename, using src_dir.
// 2. Open that file for reading. (If there's a problem, record it and bail.) // 2. Open that file for reading. (If there's a problem, record it and bail.)
// 3. Read the whole file into a string. (In the future, we can read just the header.) // 3. Read the whole file into a string. (In the future, we can read just the header.)
@ -145,14 +138,11 @@ async fn load_module<'a>(env: &'a Env<'a>,
// End with .roc // End with .roc
filename.set_extension("roc"); filename.set_extension("roc");
load_filename(env, loaded_headers,&filename).await load_filename(env, &filename)
} }
async fn load_filename<'a, 'p>(env: &'a Env<'a>, fn load_filename<'a, 'p>(env: &mut Env<'a, 'p>, filename: &Path) -> LoadedHeader<'a> {
match read_to_string(filename) {
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>,
filename: &Path) -> (LoadedHeader<'a>, ImMap<ModuleName<'a>, LoadedHeader<'a>>) {
let imports = match read_to_string(filename).await {
Ok(src) => { Ok(src) => {
// 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
// in the arena as a Vec<'a, u8> and call .as_mut_slice() on it to // in the arena as a Vec<'a, u8> and call .as_mut_slice() on it to
@ -164,80 +154,64 @@ async fn load_filename<'a, 'p>(env: &'a Env<'a>,
match module::module().parse(env.arena, state) { match module::module().parse(env.arena, state) {
Ok((Module::Interface { header }, state)) => { Ok((Module::Interface { header }, state)) => {
// Enqueue the defs parsing job for background processing. let mut scope = ImMap::default();
// env.queue.insert(header.name.value, state);
header.imports // Enqueue the defs parsing job for background processing.
env.queue.insert(header.name.value, state);
for loc_entry in header.imports {
load_import(env, loc_entry.region, &loc_entry.value, &mut scope);
}
LoadedHeader::Valid { scope }
} }
Ok((Module::App { header }, state)) => { Ok((Module::App { header }, state)) => {
let mut scope = ImMap::default();
// Enqueue the defs parsing job for background processing. // Enqueue the defs parsing job for background processing.
// The app module has a module name of "" // The app module has a module name of ""
// env.queue.insert(ModuleName::new(""), state); env.queue.insert(ModuleName::new(""), state);
header.imports for loc_entry in header.imports {
} load_import(env, loc_entry.region, &loc_entry.value, &mut scope);
Err((fail, _)) => {
return LoadedHeader::ParsingFailed(fail);
}
}
}
Err(err) => return LoadedHeader::FileProblem(err.kind()),
};
let mut scope = ImMap::default();
let mut headers = ImMap::default();
for loc_entry in imports {
let (new_scope, opt_header) =
load_import(env, loc_entry.region, loaded_headers, env.arena.alloc(loc_entry.value)).await;
scope = scope.union(new_scope);
if let Some((module_name, loaded_header)) = opt_header {
headers.insert(module_name, loaded_header);
}
} }
(LoadedHeader::Valid { scope }, headers) LoadedHeader::Valid { scope }
}
Err((fail, _)) => LoadedHeader::ParsingFailed(fail),
}
}
Err(err) => LoadedHeader::FileProblem(err.kind()),
}
} }
type Scope<'a>= ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>; fn load_import<'a, 'p>(
env: &mut Env<'a, 'p>,
fn load_import<'a>(
env: &'a Env<'a>,
region: Region, region: Region,
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>, entry: &ImportsEntry<'a>,
entry: &'a ImportsEntry<'a>, scope: &mut ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>,
) -> Pin<Box<dyn Future<Output = (Scope<'a>, Option<(ModuleName<'a>, LoadedHeader<'a>)>)> + 'a>> { ) {
Box::pin(async move {
use crate::parse::ast::ImportsEntry::*; use crate::parse::ast::ImportsEntry::*;
match entry { match entry {
Module(module_name, exposes) => { Module(module_name, exposes) => {
// If we haven't already loaded the module, load it! // If we haven't already loaded the module, load it!
let new_header = if !loaded_headers.contains_key(&module_name) { if !env.loaded_headers.contains_key(&module_name) {
let loaded = load_module(env, loaded_headers, module_name).await; let loaded = load_module(env, module_name);
Some((*module_name, loaded)) env.loaded_headers.insert(*module_name, loaded);
} else {
None
};
let mut scope = ImMap::default();
for loc_entry in exposes {
expose(*module_name, &loc_entry.value, loc_entry.region, &mut scope)
} }
(scope, new_header) for loc_entry in exposes {
expose(*module_name, &loc_entry.value, loc_entry.region, scope)
}
} }
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => { SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
// Ignore spaces. // Ignore spaces.
load_import(env, region, *sub_entry).await load_import(env, region, *sub_entry, scope)
} }
} }
})
} }
fn expose<'a>( fn expose<'a>(