Most files suffered major changes
- Less ambiguous syntax - Better parser (Chumsky only does tokenization now) - Tidy(|ier) error handling - Facade for simplified embedding - External code grouped in (fairly) self-contained Systems - Dynamic action dispatch - Many STL additions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::interner::Tok;
|
||||
use crate::representations::sourcefile::{FileEntry, Member, Namespace};
|
||||
use crate::representations::sourcefile::{FileEntry, Member, ModuleBlock};
|
||||
|
||||
fn member_rec(
|
||||
// object
|
||||
@@ -9,9 +9,9 @@ fn member_rec(
|
||||
prelude: &[FileEntry],
|
||||
) -> Member {
|
||||
match member {
|
||||
Member::Namespace(Namespace { name, body }) => {
|
||||
Member::Module(ModuleBlock { name, body }) => {
|
||||
let new_body = entv_rec(body, path, prelude);
|
||||
Member::Namespace(Namespace { name, body: new_body })
|
||||
Member::Module(ModuleBlock { name, body: new_body })
|
||||
},
|
||||
any => any,
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::collect_ops;
|
||||
use super::collect_ops::InjectedOperatorsFn;
|
||||
use super::parse_file::parse_file;
|
||||
use crate::ast::{Constant, Expr};
|
||||
use crate::ast::{Clause, Constant, Expr};
|
||||
use crate::error::{ProjectError, ProjectResult, TooManySupers};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::pipeline::error::{ProjectError, TooManySupers};
|
||||
use crate::pipeline::source_loader::{LoadedSource, LoadedSourceTable};
|
||||
use crate::representations::project::{ProjectExt, ProjectTree};
|
||||
use crate::representations::sourcefile::{absolute_path, FileEntry, Member};
|
||||
use crate::representations::tree::{ModEntry, ModMember, Module};
|
||||
use crate::representations::{NameLike, VName};
|
||||
use crate::tree::{WalkError, WalkErrorKind};
|
||||
use crate::utils::iter::{box_empty, box_once};
|
||||
use crate::utils::{pushed, unwrap_or, Substack};
|
||||
|
||||
@@ -26,25 +25,27 @@ struct ParsedSource<'a> {
|
||||
|
||||
/// Split a path into file- and subpath in knowledge
|
||||
///
|
||||
/// # Panics
|
||||
/// # Errors
|
||||
///
|
||||
/// if the path is invalid
|
||||
#[allow(clippy::type_complexity)] // bit too sensitive here IMO
|
||||
pub fn split_path<'a>(
|
||||
path: &'a [Tok<String>],
|
||||
proj: &'a ProjectTree<impl NameLike>,
|
||||
) -> (&'a [Tok<String>], &'a [Tok<String>]) {
|
||||
) -> Result<(&'a [Tok<String>], &'a [Tok<String>]), WalkError> {
|
||||
let (end, body) = unwrap_or!(path.split_last(); {
|
||||
return (&[], &[])
|
||||
return Ok((&[], &[]))
|
||||
});
|
||||
let mut module = (proj.0.walk_ref(body, false))
|
||||
.expect("invalid path can't have been split above");
|
||||
if let ModMember::Sub(m) = &module.items[end].member {
|
||||
let mut module = (proj.0.walk_ref(body, false))?;
|
||||
let entry = (module.items.get(end))
|
||||
.ok_or(WalkError { pos: path.len() - 1, kind: WalkErrorKind::Missing })?;
|
||||
if let ModMember::Sub(m) = &entry.member {
|
||||
module = m;
|
||||
}
|
||||
let file =
|
||||
module.extra.file.as_ref().map(|s| &path[..s.len()]).unwrap_or(path);
|
||||
let subpath = &path[file.len()..];
|
||||
(file, subpath)
|
||||
Ok((file, subpath))
|
||||
}
|
||||
|
||||
/// Convert normalized, prefixed source into a module
|
||||
@@ -63,7 +64,7 @@ fn source_to_module(
|
||||
// context
|
||||
i: &Interner,
|
||||
filepath_len: usize,
|
||||
) -> Result<Module<Expr<VName>, ProjectExt<VName>>, Rc<dyn ProjectError>> {
|
||||
) -> ProjectResult<Module<Expr<VName>, ProjectExt<VName>>> {
|
||||
let path_v = path.iter().rev_vec_clone();
|
||||
let imports = (data.iter())
|
||||
.filter_map(|ent| {
|
||||
@@ -73,16 +74,16 @@ fn source_to_module(
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let imports_from = (imports.iter())
|
||||
.map(|imp| -> Result<_, Rc<dyn ProjectError>> {
|
||||
.map(|imp| -> ProjectResult<_> {
|
||||
let mut imp_path_v = i.r(imp.path).clone();
|
||||
imp_path_v.push(imp.name.expect("glob imports had just been resolved"));
|
||||
let mut abs_path = absolute_path(&path_v, &imp_path_v, i)
|
||||
.expect("should have failed in preparsing");
|
||||
let name = abs_path.pop().ok_or_else(|| {
|
||||
TooManySupers {
|
||||
offender_file: i.extern_all(&path_v[..filepath_len]),
|
||||
offender_mod: i.extern_all(&path_v[filepath_len..]),
|
||||
path: i.extern_all(&imp_path_v),
|
||||
offender_file: path_v[..filepath_len].to_vec(),
|
||||
offender_mod: path_v[filepath_len..].to_vec(),
|
||||
path: imp_path_v,
|
||||
}
|
||||
.rc()
|
||||
})?;
|
||||
@@ -96,15 +97,18 @@ fn source_to_module(
|
||||
FileEntry::Export(names) => Box::new(names.iter().copied().map(mk_ent)),
|
||||
FileEntry::Exported(mem) => match mem {
|
||||
Member::Constant(constant) => box_once(mk_ent(constant.name)),
|
||||
Member::Namespace(ns) => box_once(mk_ent(ns.name)),
|
||||
Member::Module(ns) => box_once(mk_ent(ns.name)),
|
||||
Member::Rule(rule) => {
|
||||
let mut names = Vec::new();
|
||||
for e in rule.pattern.iter() {
|
||||
e.visit_names(Substack::Bottom, &mut |n| {
|
||||
if let Some([name]) = n.strip_prefix(&path_v[..]) {
|
||||
names.push((*name, n.clone()))
|
||||
e.search_all(&mut |e| {
|
||||
if let Clause::Name(n) = &e.value {
|
||||
if let Some([name]) = n.strip_prefix(&path_v[..]) {
|
||||
names.push((*name, n.clone()))
|
||||
}
|
||||
}
|
||||
})
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Box::new(names.into_iter())
|
||||
},
|
||||
@@ -124,7 +128,7 @@ fn source_to_module(
|
||||
let items = (data.into_iter())
|
||||
.filter_map(|ent| {
|
||||
let member_to_item = |exported, member| match member {
|
||||
Member::Namespace(ns) => {
|
||||
Member::Module(ns) => {
|
||||
let new_prep = unwrap_or!(
|
||||
&preparsed.items[&ns.name].member => ModMember::Sub;
|
||||
panic!("Preparsed should include entries for all submodules")
|
||||
@@ -171,7 +175,7 @@ fn files_to_module(
|
||||
path: Substack<Tok<String>>,
|
||||
files: Vec<ParsedSource>,
|
||||
i: &Interner,
|
||||
) -> Result<Module<Expr<VName>, ProjectExt<VName>>, Rc<dyn ProjectError>> {
|
||||
) -> ProjectResult<Module<Expr<VName>, ProjectExt<VName>>> {
|
||||
let lvl = path.len();
|
||||
debug_assert!(
|
||||
files.iter().map(|f| f.path.len()).max().unwrap() >= lvl,
|
||||
@@ -190,7 +194,7 @@ fn files_to_module(
|
||||
let items = (files.into_iter())
|
||||
.group_by(|f| f.path[lvl])
|
||||
.into_iter()
|
||||
.map(|(namespace, files)| -> Result<_, Rc<dyn ProjectError>> {
|
||||
.map(|(namespace, files)| -> ProjectResult<_> {
|
||||
let subpath = path.push(namespace);
|
||||
let files_v = files.collect::<Vec<_>>();
|
||||
let module = files_to_module(subpath, files_v, i)?;
|
||||
@@ -217,7 +221,7 @@ pub fn build_tree(
|
||||
i: &Interner,
|
||||
prelude: &[FileEntry],
|
||||
injected: &impl InjectedOperatorsFn,
|
||||
) -> Result<ProjectTree<VName>, Rc<dyn ProjectError>> {
|
||||
) -> ProjectResult<ProjectTree<VName>> {
|
||||
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
|
||||
@@ -225,7 +229,7 @@ pub fn build_tree(
|
||||
.map(|(path, loaded)| {
|
||||
Ok((path, loaded, parse_file(path, &files, &ops_cache, i, prelude)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, Rc<dyn ProjectError>>>()?;
|
||||
.collect::<ProjectResult<Vec<_>>>()?;
|
||||
// sort by similarity, then longest-first
|
||||
entries.sort_unstable_by(|a, b| a.0.cmp(b.0).reverse());
|
||||
let files = entries
|
||||
|
||||
@@ -3,14 +3,14 @@ use std::rc::Rc;
|
||||
use hashbrown::HashSet;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::error::{NotFound, ProjectError, ProjectResult};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::pipeline::error::{NotFound, 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 OpsResult = ProjectResult<Rc<HashSet<Tok<String>>>>;
|
||||
pub type ExportedOpsCache<'a> = Cache<'a, Sym, OpsResult>;
|
||||
|
||||
trait_set! {
|
||||
@@ -54,12 +54,9 @@ pub fn collect_exported_ops(
|
||||
unreachable!("visibility is not being checked here")
|
||||
},
|
||||
WalkErrorKind::Missing => NotFound {
|
||||
file: i.extern_all(fpath),
|
||||
subpath: (subpath.iter())
|
||||
.take(walk_err.pos)
|
||||
.map(|t| i.r(*t))
|
||||
.cloned()
|
||||
.collect(),
|
||||
source: None,
|
||||
file: fpath.to_vec(),
|
||||
subpath: subpath[..walk_err.pos].to_vec(),
|
||||
}
|
||||
.rc(),
|
||||
},
|
||||
|
||||
@@ -3,9 +3,9 @@ use std::rc::Rc;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use super::exported_ops::{ExportedOpsCache, OpsResult};
|
||||
use crate::error::ProjectResult;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::parse::is_op;
|
||||
use crate::pipeline::error::ProjectError;
|
||||
use crate::pipeline::import_abs_path::import_abs_path;
|
||||
use crate::pipeline::source_loader::LoadedSourceTable;
|
||||
use crate::representations::tree::{ModMember, Module};
|
||||
@@ -39,16 +39,17 @@ pub fn collect_ops_for(
|
||||
let tree = &loaded[file].preparsed.0;
|
||||
let mut ret = HashSet::new();
|
||||
tree_all_ops(tree, &mut ret);
|
||||
tree.visit_all_imports(&mut |modpath, _module, import| {
|
||||
tree.visit_all_imports(&mut |modpath, _m, import| -> ProjectResult<()> {
|
||||
if let Some(n) = import.name {
|
||||
ret.insert(n);
|
||||
} else {
|
||||
let path = import_abs_path(file, modpath, &i.r(import.path)[..], i)
|
||||
.expect("This error should have been caught during loading");
|
||||
let path = i.expect(
|
||||
import_abs_path(file, modpath, &i.r(import.path)[..], i),
|
||||
"This error should have been caught during loading",
|
||||
);
|
||||
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
|
||||
}
|
||||
Ok::<_, Rc<dyn ProjectError>>(())
|
||||
Ok(())
|
||||
})?;
|
||||
ret.drain_filter(|t| !is_op(i.r(*t)));
|
||||
Ok(Rc::new(ret))
|
||||
Ok(Rc::new(ret.into_iter().filter(|t| is_op(i.r(*t))).collect()))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::collect_ops::ExportedOpsCache;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::pipeline::import_abs_path::import_abs_path;
|
||||
use crate::representations::sourcefile::{
|
||||
FileEntry, Import, Member, Namespace,
|
||||
FileEntry, Import, Member, ModuleBlock,
|
||||
};
|
||||
use crate::representations::tree::{ModMember, Module};
|
||||
use crate::utils::iter::box_once;
|
||||
@@ -20,14 +20,14 @@ fn member_rec(
|
||||
i: &Interner,
|
||||
) -> Member {
|
||||
match member {
|
||||
Member::Namespace(Namespace { name, body }) => {
|
||||
Member::Module(ModuleBlock { name, body }) => {
|
||||
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, body, path, ops_cache, i);
|
||||
Member::Namespace(Namespace { name, body: new_body })
|
||||
Member::Module(ModuleBlock { name, body: new_body })
|
||||
},
|
||||
any => any,
|
||||
}
|
||||
@@ -58,10 +58,14 @@ fn entv_rec(
|
||||
.into_iter()
|
||||
.flat_map(|import| {
|
||||
if let Import { name: None, path } = import {
|
||||
let p = import_abs_path(mod_path, mod_stack, &i.r(path)[..], i)
|
||||
.expect("Should have emerged in preparsing");
|
||||
let names = (ops_cache.find(&i.i(&p)))
|
||||
.expect("Should have emerged in second parsing");
|
||||
let p = i.expect(
|
||||
import_abs_path(mod_path, mod_stack, &i.r(path)[..], i),
|
||||
"Should have emerged in preparsing",
|
||||
);
|
||||
let names = i.expect(
|
||||
ops_cache.find(&i.i(&p)),
|
||||
"Should have emerged in second parsing",
|
||||
);
|
||||
let imports = (names.iter())
|
||||
.map(move |&n| Import { name: Some(n), path })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -4,9 +4,9 @@ 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::error::ProjectResult;
|
||||
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};
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn parse_file(
|
||||
ops_cache: &ExportedOpsCache,
|
||||
i: &Interner,
|
||||
prelude: &[FileEntry],
|
||||
) -> Result<Vec<FileEntry>, Rc<dyn ProjectError>> {
|
||||
) -> ProjectResult<Vec<FileEntry>> {
|
||||
let ld = &loaded[path];
|
||||
// let ops_cache = collect_ops::mk_cache(loaded, i);
|
||||
let ops = collect_ops_for(path, loaded, ops_cache, i)?;
|
||||
@@ -34,8 +34,10 @@ pub fn parse_file(
|
||||
ops: &ops_vec,
|
||||
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 entries = i.expect(
|
||||
parse::parse2(ld.text.as_str(), ctx),
|
||||
"This error should have been caught during loading",
|
||||
);
|
||||
let with_prelude = add_prelude(entries, path, prelude);
|
||||
let impnormalized =
|
||||
normalize_imports(&ld.preparsed.0, with_prelude, path, ops_cache, i);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::collect_ops::ExportedOpsCache;
|
||||
use crate::ast::{Constant, Rule};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::representations::sourcefile::{FileEntry, Member, Namespace};
|
||||
use crate::representations::sourcefile::{FileEntry, Member, ModuleBlock};
|
||||
use crate::utils::Substack;
|
||||
|
||||
fn member_rec(
|
||||
@@ -19,9 +19,9 @@ fn member_rec(
|
||||
.chain(mod_stack.iter().rev_vec_clone().into_iter())
|
||||
.collect::<Vec<_>>();
|
||||
match data {
|
||||
Member::Namespace(Namespace { name, body }) => {
|
||||
Member::Module(ModuleBlock { name, body }) => {
|
||||
let new_body = entv_rec(mod_stack.push(name), body, path, ops_cache, i);
|
||||
Member::Namespace(Namespace { name, body: new_body })
|
||||
Member::Module(ModuleBlock { name, body: new_body })
|
||||
},
|
||||
Member::Constant(constant) => Member::Constant(Constant {
|
||||
name: constant.name,
|
||||
|
||||
Reference in New Issue
Block a user