forked from Orchid/orchid
temp commit
This commit is contained in:
@@ -3,19 +3,18 @@ use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use async_stream::stream;
|
||||
use derive_destructure::destructure;
|
||||
use futures::StreamExt;
|
||||
use futures::FutureExt;
|
||||
use futures::future::join_all;
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use memo_map::MemoMap;
|
||||
use orchid_base::char_filter::char_filter_match;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::{OrcErrv, OrcRes};
|
||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::location::SrcRange;
|
||||
use orchid_base::name::{NameLike, Sym, VName};
|
||||
use orchid_base::parse::Comment;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use orchid_base::tree::ttv_from_api;
|
||||
@@ -24,19 +23,25 @@ use substack::{Stackframe, Substack};
|
||||
|
||||
use crate::api;
|
||||
use crate::ctx::Ctx;
|
||||
use crate::expr::{Expr, ExprParseCtx};
|
||||
use crate::dealias::{absolute_path, walk};
|
||||
use crate::expr::{ExprParseCtx, ExprWillPanic};
|
||||
use crate::expr_store::ExprStore;
|
||||
use crate::extension::{Extension, WeakExtension};
|
||||
use crate::parsed::{ItemKind, ParsTokTree, ParsedModule, Root};
|
||||
use crate::tree::Module;
|
||||
use crate::fs::{DeclFS, DeclMod};
|
||||
use crate::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule};
|
||||
use crate::tree::Root;
|
||||
|
||||
#[derive(destructure)]
|
||||
struct SystemInstData {
|
||||
deps: Vec<System>,
|
||||
ctx: Ctx,
|
||||
ext: Extension,
|
||||
decl_id: api::SysDeclId,
|
||||
lex_filter: api::CharFilter,
|
||||
id: api::SysId,
|
||||
line_types: Vec<Tok<String>>,
|
||||
vfs: std::collections::HashMap<api::TStr, api::EagerVfs>,
|
||||
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
||||
}
|
||||
impl Drop for SystemInstData {
|
||||
fn drop(&mut self) { self.ext.system_drop(self.id); }
|
||||
@@ -55,15 +60,29 @@ impl fmt::Debug for SystemInstData {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct System(Rc<SystemInstData>);
|
||||
impl System {
|
||||
#[must_use]
|
||||
pub fn id(&self) -> api::SysId { self.0.id }
|
||||
#[must_use]
|
||||
pub fn ext(&self) -> &Extension { &self.0.ext }
|
||||
#[must_use]
|
||||
pub fn ctx(&self) -> &Ctx { &self.0.ctx }
|
||||
#[must_use]
|
||||
pub fn i(&self) -> &Interner { &self.0.ctx.i }
|
||||
#[must_use]
|
||||
pub fn deps(&self) -> &[System] { &self.0.deps }
|
||||
#[must_use]
|
||||
pub(crate) fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { self.0.ext.reqnot() }
|
||||
#[must_use]
|
||||
pub async fn get_tree(&self, id: api::TreeId) -> api::MemberKind {
|
||||
self.reqnot().request(api::GetMember(self.0.id, id)).await
|
||||
}
|
||||
#[must_use]
|
||||
pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() }
|
||||
#[must_use]
|
||||
pub async fn vfs(&self) -> DeclFS {
|
||||
DeclFS::Eager(DeclMod::from_api(&self.0.vfs, self.clone()).await)
|
||||
}
|
||||
#[must_use]
|
||||
pub fn can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) }
|
||||
/// Have this system lex a part of the source. It is assumed that
|
||||
/// [Self::can_lex] was called and returned true.
|
||||
@@ -76,24 +95,26 @@ impl System {
|
||||
) -> api::OrcResult<Option<api::LexedExpr>> {
|
||||
self.0.ext.lex_req(source, src, pos, self.id(), r).await
|
||||
}
|
||||
#[must_use]
|
||||
pub fn can_parse(&self, ltyp: Tok<String>) -> bool { self.0.line_types.contains(<yp) }
|
||||
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
||||
pub async fn parse(
|
||||
&self,
|
||||
module: Sym,
|
||||
path: Substack<'_, Tok<String>>,
|
||||
line: Vec<ParsTokTree>,
|
||||
exported: bool,
|
||||
comments: Vec<Comment>,
|
||||
) -> OrcRes<Vec<ParsTokTree>> {
|
||||
callback: &mut impl AsyncFnMut(Substack<'_, Tok<String>>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
||||
) -> OrcRes<Vec<Item>> {
|
||||
let src_path = line.first().expect("cannot be empty").sr.path();
|
||||
let line = join_all(line.into_iter().map(|t| async {
|
||||
let mut expr_store = self.0.ext.exprs().clone();
|
||||
t.into_api(&mut expr_store, &mut ()).await
|
||||
t.into_api(&mut expr_store, &mut ExprWillPanic).await
|
||||
}))
|
||||
.await;
|
||||
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
||||
let req = api::ParseLine {
|
||||
module: module.to_api(),
|
||||
module: self.i().i(&path.unreverse()).await.to_api(),
|
||||
src: src_path.to_api(),
|
||||
exported,
|
||||
sys: self.id(),
|
||||
@@ -101,14 +122,69 @@ impl System {
|
||||
line,
|
||||
};
|
||||
match self.reqnot().request(req).await {
|
||||
Ok(parsed) => {
|
||||
let mut pctx = ExprParseCtx { ctx: self.ctx().clone(), exprs: self.ext().exprs().clone() };
|
||||
Ok(parsed_v) => {
|
||||
let mut ext_exprs = self.ext().exprs().clone();
|
||||
Ok(ttv_from_api(parsed, &mut ext_exprs, &mut pctx, &src_path, self.i()).await)
|
||||
struct ConvCtx<'a> {
|
||||
sys: &'a System,
|
||||
src_path: &'a Sym,
|
||||
i: &'a Interner,
|
||||
ext_exprs: &'a mut ExprStore,
|
||||
pctx: &'a mut ExprParseCtx<'a>,
|
||||
}
|
||||
async fn conv(
|
||||
parsed_v: Vec<api::ParsedLine>,
|
||||
module: Substack<'_, Tok<String>>,
|
||||
callback: &'_ mut impl AsyncFnMut(
|
||||
Substack<'_, Tok<String>>,
|
||||
Vec<ParsTokTree>,
|
||||
) -> OrcRes<Vec<Item>>,
|
||||
ctx: &mut ConvCtx<'_>,
|
||||
) -> OrcRes<Vec<Item>> {
|
||||
let mut items = Vec::new();
|
||||
for parsed in parsed_v {
|
||||
let (name, exported, kind) = match parsed.kind {
|
||||
api::ParsedLineKind::Member(api::ParsedMember { name, exported, kind }) =>
|
||||
(name, exported, kind),
|
||||
api::ParsedLineKind::Recursive(rec) => {
|
||||
let tokens = ttv_from_api(rec, ctx.ext_exprs, ctx.pctx, ctx.src_path, ctx.i).await;
|
||||
items.extend(callback(module.clone(), tokens).await?);
|
||||
continue;
|
||||
},
|
||||
};
|
||||
let name = ctx.i.ex(name).await;
|
||||
let mkind = match kind {
|
||||
api::ParsedMemberKind::Module(items) => {
|
||||
let items =
|
||||
conv(items, module.push(name.clone()), callback, ctx).boxed_local().await?;
|
||||
ParsedMemberKind::Mod(ParsedModule::new(items))
|
||||
},
|
||||
api::ParsedMemberKind::Constant(cid) =>
|
||||
ParsedMemberKind::DeferredConst(cid, ctx.sys.clone()),
|
||||
};
|
||||
items.push(Item {
|
||||
comments: join_all(
|
||||
parsed.comments.iter().map(|c| Comment::from_api(c, ctx.src_path.clone(), ctx.i)),
|
||||
)
|
||||
.await,
|
||||
sr: SrcRange::from_api(&parsed.source_range, ctx.i).await,
|
||||
kind: ItemKind::Member(ParsedMember { name, exported, kind: mkind }),
|
||||
})
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
conv(parsed_v, path, callback, &mut ConvCtx {
|
||||
i: self.i(),
|
||||
ext_exprs: &mut ext_exprs,
|
||||
pctx: &mut ExprParseCtx { ctx: self.ctx(), exprs: self.ext().exprs() },
|
||||
src_path: &src_path,
|
||||
sys: self,
|
||||
})
|
||||
.await
|
||||
},
|
||||
Err(e) => Err(OrcErrv::from_api(&e, &self.ctx().i).await),
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
|
||||
self.reqnot().request(api::SysFwded(self.id(), req)).await
|
||||
}
|
||||
@@ -118,7 +194,24 @@ impl System {
|
||||
this.ctx.owned_atoms.write().await.remove(&drop);
|
||||
}))
|
||||
}
|
||||
#[must_use]
|
||||
pub fn downgrade(&self) -> WeakSystem { WeakSystem(Rc::downgrade(&self.0)) }
|
||||
/// Implementation of [api::ResolveNames]
|
||||
pub(crate) async fn name_resolver(
|
||||
&self,
|
||||
orig: api::ParsedConstId,
|
||||
) -> impl AsyncFnMut(&[Tok<String>]) -> Option<VName> + use<> {
|
||||
let root = self.0.ctx.root.read().await.upgrade().expect("find_names when root not in context");
|
||||
let orig = self.0.const_paths.get(&orig).expect("origin for find_names invalid").clone();
|
||||
let ctx = self.0.ctx.clone();
|
||||
async move |rel| {
|
||||
let cwd = orig.split_last().1;
|
||||
let abs = absolute_path(cwd, rel, &ctx.i).await.ok()?;
|
||||
let root_data = &mut *root.0.write().await;
|
||||
let walk_ctx = &mut (ctx.clone(), &mut root_data.consts);
|
||||
walk(&root_data.root, false, abs.iter(), walk_ctx).await.is_ok().then_some(abs)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Format for System {
|
||||
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
@@ -130,6 +223,7 @@ impl Format for System {
|
||||
|
||||
pub struct WeakSystem(Weak<SystemInstData>);
|
||||
impl WeakSystem {
|
||||
#[must_use]
|
||||
pub fn upgrade(&self) -> Option<System> { self.0.upgrade().map(System) }
|
||||
}
|
||||
|
||||
@@ -138,56 +232,42 @@ pub struct SystemCtor {
|
||||
pub(crate) ext: WeakExtension,
|
||||
}
|
||||
impl SystemCtor {
|
||||
#[must_use]
|
||||
pub fn name(&self) -> &str { &self.decl.name }
|
||||
#[must_use]
|
||||
pub fn priority(&self) -> NotNan<f64> { self.decl.priority }
|
||||
#[must_use]
|
||||
pub fn depends(&self) -> impl ExactSizeIterator<Item = &str> {
|
||||
self.decl.depends.iter().map(|s| &**s)
|
||||
}
|
||||
#[must_use]
|
||||
pub fn id(&self) -> api::SysDeclId { self.decl.id }
|
||||
pub async fn run<'a>(
|
||||
&self,
|
||||
depends: impl IntoIterator<Item = &'a System>,
|
||||
consts: &mut HashMap<Sym, Expr>,
|
||||
) -> (Module, System) {
|
||||
let depends = depends.into_iter().map(|si| si.id()).collect_vec();
|
||||
#[must_use]
|
||||
pub async fn run(&self, deps: Vec<System>) -> (Root, System) {
|
||||
let depends = deps.iter().map(|si| si.id()).collect_vec();
|
||||
debug_assert_eq!(depends.len(), self.decl.depends.len(), "Wrong number of deps provided");
|
||||
let ext = self.ext.upgrade().expect("SystemCtor should be freed before Extension");
|
||||
let id = ext.ctx().next_sys_id();
|
||||
let sys_inst = ext.reqnot().request(api::NewSystem { depends, id, system: self.decl.id }).await;
|
||||
let data = System(Rc::new(SystemInstData {
|
||||
deps,
|
||||
decl_id: self.decl.id,
|
||||
ext: ext.clone(),
|
||||
ctx: ext.ctx().clone(),
|
||||
lex_filter: sys_inst.lex_filter,
|
||||
vfs: sys_inst.vfs,
|
||||
line_types: join_all(sys_inst.line_types.iter().map(|m| Tok::from_api(*m, &ext.ctx().i)))
|
||||
.await,
|
||||
id,
|
||||
const_paths: MemoMap::new(),
|
||||
}));
|
||||
let const_root =
|
||||
Module::from_api((sys_inst.const_root.into_iter()).map(|(k, v)| api::Member {
|
||||
name: k,
|
||||
kind: v,
|
||||
comments: vec![],
|
||||
exported: true,
|
||||
}))
|
||||
.await;
|
||||
let const_root = clone!(data, ext; stream! {
|
||||
for (k, v) in sys_inst.const_root {
|
||||
yield Member::from_api(
|
||||
,
|
||||
&mut ParsedFromApiCx {
|
||||
consts,
|
||||
path: ext.ctx().i.i(&[]).await,
|
||||
sys: &data,
|
||||
}
|
||||
).await;
|
||||
}
|
||||
})
|
||||
.map(|mem| ItemKind::Member(mem).at(Pos::None))
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
let api_module_root = api::Module {
|
||||
members: (sys_inst.const_root.into_iter())
|
||||
.map(|(k, v)| api::Member { name: k, kind: v, comments: vec![], exported: true })
|
||||
.collect_vec(),
|
||||
};
|
||||
let root = Root::from_api(api_module_root, &data).await;
|
||||
ext.ctx().systems.write().await.insert(id, data.downgrade());
|
||||
let root = ParsedModule::new(const_root);
|
||||
(root, data)
|
||||
}
|
||||
}
|
||||
@@ -219,7 +299,6 @@ pub async fn init_systems(
|
||||
fn walk_deps<'a>(
|
||||
graph: &mut HashMap<&str, &'a SystemCtor>,
|
||||
list: &mut Vec<&'a SystemCtor>,
|
||||
consts: &mut HashMap<Sym, Expr>,
|
||||
chain: Stackframe<&str>,
|
||||
) -> Result<(), SysResolvErr> {
|
||||
if let Some(ctor) = graph.remove(chain.item) {
|
||||
@@ -231,22 +310,21 @@ pub async fn init_systems(
|
||||
circle.extend(Substack::Frame(chain).iter().map(|s| s.to_string()));
|
||||
return Err(SysResolvErr::Loop(circle));
|
||||
}
|
||||
walk_deps(graph, list, consts, Substack::Frame(chain).new_frame(dep))?
|
||||
walk_deps(graph, list, Substack::Frame(chain).new_frame(dep))?
|
||||
}
|
||||
list.push(ctor);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
let mut consts = HashMap::new();
|
||||
for tgt in tgts {
|
||||
walk_deps(&mut to_load, &mut to_load_ordered, &mut consts, Substack::Bottom.new_frame(tgt))?;
|
||||
walk_deps(&mut to_load, &mut to_load_ordered, Substack::Bottom.new_frame(tgt))?;
|
||||
}
|
||||
let mut systems = HashMap::<&str, System>::new();
|
||||
let mut root_mod = ParsedModule::default();
|
||||
let mut root = Root::new(exts.first().unwrap().ctx().clone());
|
||||
for ctor in to_load_ordered.iter() {
|
||||
let (sys_root, sys) = ctor.run(ctor.depends().map(|n| &systems[n]), &mut consts).await;
|
||||
let (sys_root, sys) = ctor.run(ctor.depends().map(|n| systems[n].clone()).collect()).await;
|
||||
systems.insert(ctor.name(), sys);
|
||||
root_mod.merge(sys_root);
|
||||
root = root.merge(&sys_root).await.expect("Conflicting roots");
|
||||
}
|
||||
Ok((Root::new(root_mod, consts), systems.into_values().collect_vec()))
|
||||
Ok((root, systems.into_values().collect_vec()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user