Added directfs

Added a very rudimentary file I/O system suitable for experimenting
with the language further. A better one will be designed when we have
sensible error management.
This commit is contained in:
2023-09-17 16:37:39 +01:00
parent 1078835e8b
commit 7396078304
84 changed files with 563 additions and 721 deletions

View File

@@ -1,59 +0,0 @@
use std::slice;
use chumsky::primitive::Container;
use hashbrown::HashMap;
use crate::representations::project::{ProjectMod, ItemKind, ProjectEntry};
use crate::tree::ModMember;
use crate::utils::{pushed, unwrap_or};
use crate::{ProjectTree, VName, Tok, NameLike};
use super::walk_with_links::{walk_with_links, Target};
pub struct AliasCache {
data: HashMap<Vec<Tok<String>>, Option<Vec<Tok<String>>>>,
}
impl AliasCache {
pub fn new() -> Self {
Self { data: HashMap::new() }
}
/// Finds the absolute nsname corresponding to the given name in the given
/// context, if it's imported. If the name is defined locally, returns None
/// to avoid allocating several vectors for every local variable.
pub fn resolv_name<'a>(
&'a mut self,
root: &ProjectMod<VName>,
location: &[Tok<String>],
name: Tok<String>
) -> Option<&'a [Tok<String>]> {
let full_path = pushed(location, name);
if let Some(result) = self.data.get(&full_path) {
return result.as_deref();
}
let (ent, finalp) = walk_with_links(root, location.iter().cloned())
.expect("This path should be valid");
let m = unwrap_or!{ent => Target::Mod; panic!("Must be a module")};
let result = m.extra.imports_from.get(&name).map(|next| {
self.resolv_name(root, &next, name).unwrap_or(&next)
});
self.data.insert(full_path, result.map(|s| s.to_vec()));
return result;
}
/// Find the absolute target of a
pub fn resolv_vec<'a>(
&'a mut self,
root: &ProjectMod<VName>,
modname: &[Tok<String>],
vname: &[Tok<String>],
) -> Option<&'a [Tok<String>]> {
let (name, ns) = vname.split_last().expect("name cannot be empty");
if ns.is_empty() {
self.resolv_name(modname, name)
} else {
let origin = self.resolv_vec(modname, ns)?;
self.resolv_name(origin, name)
}
}
}

View File

@@ -1,4 +1,3 @@
// mod alias_cache;
mod resolve_aliases;
mod walk_with_links;

View File

@@ -11,6 +11,7 @@ use crate::tree::{ModEntry, ModMember, Module};
use crate::utils::pure_push::pushed;
use crate::{Interner, ProjectTree, Tok, VName};
#[must_use]
fn resolve_aliases_rec(
root: &ProjectMod<VName>,
module: &ProjectMod<VName>,
@@ -26,7 +27,6 @@ fn resolve_aliases_rec(
let full_name = (module.extra.path.iter()).chain(n.iter()).cloned();
match walk_with_links(root, full_name, false) {
Ok(rep) => Some(rep.abs_path),
// Ok(_) => None,
Err(e) => {
let leftovers = e.tail.collect::<Vec<_>>();
if !leftovers.is_empty() {
@@ -87,6 +87,7 @@ fn resolve_aliases_rec(
}
}
#[must_use]
pub fn resolve_aliases(
project: ProjectTree<VName>,
updated: &impl Fn(&[Tok<String>]) -> bool,

View File

@@ -12,6 +12,7 @@ pub enum Target<'a, N: NameLike> {
Leaf(&'a ProjectItem<N>),
}
#[must_use = "this is the sole product of this function"]
pub struct WalkReport<'a, N: NameLike> {
pub target: Target<'a, N>,
pub abs_path: VName,

View File

@@ -87,6 +87,7 @@ pub fn load_file(root: &Path, path: &[Tok<String>]) -> IOResult {
}
/// Generates a cached file loader for a directory
#[must_use]
pub fn mk_dir_cache(root: PathBuf) -> Cache<'static, VName, IOResult> {
Cache::new(move |vname: VName, _this| load_file(&root, &vname))
}
@@ -125,6 +126,7 @@ pub fn load_embed<T: 'static + RustEmbed>(path: &str, ext: &str) -> IOResult {
}
/// Generates a cached file loader for a [RustEmbed]
#[must_use]
pub fn mk_embed_cache<T: 'static + RustEmbed>(
ext: &str,
) -> Cache<'_, Vec<Stok>, IOResult> {
@@ -136,6 +138,7 @@ pub fn mk_embed_cache<T: 'static + RustEmbed>(
/// Load all files from an embed and convert them into a map usable in a
/// [System]
#[must_use]
pub fn embed_to_map<T: 'static + RustEmbed>(
suffix: &str,
i: &Interner,

View File

@@ -1,55 +0,0 @@
use std::hash::Hash;
use hashbrown::{HashMap, HashSet};
use crate::{interner::Tok, VName};
#[derive(Clone, Debug, Default)]
pub struct AliasMap {
pub targets: HashMap<VName, VName>,
pub aliases: HashMap<VName, HashSet<VName>>,
}
impl AliasMap {
pub fn new() -> Self {
Self::default()
}
pub fn link(&mut self, alias: VName, target: VName) {
let prev = self.targets.insert(alias.clone(), target.clone());
debug_assert!(prev.is_none(), "Alias already has a target");
multimap_entry(&mut self.aliases, &target).insert(alias.clone());
// Remove aliases of the alias
if let Some(alts) = self.aliases.remove(&alias) {
for alt in alts {
// Assert that this step has always been done in the past
debug_assert!(
self.aliases.get(&alt).map(HashSet::is_empty).unwrap_or(true),
"Alias set of alias not empty"
);
let alt_target = self.targets.insert(alt.clone(), target.clone());
debug_assert!(
alt_target.as_ref() == Some(&alias),
"Name not target of its own alias"
);
multimap_entry(&mut self.aliases, &alias).insert(alt);
}
}
}
pub fn resolve(&self, alias: &[Tok<String>]) -> Option<&VName> {
self.targets.get(alias)
}
}
/// find or create the set belonging to the given key in the given
/// map-to-set (aka. multimap)
fn multimap_entry<'a, K: Eq + Hash + Clone, V>(
map: &'a mut HashMap<K, HashSet<V>>,
key: &'_ K,
) -> &'a mut HashSet<V> {
map
.raw_entry_mut()
.from_key(key)
.or_insert_with(|| (key.clone(), HashSet::new()))
.1
}

View File

@@ -1,86 +0,0 @@
use super::alias_map::AliasMap;
use super::decls::{InjectedAsFn, UpdatedFn};
use crate::ast::{Expr, Rule};
use crate::interner::Tok;
use crate::representations::project::{ItemKind, ProjectMod};
use crate::representations::tree::ModMember;
use crate::representations::VName;
use crate::utils::Substack;
fn resolve_rec(
namespace: &[Tok<String>],
alias_map: &AliasMap,
) -> Option<VName> {
if let Some(alias) = alias_map.resolve(namespace) {
Some(alias.clone())
} else if let Some((foot, body)) = namespace.split_last() {
let mut new_beginning = resolve_rec(body, alias_map)?;
new_beginning.push(foot.clone());
Some(new_beginning)
} else {
None
}
}
fn resolve(
namespace: &[Tok<String>],
alias_map: &AliasMap,
injected_as: &impl InjectedAsFn,
) -> Option<VName> {
injected_as(namespace).or_else(|| {
let next_v = resolve_rec(namespace, alias_map)?;
Some(injected_as(&next_v).unwrap_or(next_v))
})
}
fn process_expr(
expr: &Expr<VName>,
alias_map: &AliasMap,
injected_as: &impl InjectedAsFn,
) -> Expr<VName> {
expr
.map_names(&|n| resolve(n, alias_map, injected_as))
.unwrap_or_else(|| expr.clone())
}
/// Replace all aliases with the name they're originally defined as
fn apply_aliases_rec(
path: Substack<Tok<String>>,
module: &mut ProjectMod<VName>,
alias_map: &AliasMap,
injected_as: &impl InjectedAsFn,
updated: &impl UpdatedFn,
) {
for (name, entry) in module.entries.iter_mut() {
match &mut entry.member {
ModMember::Sub(sub) => {
let subpath = path.push(name.clone());
apply_aliases_rec(subpath, sub, alias_map, injected_as, updated)
},
ModMember::Item(it) => match &mut it.kind {
ItemKind::None => (),
ItemKind::Const(expr) =>
*expr = process_expr(expr, alias_map, injected_as),
ItemKind::Alias(name) =>
if let Some(alt) = alias_map.resolve(&name) {
*name = alt.clone()
},
},
_ => (),
}
}
for Rule { pattern, prio, template } in module.extra.rules.iter_mut() {
for expr in pattern.iter_mut().chain(template.iter_mut()) {
*expr = process_expr(expr, alias_map, injected_as)
}
}
}
pub fn apply_aliases(
module: &mut ProjectMod<VName>,
alias_map: &AliasMap,
injected_as: &impl InjectedAsFn,
updated: &impl UpdatedFn,
) {
apply_aliases_rec(Substack::Bottom, module, alias_map, injected_as, updated)
}

View File

@@ -1,47 +0,0 @@
use super::alias_map::AliasMap;
use super::decls::UpdatedFn;
use crate::error::ProjectResult;
use crate::interner::Tok;
use crate::representations::project::{ProjectMod, ProjectTree};
use crate::representations::tree::ModMember;
use crate::representations::VName;
use crate::utils::{pushed, unwrap_or};
/// Populate target and alias maps from the module tree recursively
fn collect_aliases_rec(
path: Vec<Tok<String>>,
module: &ProjectMod<VName>,
project: &ProjectTree<VName>,
alias_map: &mut AliasMap,
updated: &impl UpdatedFn,
) -> ProjectResult<()> {
// Assume injected module has been alias-resolved
if !updated(&path) {
return Ok(());
};
for (name, target_sym_v) in module.extra.imports_from.iter() {
let sym_path_v = pushed(&path, name.clone());
alias_map.link(sym_path_v, target_sym_v.clone());
}
for (name, entry) in module.entries.iter() {
let submodule = unwrap_or!(&entry.member => ModMember::Sub; continue);
collect_aliases_rec(
pushed(&path, name.clone()),
submodule,
project,
alias_map,
updated,
)?
}
Ok(())
}
/// Populate target and alias maps from the module tree
pub fn collect_aliases(
module: &ProjectMod<VName>,
project: &ProjectTree<VName>,
alias_map: &mut AliasMap,
updated: &impl UpdatedFn,
) -> ProjectResult<()> {
collect_aliases_rec(Vec::new(), module, project, alias_map, updated)
}

View File

@@ -1,8 +0,0 @@
use trait_set::trait_set;
use crate::{interner::Tok, VName};
trait_set! {
pub trait InjectedAsFn = Fn(&[Tok<String>]) -> Option<VName>;
pub trait UpdatedFn = Fn(&[Tok<String>]) -> bool;
}

View File

@@ -1,8 +0,0 @@
mod alias_map;
mod apply_aliases;
mod collect_aliases;
mod decls;
mod resolve_imports;
mod alias_cache;
pub use resolve_imports::resolve_imports;

View File

@@ -1,22 +0,0 @@
use super::alias_cache::AliasCache;
use super::alias_map::AliasMap;
use super::apply_aliases::apply_aliases;
use super::collect_aliases::collect_aliases;
use super::decls::{InjectedAsFn, UpdatedFn};
use crate::error::ProjectResult;
use crate::representations::project::ProjectTree;
use crate::representations::VName;
/// Follow import chains to locate the original name of all tokens, then
/// replace these aliases with the original names throughout the tree
pub fn resolve_imports(
mut project: ProjectTree<VName>,
injected_as: &impl InjectedAsFn,
updated: &impl UpdatedFn,
) -> ProjectResult<ProjectTree<VName>> {
let mut cache = AliasCache::new(&project);
// let mut map = AliasMap::new();
// collect_aliases(&project.0, &project, &mut map, updated)?;
// apply_aliases(&mut project.0, &map, injected_as, updated);
Ok(project)
}

View File

@@ -1,7 +1,6 @@
//! Loading Orchid modules from source
pub mod file_loader;
mod import_abs_path;
// mod import_resolution;
mod dealias;
mod parse_layer;
mod project_tree;

View File

@@ -16,6 +16,7 @@ use crate::utils::get_or::get_or_default;
use crate::utils::pure_push::pushed_ref;
use crate::{Tok, VName};
#[must_use = "A submodule may not be integrated into the tree"]
pub struct TreeReport {
pub entries: HashMap<Tok<String>, ProjectEntry<VName>>,
pub rules: Vec<Rule<VName>>,