Removed a copious amount of premature Rc-s

This commit is contained in:
2023-06-18 04:22:20 +01:00
parent aebbf51228
commit 79e28883db
56 changed files with 716 additions and 636 deletions

View File

@@ -12,8 +12,9 @@ use crate::pipeline::error::ProjectError;
use crate::pipeline::source_loader::{LoadedSource, LoadedSourceTable};
use crate::representations::sourcefile::{absolute_path, FileEntry, Member};
use crate::representations::tree::{ModEntry, ModMember, Module};
use crate::representations::{NameLike, VName};
use crate::utils::iter::{box_empty, box_once};
use crate::utils::{pushed, Substack};
use crate::utils::{pushed, unwrap_or, Substack};
#[derive(Debug)]
struct ParsedSource<'a> {
@@ -24,7 +25,7 @@ struct ParsedSource<'a> {
pub fn split_path<'a>(
path: &'a [Tok<String>],
proj: &'a ProjectTree,
proj: &'a ProjectTree<impl NameLike>,
) -> (&'a [Tok<String>], &'a [Tok<String>]) {
let (end, body) = if let Some(s) = path.split_last() {
s
@@ -32,9 +33,9 @@ pub fn split_path<'a>(
return (&[], &[]);
};
let mut module =
proj.0.walk(body, false).expect("invalid path cannot be split");
proj.0.walk_ref(body, false).expect("invalid path cannot be split");
if let ModMember::Sub(m) = &module.items[end].member {
module = m.clone();
module = m;
}
let file =
module.extra.file.as_ref().map(|s| &path[..s.len()]).unwrap_or(path);
@@ -52,7 +53,7 @@ fn source_to_module(
// context
i: &Interner,
filepath_len: usize,
) -> Rc<Module<Expr, ProjectExt>> {
) -> Module<Expr<VName>, ProjectExt<VName>> {
let path_v = path.iter().rev_vec_clone();
let imports = data
.iter()
@@ -70,13 +71,13 @@ fn source_to_module(
let mut abs_path =
absolute_path(&path_v, &imp_path_v, i).expect("tested in preparsing");
let name = abs_path.pop().expect("importing the global context");
(name, i.i(&abs_path))
(name, abs_path)
})
.collect::<HashMap<_, _>>();
let exports = data
.iter()
.flat_map(|ent| {
let mk_ent = |name| (name, i.i(&pushed(&path_v, name)));
let mk_ent = |name| (name, pushed(&path_v, name));
match ent {
FileEntry::Export(names) => Box::new(names.iter().copied().map(mk_ent)),
FileEntry::Exported(mem) => match mem {
@@ -86,8 +87,8 @@ fn source_to_module(
let mut names = Vec::new();
for e in rule.pattern.iter() {
e.visit_names(Substack::Bottom, &mut |n| {
if let Some([name]) = i.r(n).strip_prefix(&path_v[..]) {
names.push((*name, n))
if let Some([name]) = n.strip_prefix(&path_v[..]) {
names.push((*name, n.clone()))
}
})
}
@@ -109,58 +110,37 @@ fn source_to_module(
.collect::<Vec<_>>();
let items = data
.into_iter()
.filter_map(|ent| match ent {
FileEntry::Exported(Member::Namespace(ns)) => {
let prep_member = &preparsed.items[&ns.name].member;
let new_prep = if let ModMember::Sub(s) = prep_member {
s.as_ref()
} else {
panic!("preparsed missing a submodule")
};
let module = source_to_module(
path.push(ns.name),
new_prep,
ns.body,
i,
filepath_len,
);
let member = ModMember::Sub(module);
Some((ns.name, ModEntry { exported: true, member }))
},
FileEntry::Internal(Member::Namespace(ns)) => {
let prep_member = &preparsed.items[&ns.name].member;
let new_prep = if let ModMember::Sub(s) = prep_member {
s.as_ref()
} else {
panic!("preparsed missing a submodule")
};
let module = source_to_module(
path.push(ns.name),
new_prep,
ns.body,
i,
filepath_len,
);
let member = ModMember::Sub(module);
Some((ns.name, ModEntry { exported: false, member }))
},
FileEntry::Exported(Member::Constant(Constant { name, value })) => {
let member = ModMember::Item(value);
Some((name, ModEntry { exported: true, member }))
},
FileEntry::Internal(Member::Constant(Constant { name, value })) => {
let member = ModMember::Item(value);
Some((name, ModEntry { exported: false, member }))
},
_ => None,
.filter_map(|ent| {
let member_to_item = |exported, member| match member {
Member::Namespace(ns) => {
let new_prep = unwrap_or!(
&preparsed.items[&ns.name].member => ModMember::Sub;
panic!("preparsed missing a submodule")
);
let module = source_to_module(
path.push(ns.name),
new_prep,
ns.body,
i,
filepath_len,
);
let member = ModMember::Sub(module);
Some((ns.name, ModEntry { exported, member }))
},
Member::Constant(Constant { name, value }) => {
let member = ModMember::Item(value);
Some((name, ModEntry { exported, member }))
},
_ => None,
};
match ent {
FileEntry::Exported(member) => member_to_item(true, member),
FileEntry::Internal(member) => member_to_item(false, member),
_ => None,
}
})
.collect::<HashMap<_, _>>();
// println!(
// "Constructing file-module {} with members ({})",
// i.extern_all(&path_v[..]).join("::"),
// exports.keys().map(|t| i.r(*t)).join(", ")
// );
Rc::new(Module {
Module {
imports,
items,
extra: ProjectExt {
@@ -169,14 +149,14 @@ fn source_to_module(
rules,
file: Some(path_v[..filepath_len].to_vec()),
},
})
}
}
fn files_to_module(
path: Substack<Tok<String>>,
files: Vec<ParsedSource>,
i: &Interner,
) -> Rc<Module<Expr, ProjectExt>> {
) -> Module<Expr<VName>, ProjectExt<VName>> {
let lvl = path.len();
debug_assert!(
files.iter().map(|f| f.path.len()).max().unwrap() >= lvl,
@@ -186,7 +166,7 @@ fn files_to_module(
if files.len() == 1 && files[0].path.len() == lvl {
return source_to_module(
path,
files[0].loaded.preparsed.0.as_ref(),
&files[0].loaded.preparsed.0,
files[0].parsed.clone(),
i,
path.len(),
@@ -204,12 +184,9 @@ fn files_to_module(
(namespace, ModEntry { exported: true, member })
})
.collect::<HashMap<_, _>>();
let exports: HashMap<_, _> = items
.keys()
.copied()
.map(|name| (name, i.i(&pushed(&path_v, name))))
.collect();
Rc::new(Module {
let exports: HashMap<_, _> =
items.keys().copied().map(|name| (name, pushed(&path_v, name))).collect();
Module {
items,
imports: vec![],
extra: ProjectExt {
@@ -218,7 +195,7 @@ fn files_to_module(
rules: vec![],
file: None,
},
})
}
}
pub fn build_tree(
@@ -226,17 +203,13 @@ pub fn build_tree(
i: &Interner,
prelude: &[FileEntry],
injected: &impl InjectedOperatorsFn,
) -> Result<ProjectTree, Rc<dyn ProjectError>> {
) -> Result<ProjectTree<VName>, Rc<dyn ProjectError>> {
assert!(!files.is_empty(), "A tree requires at least one module");
let ops_cache = collect_ops::mk_cache(&files, i, injected);
let mut entries = files
.iter()
.map(|(path, loaded)| {
Ok((
i.r(*path),
loaded,
parse_file(*path, &files, &ops_cache, i, prelude)?,
))
Ok((path, loaded, parse_file(path, &files, &ops_cache, i, prelude)?))
})
.collect::<Result<Vec<_>, Rc<dyn ProjectError>>>()?;
// sort by similarity, then longest-first

View File

@@ -3,11 +3,12 @@ use std::rc::Rc;
use hashbrown::HashSet;
use trait_set::trait_set;
use crate::interner::{Interner, Sym, Tok};
use crate::interner::{Interner, Tok};
use crate::pipeline::error::{ModuleNotFound, ProjectError};
use crate::pipeline::source_loader::LoadedSourceTable;
use crate::representations::tree::WalkErrorKind;
use crate::utils::{split_max_prefix, unwrap_or, Cache};
use crate::Sym;
pub type OpsResult = Result<Rc<HashSet<Tok<String>>>, Rc<dyn ProjectError>>;
pub type ExportedOpsCache<'a> = Cache<'a, Sym, OpsResult>;
@@ -31,16 +32,13 @@ pub fn collect_exported_ops(
injected: &impl InjectedOperatorsFn,
) -> OpsResult {
let injected = injected(path).unwrap_or_else(|| Rc::new(HashSet::new()));
let is_file = |n: &[Tok<String>]| loaded.contains_key(&i.i(n));
let path_s = &i.r(path)[..];
let name_split = split_max_prefix(path_s, &is_file);
let (fpath_v, subpath_v) = unwrap_or!(name_split; return Ok(Rc::new(
let name_split = split_max_prefix(path_s, &|n| loaded.contains_key(n));
let (fpath, subpath) = unwrap_or!(name_split; 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()])
if path_s.len() == coprefix(path_s.iter(), modname.iter()) {
Some(modname[path_s.len()])
} else {
None
}
@@ -48,24 +46,24 @@ pub fn collect_exported_ops(
.chain(injected.iter().copied())
.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")
let preparsed = &loaded[fpath].preparsed;
let module =
preparsed.0.walk_ref(subpath, false).map_err(
|walk_err| match walk_err.kind {
WalkErrorKind::Private => {
unreachable!("visibility is not being checked here")
},
WalkErrorKind::Missing => ModuleNotFound {
file: i.extern_all(fpath),
subpath: (subpath.iter())
.take(walk_err.pos)
.map(|t| i.r(*t))
.cloned()
.collect(),
}
.rc(),
},
WalkErrorKind::Missing => ModuleNotFound {
file: i.extern_vec(fpath),
subpath: (subpath_v.iter())
.take(walk_err.pos)
.map(|t| i.r(*t))
.cloned()
.collect(),
}
.rc(),
}
})?;
)?;
let out = (module.items.iter())
.filter(|(_, v)| v.exported)
.map(|(k, _)| *k)

View File

@@ -19,7 +19,7 @@ fn tree_all_ops(
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);
tree_all_ops(m, ops);
}
}
}
@@ -31,9 +31,9 @@ pub fn collect_ops_for(
ops_cache: &ExportedOpsCache,
i: &Interner,
) -> OpsResult {
let tree = &loaded[&i.i(file)].preparsed.0;
let tree = &loaded[file].preparsed.0;
let mut ret = HashSet::new();
tree_all_ops(tree.as_ref(), &mut ret);
tree_all_ops(tree, &mut ret);
tree.visit_all_imports(&mut |modpath, _module, import| {
if let Some(n) = import.name {
ret.insert(n);

View File

@@ -1,15 +1,14 @@
use std::ops::Add;
use std::rc::Rc;
use hashbrown::HashMap;
use super::{ProjectExt, ProjectModule, ProjectTree};
use crate::ast::{Clause, Expr};
use crate::foreign::{Atom, Atomic, ExternFn};
use crate::interner::{Interner, Tok};
use crate::interner::Tok;
use crate::representations::location::Location;
use crate::representations::tree::{ModEntry, ModMember, Module};
use crate::representations::Primitive;
use crate::representations::{Primitive, VName};
use crate::utils::{pushed, Substack};
/// A lightweight module tree that can be built declaratively by hand to
@@ -17,7 +16,7 @@ use crate::utils::{pushed, Substack};
/// added convenience
pub enum ConstTree {
/// A function or constant
Const(Expr),
Const(Expr<VName>),
/// A submodule
Tree(HashMap<Tok<String>, ConstTree>),
}
@@ -67,8 +66,7 @@ fn from_const_tree_rec(
path: Substack<Tok<String>>,
consts: HashMap<Tok<String>, ConstTree>,
file: &[Tok<String>],
i: &Interner,
) -> ProjectModule {
) -> ProjectModule<VName> {
let mut items = HashMap::new();
let path_v = path.iter().rev_vec_clone();
for (name, item) in consts {
@@ -76,17 +74,13 @@ fn from_const_tree_rec(
exported: true,
member: match item {
ConstTree::Const(c) => ModMember::Item(c),
ConstTree::Tree(t) => ModMember::Sub(Rc::new(from_const_tree_rec(
path.push(name),
t,
file,
i,
))),
ConstTree::Tree(t) =>
ModMember::Sub(from_const_tree_rec(path.push(name), t, file)),
},
});
}
let exports =
items.keys().map(|name| (*name, i.i(&pushed(&path_v, *name)))).collect();
items.keys().map(|name| (*name, pushed(&path_v, *name))).collect();
Module {
items,
imports: vec![],
@@ -103,8 +97,7 @@ fn from_const_tree_rec(
pub fn from_const_tree(
consts: HashMap<Tok<String>, ConstTree>,
file: &[Tok<String>],
i: &Interner,
) -> ProjectTree {
let module = from_const_tree_rec(Substack::Bottom, consts, file, i);
ProjectTree(Rc::new(module))
) -> ProjectTree<VName> {
let module = from_const_tree_rec(Substack::Bottom, consts, file);
ProjectTree(module)
}

View File

@@ -26,5 +26,6 @@ pub use build_tree::{build_tree, split_path};
pub use collect_ops::InjectedOperatorsFn;
pub use const_tree::{from_const_tree, ConstTree};
pub use tree::{
collect_consts, collect_rules, ProjectExt, ProjectModule, ProjectTree,
collect_consts, collect_rules, vname_to_sym_tree, ProjectExt, ProjectModule,
ProjectTree,
};

View File

@@ -6,7 +6,7 @@ use crate::representations::sourcefile::{
};
use crate::representations::tree::{ModMember, Module};
use crate::utils::iter::box_once;
use crate::utils::{BoxedIter, Substack};
use crate::utils::{unwrap_or, BoxedIter, Substack};
fn member_rec(
// level
@@ -21,20 +21,12 @@ fn member_rec(
) -> Member {
match member {
Member::Namespace(Namespace { name, body }) => {
let prepmember = &preparsed.items[&name].member;
let subprep = if let ModMember::Sub(m) = prepmember {
m.clone()
} else {
let subprep = unwrap_or!(
&preparsed.items[&name].member => ModMember::Sub;
unreachable!("This name must point to a namespace")
};
let new_body = entv_rec(
mod_stack.push(name),
subprep.as_ref(),
body,
path,
ops_cache,
i,
);
let new_body =
entv_rec(mod_stack.push(name), subprep, body, path, ops_cache, i);
Member::Namespace(Namespace { name, body: new_body })
},
any => any,

View File

@@ -4,40 +4,35 @@ use super::add_prelude::add_prelude;
use super::collect_ops::{collect_ops_for, ExportedOpsCache};
use super::normalize_imports::normalize_imports;
use super::prefix::prefix;
use crate::interner::{Interner, Sym};
use crate::interner::{Interner, Tok};
use crate::parse;
use crate::pipeline::error::ProjectError;
use crate::pipeline::source_loader::LoadedSourceTable;
use crate::representations::sourcefile::{normalize_namespaces, FileEntry};
pub fn parse_file(
path: Sym,
path: &[Tok<String>],
loaded: &LoadedSourceTable,
ops_cache: &ExportedOpsCache,
i: &Interner,
prelude: &[FileEntry],
) -> Result<Vec<FileEntry>, Rc<dyn ProjectError>> {
let ld = &loaded[&path];
let ld = &loaded[path];
// let ops_cache = collect_ops::mk_cache(loaded, i);
let ops = collect_ops_for(&i.r(path)[..], loaded, ops_cache, i)?;
let ops = collect_ops_for(path, loaded, ops_cache, i)?;
let ops_vec = ops.iter().map(|t| i.r(*t)).cloned().collect::<Vec<_>>();
let ctx = parse::ParsingContext {
interner: i,
ops: &ops_vec,
file: Rc::new(i.extern_vec(path)),
file: Rc::new(i.extern_all(path)),
};
let entries = parse::parse(ld.text.as_str(), ctx)
.expect("This error should have been caught during loading");
let with_prelude = add_prelude(entries, &i.r(path)[..], prelude);
let impnormalized = normalize_imports(
&ld.preparsed.0,
with_prelude,
&i.r(path)[..],
ops_cache,
i,
);
let with_prelude = add_prelude(entries, path, prelude);
let impnormalized =
normalize_imports(&ld.preparsed.0, with_prelude, path, ops_cache, i);
let nsnormalized = normalize_namespaces(Box::new(impnormalized.into_iter()))
.expect("This error should have been caught during preparsing");
let prefixed = prefix(nsnormalized, &i.r(path)[..], ops_cache, i);
let prefixed = prefix(nsnormalized, path, ops_cache, i);
Ok(prefixed)
}

View File

@@ -1,5 +1,3 @@
use std::rc::Rc;
use super::collect_ops::ExportedOpsCache;
use crate::ast::{Constant, Rule};
use crate::interner::{Interner, Tok};
@@ -16,14 +14,10 @@ fn member_rec(
ops_cache: &ExportedOpsCache,
i: &Interner,
) -> Member {
// let except = |op| imported.contains(&op);
let except = |_| false;
let prefix_v = path
.iter()
let prefix = (path.iter())
.copied()
.chain(mod_stack.iter().rev_vec_clone().into_iter())
.collect::<Vec<_>>();
let prefix = i.i(&prefix_v);
match data {
Member::Namespace(Namespace { name, body }) => {
let new_body = entv_rec(mod_stack.push(name), body, path, ops_cache, i);
@@ -31,16 +25,16 @@ fn member_rec(
},
Member::Constant(constant) => Member::Constant(Constant {
name: constant.name,
value: constant.value.prefix(prefix, i, &except),
value: constant.value.prefix(&prefix, &|_| false),
}),
Member::Rule(rule) => Member::Rule(Rule {
prio: rule.prio,
pattern: Rc::new(
rule.pattern.iter().map(|e| e.prefix(prefix, i, &except)).collect(),
),
template: Rc::new(
rule.template.iter().map(|e| e.prefix(prefix, i, &except)).collect(),
),
pattern: (rule.pattern.into_iter())
.map(|e| e.prefix(&prefix, &|_| false))
.collect(),
template: (rule.template.into_iter())
.map(|e| e.prefix(&prefix, &|_| false))
.collect(),
}),
}
}

View File

@@ -1,28 +1,30 @@
use std::ops::Add;
use std::rc::Rc;
use hashbrown::HashMap;
use crate::ast::{Expr, Rule};
use crate::interner::{Interner, Sym, Tok};
use crate::interner::{Interner, Tok};
use crate::representations::tree::{ModMember, Module};
use crate::representations::NameLike;
use crate::tree::ModEntry;
use crate::utils::Substack;
use crate::{Sym, VName};
/// Additional data about a loaded module beyond the list of constants and
/// submodules
#[derive(Clone, Debug, Default)]
pub struct ProjectExt {
pub struct ProjectExt<N: NameLike> {
/// Pairs each foreign token to the module it was imported from
pub imports_from: HashMap<Tok<String>, Sym>,
pub imports_from: HashMap<Tok<String>, N>,
/// Pairs each exported token to its original full name
pub exports: HashMap<Tok<String>, Sym>,
pub exports: HashMap<Tok<String>, N>,
/// All rules defined in this module, exported or not
pub rules: Vec<Rule>,
pub rules: Vec<Rule<N>>,
/// Filename, if known, for error reporting
pub file: Option<Vec<Tok<String>>>,
}
impl Add for ProjectExt {
impl<N: NameLike> Add for ProjectExt<N> {
type Output = Self;
fn add(mut self, rhs: Self) -> Self::Output {
@@ -38,33 +40,36 @@ impl Add for ProjectExt {
}
/// A node in the tree describing the project
pub type ProjectModule = Module<Expr, ProjectExt>;
pub type ProjectModule<N> = Module<Expr<N>, ProjectExt<N>>;
/// Module corresponding to the root of a project
#[derive(Debug, Clone)]
pub struct ProjectTree(pub Rc<ProjectModule>);
pub struct ProjectTree<N: NameLike>(pub ProjectModule<N>);
fn collect_rules_rec(bag: &mut Vec<Rule>, module: &ProjectModule) {
fn collect_rules_rec<N: NameLike>(
bag: &mut Vec<Rule<N>>,
module: &ProjectModule<N>,
) {
bag.extend(module.extra.rules.iter().cloned());
for item in module.items.values() {
if let ModMember::Sub(module) = &item.member {
collect_rules_rec(bag, module.as_ref());
collect_rules_rec(bag, module);
}
}
}
/// Collect the complete list of rules to be used by the rule repository from
/// the [ProjectTree]
pub fn collect_rules(project: &ProjectTree) -> Vec<Rule> {
pub fn collect_rules<N: NameLike>(project: &ProjectTree<N>) -> Vec<Rule<N>> {
let mut rules = Vec::new();
collect_rules_rec(&mut rules, project.0.as_ref());
collect_rules_rec(&mut rules, &project.0);
rules
}
fn collect_consts_rec(
fn collect_consts_rec<N: NameLike>(
path: Substack<Tok<String>>,
bag: &mut HashMap<Sym, Expr>,
module: &ProjectModule,
bag: &mut HashMap<Sym, Expr<N>>,
module: &ProjectModule<N>,
i: &Interner,
) {
for (key, entry) in module.items.iter() {
@@ -81,11 +86,59 @@ fn collect_consts_rec(
}
/// Extract the symbol table from a [ProjectTree]
pub fn collect_consts(
project: &ProjectTree,
pub fn collect_consts<N: NameLike>(
project: &ProjectTree<N>,
i: &Interner,
) -> HashMap<Sym, Expr> {
) -> HashMap<Sym, Expr<N>> {
let mut consts = HashMap::new();
collect_consts_rec(Substack::Bottom, &mut consts, project.0.as_ref(), i);
collect_consts_rec(Substack::Bottom, &mut consts, &project.0, i);
consts
}
fn vname_to_sym_tree_rec(
tree: ProjectModule<VName>,
i: &Interner,
) -> ProjectModule<Sym> {
let process_expr = |ex: Expr<VName>| ex.transform_names(&|n| i.i(&n));
ProjectModule {
imports: tree.imports,
items: (tree.items.into_iter())
.map(|(k, ModEntry { exported, member })| {
(k, ModEntry {
exported,
member: match member {
ModMember::Sub(module) =>
ModMember::Sub(vname_to_sym_tree_rec(module, i)),
ModMember::Item(ex) => ModMember::Item(process_expr(ex)),
},
})
})
.collect(),
extra: ProjectExt {
imports_from: (tree.extra.imports_from.into_iter())
.map(|(k, v)| (k, i.i(&v)))
.collect(),
exports: (tree.extra.exports.into_iter())
.map(|(k, v)| (k, i.i(&v)))
.collect(),
rules: (tree.extra.rules.into_iter())
.map(|Rule { pattern, prio, template }| Rule {
pattern: pattern.into_iter().map(process_expr).collect(),
prio,
template: template.into_iter().map(process_expr).collect(),
})
.collect(),
file: tree.extra.file,
},
}
}
/// Convert a flexible vname-based tree to a more rigid but faster symbol-based
/// tree. The pipeline works with vnames, but the macro executor works with
/// symbols.
pub fn vname_to_sym_tree(
tree: ProjectTree<VName>,
i: &Interner,
) -> ProjectTree<Sym> {
ProjectTree(vname_to_sym_tree_rec(tree.0, i))
}