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 bumpalo::collections::Vec;
use bumpalo::Bump;
use std::future::Future;
use std::fs::read_to_string;
use std::io;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use tokio::fs::read_to_string;
pub struct Loaded<'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 problems: Vec<'a, BuildProblem<'a>>,
}
struct Env<'a> {
struct Env<'a, 'p> {
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>,
}
@ -33,7 +34,7 @@ pub enum BuildProblem<'a> {
FileNotFound(&'a Path),
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq)]
pub enum LoadedHeader<'a> {
Valid {
scope: ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>,
@ -42,38 +43,32 @@ pub enum LoadedHeader<'a> {
ParsingFailed(Fail),
}
pub async fn load<'a>(arena: &'a Bump, src_dir: &'a Path, filename: &Path) -> Loaded<'a> {
let env = Env {
pub fn load<'a>(arena: &'a Bump, src_dir: &Path, filename: &Path) -> Loaded<'a> {
let mut env = Env {
arena,
src_dir,
problems: Vec::new_in(&arena),
loaded_headers: MutMap::default(),
queue: MutMap::default(),
};
/// 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 requested_header = load_filename(&mut env, filename);
let mut defs = MutMap::default();
// for (module_name, state) in env.queue {
// let loaded_defs = match module::module_defs().parse(arena, state) {
// Ok((defs, _)) => Ok(defs),
// Err((fail, _)) => Err(fail),
// };
for (module_name, state) in env.queue {
let loaded_defs = match module::module_defs().parse(arena, state) {
Ok((defs, _)) => Ok(defs),
Err((fail, _)) => Err(fail),
};
// defs.insert(module_name, loaded_defs);
// }
defs.insert(module_name, loaded_defs);
}
Loaded {
requested_header,
dependent_headers,
dependent_headers: env.loaded_headers,
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.
///
/// If a given import has not been loaded yet, load it too.
async fn load_module<'a>(env: &'a Env<'a>,
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>,
module_name: &ModuleName<'a>) -> (LoadedHeader<'a>, ImMap<ModuleName<'a>, LoadedHeader<'a>>) {
fn load_module<'a, 'p>(env: &mut Env<'a, 'p>, module_name: &ModuleName<'a>) -> LoadedHeader<'a> {
// 1. Convert module_name to filename, using src_dir.
// 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.)
@ -145,14 +138,11 @@ async fn load_module<'a>(env: &'a Env<'a>,
// End with .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>,
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>,
filename: &Path) -> (LoadedHeader<'a>, ImMap<ModuleName<'a>, LoadedHeader<'a>>) {
let imports = match read_to_string(filename).await {
fn load_filename<'a, 'p>(env: &mut Env<'a, 'p>, filename: &Path) -> LoadedHeader<'a> {
match read_to_string(filename) {
Ok(src) => {
// 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
@ -164,80 +154,64 @@ async fn load_filename<'a, 'p>(env: &'a Env<'a>,
match module::module().parse(env.arena, state) {
Ok((Module::Interface { header }, state)) => {
let mut scope = ImMap::default();
// Enqueue the defs parsing job for background processing.
// env.queue.insert(header.name.value, state);
header.imports
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)) => {
let mut scope = ImMap::default();
// Enqueue the defs parsing job for background processing.
// The app module has a module name of ""
// env.queue.insert(ModuleName::new(""), state);
header.imports
}
Err((fail, _)) => {
return LoadedHeader::ParsingFailed(fail);
env.queue.insert(ModuleName::new(""), state);
for loc_entry in header.imports {
load_import(env, loc_entry.region, &loc_entry.value, &mut scope);
}
LoadedHeader::Valid { scope }
}
Err((fail, _)) => LoadedHeader::ParsingFailed(fail),
}
}
Err(err) => return LoadedHeader::FileProblem(err.kind()),
};
Err(err) => LoadedHeader::FileProblem(err.kind()),
}
}
let mut scope = ImMap::default();
let mut headers = ImMap::default();
fn load_import<'a, 'p>(
env: &mut Env<'a, 'p>,
region: Region,
entry: &ImportsEntry<'a>,
scope: &mut ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>,
) {
use crate::parse::ast::ImportsEntry::*;
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;
match entry {
Module(module_name, exposes) => {
// If we haven't already loaded the module, load it!
if !env.loaded_headers.contains_key(&module_name) {
let loaded = load_module(env, module_name);
scope = scope.union(new_scope);
env.loaded_headers.insert(*module_name, loaded);
}
if let Some((module_name, loaded_header)) = opt_header {
headers.insert(module_name, loaded_header);
for loc_entry in exposes {
expose(*module_name, &loc_entry.value, loc_entry.region, scope)
}
}
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
// Ignore spaces.
load_import(env, region, *sub_entry, scope)
}
}
(LoadedHeader::Valid { scope }, headers)
}
type Scope<'a>= ImMap<UnqualifiedIdent<'a>, (Symbol, Region)>;
fn load_import<'a>(
env: &'a Env<'a>,
region: Region,
loaded_headers: ImMap<ModuleName<'a>, LoadedHeader<'a>>,
entry: &'a ImportsEntry<'a>,
) -> Pin<Box<dyn Future<Output = (Scope<'a>, Option<(ModuleName<'a>, LoadedHeader<'a>)>)> + 'a>> {
Box::pin(async move {
use crate::parse::ast::ImportsEntry::*;
match entry {
Module(module_name, exposes) => {
// If we haven't already loaded the module, load it!
let new_header = if !loaded_headers.contains_key(&module_name) {
let loaded = load_module(env, loaded_headers, module_name).await;
Some((*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)
}
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
// Ignore spaces.
load_import(env, region, *sub_entry).await
}
}
})
}
fn expose<'a>(