bug fixes and performance improvements

This commit is contained in:
2023-05-07 22:35:38 +01:00
parent f3ce910f66
commit a604e40bad
167 changed files with 5965 additions and 4229 deletions

View File

@@ -0,0 +1,75 @@
use std::rc::Rc;
use hashbrown::HashSet;
use crate::representations::tree::WalkErrorKind;
use crate::pipeline::source_loader::LoadedSourceTable;
use crate::pipeline::error::{ProjectError, ModuleNotFound};
use crate::interner::{Token, Interner};
use crate::utils::Cache;
use crate::pipeline::split_name::split_name;
pub type OpsResult = Result<Rc<HashSet<Token<String>>>, Rc<dyn ProjectError>>;
pub type ExportedOpsCache<'a> = Cache<'a, Token<Vec<Token<String>>>, OpsResult>;
pub trait InjectedOperatorsFn = Fn(
Token<Vec<Token<String>>>
) -> Option<Rc<HashSet<Token<String>>>>;
fn coprefix<T: Eq>(
l: impl Iterator<Item = T>,
r: impl Iterator<Item = T>
) -> usize {
l.zip(r).take_while(|(a, b)| a == b).count()
}
/// Collect all names exported by the module at the specified path
pub fn collect_exported_ops(
path: Token<Vec<Token<String>>>,
loaded: &LoadedSourceTable,
i: &Interner,
injected: &impl InjectedOperatorsFn
) -> OpsResult {
if let Some(i) = injected(path) {return Ok(i)}
let is_file = |n: &[Token<String>]| loaded.contains_key(&i.i(n));
let path_s = &i.r(path)[..];
let name_split = split_name(path_s, &is_file);
let (fpath_v, subpath_v) = if let Some(f) = name_split {f} else {
return Ok(Rc::new(loaded.keys().copied()
.filter_map(|modname| {
let modname_s = i.r(modname);
if path_s.len() == coprefix(path_s.iter(), modname_s.iter()) {
Some(modname_s[path_s.len()])
} else {None}
})
.collect::<HashSet<_>>()
))
};
let fpath = i.i(fpath_v);
let preparsed = &loaded[&fpath].preparsed;
let module = preparsed.0.walk(&subpath_v, false)
.map_err(|walk_err| match walk_err.kind {
WalkErrorKind::Private => unreachable!("visibility is not being checked here"),
WalkErrorKind::Missing => ModuleNotFound{
file: i.extern_vec(fpath),
subpath: subpath_v.into_iter()
.take(walk_err.pos)
.map(|t| i.r(*t))
.cloned()
.collect()
}.rc(),
})?;
Ok(Rc::new(module.items.iter()
.filter(|(_, v)| v.exported)
.map(|(k, _)| *k)
.collect()
))
}
pub fn mk_cache<'a>(
loaded: &'a LoadedSourceTable,
i: &'a Interner,
injected: &'a impl InjectedOperatorsFn,
) -> ExportedOpsCache<'a> {
Cache::new(|path, _this| collect_exported_ops(path, loaded, i, injected))
}

View File

@@ -0,0 +1,8 @@
mod exported_ops;
mod ops_for;
pub use exported_ops::{
ExportedOpsCache, OpsResult, InjectedOperatorsFn,
collect_exported_ops, mk_cache
};
pub use ops_for::collect_ops_for;

View File

@@ -0,0 +1,49 @@
use std::rc::Rc;
use hashbrown::HashSet;
use crate::parse::is_op;
use crate::pipeline::error::ProjectError;
use crate::pipeline::source_loader::LoadedSourceTable;
use crate::interner::{Token, Interner};
use crate::representations::tree::{Module, ModMember};
use crate::pipeline::import_abs_path::import_abs_path;
use super::exported_ops::{ExportedOpsCache, OpsResult};
/// Collect all operators and names, exported or local, defined in this
/// tree.
fn tree_all_ops(
module: &Module<impl Clone, impl Clone>,
ops: &mut HashSet<Token<String>>
) {
ops.extend(module.items.keys().copied());
for ent in module.items.values() {
if let ModMember::Sub(m) = &ent.member {
tree_all_ops(m.as_ref(), ops);
}
}
}
/// Collect all names imported in this file
pub fn collect_ops_for(
file: &[Token<String>],
loaded: &LoadedSourceTable,
ops_cache: &ExportedOpsCache,
i: &Interner
) -> OpsResult {
let tree = &loaded[&i.i(file)].preparsed.0;
let mut ret = HashSet::new();
tree_all_ops(tree.as_ref(), &mut ret);
tree.visit_all_imports(&mut |modpath, module, import| {
if let Some(n) = import.name { ret.insert(n); } else {
let path = import_abs_path(
&file, modpath, module, &i.r(import.path)[..], i
).expect("This error should have been caught during loading");
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
}
Ok::<_, Rc<dyn ProjectError>>(())
})?;
ret.drain_filter(|t| !is_op(i.r(*t)));
Ok(Rc::new(ret))
}