forked from Orchid/orchid
Rule execution now runs, no tests tho
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use mappable_rc::Mrc;
|
||||
|
||||
use crate::expression::Rule;
|
||||
use crate::parse::{self, FileEntry};
|
||||
use crate::utils::Cache;
|
||||
use crate::utils::{Cache, mrc_derive, to_mrc_slice};
|
||||
|
||||
use super::name_resolver::NameResolver;
|
||||
use super::module_error::ModuleError;
|
||||
@@ -17,27 +20,29 @@ type ParseResult<T, ELoad> = Result<T, ModuleError<ELoad>>;
|
||||
pub struct Module {
|
||||
pub rules: Vec<Rule>,
|
||||
pub exports: Vec<String>,
|
||||
pub references: Vec<Vec<String>>
|
||||
pub references: Vec<Mrc<[String]>>
|
||||
}
|
||||
|
||||
pub type RuleCollectionResult<ELoad> = Result<Vec<super::Rule>, ModuleError<ELoad>>;
|
||||
|
||||
pub fn rule_collector<F: 'static, ELoad>(
|
||||
mut load_mod: F,
|
||||
prelude: Vec<String>
|
||||
// ) -> impl FnMut(Vec<String>) -> Result<&'a Vec<super::Rule>, ParseError<ELoad>> + 'a
|
||||
) -> Cache<'static, Vec<String>, Result<Vec<super::Rule>, ModuleError<ELoad>>>
|
||||
) -> Cache<'static, Mrc<[String]>, RuleCollectionResult<ELoad>>
|
||||
where
|
||||
F: FnMut(Vec<String>) -> Result<Loaded, ELoad>,
|
||||
F: FnMut(Mrc<[String]>) -> Result<Loaded, ELoad>,
|
||||
ELoad: Clone + Debug
|
||||
{
|
||||
let load_mod_rc = RefCell::new(load_mod);
|
||||
// Map paths to a namespace with name list (folder) or module with source text (file)
|
||||
let loaded = Rc::new(Cache::new(move |path: Vec<String>, _|
|
||||
let loaded = Rc::new(Cache::new(move |path: Mrc<[String]>, _|
|
||||
-> ParseResult<Loaded, ELoad> {
|
||||
load_mod(path).map_err(ModuleError::Load)
|
||||
(load_mod_rc.borrow_mut())(path).map_err(ModuleError::Load)
|
||||
}));
|
||||
// Map names to the longest prefix that points to a valid module
|
||||
let modname = Rc::new(Cache::new({
|
||||
let loaded = Rc::clone(&loaded);
|
||||
move |symbol: Vec<String>, _| -> Result<Vec<String>, Vec<ModuleError<ELoad>>> {
|
||||
move |symbol: Mrc<[String]>, _| -> Result<Mrc<[String]>, Vec<ModuleError<ELoad>>> {
|
||||
let mut errv: Vec<ModuleError<ELoad>> = Vec::new();
|
||||
let reg_err = |e, errv: &mut Vec<ModuleError<ELoad>>| {
|
||||
errv.push(e);
|
||||
@@ -45,11 +50,10 @@ where
|
||||
else { Ok(()) }
|
||||
};
|
||||
loop {
|
||||
let (path, _) = symbol.split_at(symbol.len() - errv.len());
|
||||
let pathv = path.to_vec();
|
||||
match loaded.try_find(&pathv) {
|
||||
let path = mrc_derive(&symbol, |s| &s[..s.len() - errv.len()]);
|
||||
match loaded.try_find(&path) {
|
||||
Ok(imports) => match imports.as_ref() {
|
||||
Loaded::Module(_) => break Ok(pathv.clone()),
|
||||
Loaded::Module(_) => break Ok(path),
|
||||
_ => reg_err(ModuleError::None, &mut errv)?
|
||||
},
|
||||
Err(err) => reg_err(err, &mut errv)?
|
||||
@@ -61,7 +65,7 @@ where
|
||||
let preparsed = Rc::new(Cache::new({
|
||||
let loaded = Rc::clone(&loaded);
|
||||
let prelude2 = prelude.clone();
|
||||
move |path: Vec<String>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
|
||||
let loaded = loaded.try_find(&path)?;
|
||||
if let Loaded::Module(source) = loaded.as_ref() {
|
||||
Ok(parse::parse(&prelude2, source.as_str())?)
|
||||
@@ -72,7 +76,7 @@ where
|
||||
let exports = Rc::new(Cache::new({
|
||||
let loaded = Rc::clone(&loaded);
|
||||
let preparsed = Rc::clone(&preparsed);
|
||||
move |path: Vec<String>, _| -> ParseResult<Vec<String>, ELoad> {
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<Vec<String>, ELoad> {
|
||||
let loaded = loaded.try_find(&path)?;
|
||||
if let Loaded::Namespace(names) = loaded.as_ref() {
|
||||
return Ok(names.clone());
|
||||
@@ -88,19 +92,19 @@ where
|
||||
let imports = Rc::new(Cache::new({
|
||||
let preparsed = Rc::clone(&preparsed);
|
||||
let exports = Rc::clone(&exports);
|
||||
move |path: Vec<String>, _| -> ParseResult<HashMap<String, Vec<String>>, ELoad> {
|
||||
let entv = preparsed.try_find(&path)?.clone();
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<HashMap<String, Mrc<[String]>>, ELoad> {
|
||||
let entv = preparsed.try_find(&path)?;
|
||||
let import_entries = parse::imports(entv.iter());
|
||||
let mut imported_symbols: HashMap<String, Vec<String>> = HashMap::new();
|
||||
let mut imported_symbols: HashMap<String, Mrc<[String]>> = HashMap::new();
|
||||
for imp in import_entries {
|
||||
let export = exports.try_find(&imp.path)?;
|
||||
if let Some(ref name) = imp.name {
|
||||
if export.contains(&name) {
|
||||
imported_symbols.insert(name.clone(), imp.path.clone());
|
||||
if export.contains(name) {
|
||||
imported_symbols.insert(name.clone(), Mrc::clone(&imp.path));
|
||||
}
|
||||
} else {
|
||||
for exp in export.as_ref() {
|
||||
imported_symbols.insert(exp.clone(), imp.path.clone());
|
||||
imported_symbols.insert(exp.clone(), Mrc::clone(&imp.path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +116,7 @@ where
|
||||
let preparsed = Rc::clone(&preparsed);
|
||||
let imports = Rc::clone(&imports);
|
||||
let loaded = Rc::clone(&loaded);
|
||||
move |path: Vec<String>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
|
||||
let imported_ops: Vec<String> =
|
||||
imports.try_find(&path)?
|
||||
.keys()
|
||||
@@ -127,45 +131,44 @@ where
|
||||
} else { Err(ModuleError::None) }
|
||||
}
|
||||
}));
|
||||
let mut name_resolver = NameResolver::new({
|
||||
let mut name_resolver_rc = RefCell::new(NameResolver::new({
|
||||
let modname = Rc::clone(&modname);
|
||||
move |path| {
|
||||
Some(modname.try_find(path).ok()?.as_ref().clone())
|
||||
Some(modname.try_find(&path).ok()?.as_ref().clone())
|
||||
}
|
||||
}, {
|
||||
let imports = Rc::clone(&imports);
|
||||
move |path| {
|
||||
imports.try_find(path).map(|f| f.as_ref().clone())
|
||||
imports.try_find(&path).map(|f| f.as_ref().clone())
|
||||
}
|
||||
});
|
||||
}));
|
||||
// Turn parsed files into a bag of rules and a list of toplevel export names
|
||||
let resolved = Rc::new(Cache::new({
|
||||
let parsed = Rc::clone(&parsed);
|
||||
let exports = Rc::clone(&exports);
|
||||
let imports = Rc::clone(&imports);
|
||||
let modname = Rc::clone(&modname);
|
||||
move |path: Vec<String>, _| -> ParseResult<Module, ELoad> {
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<Module, ELoad> {
|
||||
let mut name_resolver = name_resolver_rc.borrow_mut();
|
||||
let module = Module {
|
||||
rules: parsed.try_find(&path)?
|
||||
.iter()
|
||||
.filter_map(|ent| {
|
||||
if let FileEntry::Rule(Rule{source, prio, target}, _) = ent {
|
||||
Some(Rule {
|
||||
source: source.iter().map(|ex| prefix_expr(ex, &path)).collect(),
|
||||
target: target.iter().map(|ex| prefix_expr(ex, &path)).collect(),
|
||||
source: source.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
|
||||
target: target.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
|
||||
prio: *prio,
|
||||
})
|
||||
} else { None }
|
||||
})
|
||||
.map(|rule| Ok(super::Rule {
|
||||
source: rule.source.iter()
|
||||
source: to_mrc_slice(rule.source.iter()
|
||||
.map(|ex| name_resolver.process_expression(ex))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
target: rule.target.iter()
|
||||
.collect::<Result<Vec<_>, _>>()?),
|
||||
target: to_mrc_slice(rule.target.iter()
|
||||
.map(|ex| name_resolver.process_expression(ex))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
// source: name_resolver.process_expression(&rule.source)?,
|
||||
// target: name_resolver.process_expression(&rule.target)?,
|
||||
.collect::<Result<Vec<_>, _>>()?),
|
||||
..rule
|
||||
}))
|
||||
.collect::<ParseResult<Vec<super::Rule>, ELoad>>()?,
|
||||
@@ -173,19 +176,20 @@ where
|
||||
references: imports.try_find(&path)?
|
||||
.values()
|
||||
.filter_map(|imps| {
|
||||
modname.try_find(&imps).ok().map(|r| r.as_ref().clone())
|
||||
modname.try_find(imps).ok().map(|r| r.as_ref().clone())
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
Ok(module)
|
||||
}
|
||||
}));
|
||||
let all_rules = Cache::new({
|
||||
Cache::new({
|
||||
let resolved = Rc::clone(&resolved);
|
||||
move |path: Vec<String>, _| -> ParseResult<Vec<super::Rule>, ELoad> {
|
||||
let mut processed: HashSet<Vec<String>> = HashSet::new();
|
||||
move |path: Mrc<[String]>, _| -> ParseResult<Vec<super::Rule>, ELoad> {
|
||||
// Breadth-first search
|
||||
let mut processed: HashSet<Mrc<[String]>> = HashSet::new();
|
||||
let mut rules: Vec<super::Rule> = Vec::new();
|
||||
let mut pending: VecDeque<Vec<String>> = VecDeque::new();
|
||||
let mut pending: VecDeque<Mrc<[String]>> = VecDeque::new();
|
||||
pending.push_back(path);
|
||||
while let Some(el) = pending.pop_front() {
|
||||
let resolved = resolved.try_find(&el)?;
|
||||
@@ -201,6 +205,5 @@ where
|
||||
};
|
||||
Ok(rules)
|
||||
}
|
||||
});
|
||||
return all_rules;
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user