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:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// mod alias_cache;
|
||||
mod resolve_aliases;
|
||||
mod walk_with_links;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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>>,
|
||||
|
||||
Reference in New Issue
Block a user